西部热线 | 助力西部开发,关注西部民生! |
adtop
adtop01
当前位置: 西部热线 > 新闻

Linux0.11第4回把全部的操作系统代码从硬盘搬到内存

作者:樊华    栏目:新闻    来源:IT之家    发布时间:2022-10-03 16:16

本系列将以一种新奇的阅读心态阅读和欣赏Linux 0.11的所有核心代码,从启动后的代码执行序列中了解操作系统的技术细节和设计思路。

Linux0.11第4回把全部的操作系统代码从硬盘搬到内存

你会跟着我,看着一个操作系统从无到有,最后一步一步实现它复杂而精致的设计看完这个系列,希望你能感叹原来操作系统源代码就是这个蠢东西以下是已发表文章的列表想详细了解这个系列,可以从开篇的话开始

开场白

第一次输入的前两行代码

第二次,给自己挪个位置。

第三遍,做最基本的准备工作。

本系列GitHub地址:点击此处访问

—正文开始—

上一次,上一次,我们说操作系统的一些最基本的准备已经准备好了。

如图,操作系统此时只有几行代码,数据段寄存器ds和代码段寄存器cs都设置为0x9000,方便代码跳转和数据访问此外,堆栈顶部的地址ss:sp被设置为0x9FF00,距离代码的位置0x90000足够远,以确保堆栈在下降时不会轻易撞到代码的位置

简单来说就是设置数据的数据段如何访问,代码的代码段如何访问,栈顶指针如何访问,也就是做一个初步的内存规划从CPU的角度来看,访问内存的地方只有三个

做完基础工作,就该轮到新的了我们继续往下看

load_setup:movdx,# 0x0000drive0,head0movcx,# 0x0002扇区2,track0movbx,# 0x0200地址=512,in0x9000movax,# 0x 0200+4,service2,nrofsectorsint0x13readitjncok _ load _ setupok—continuemovdx,#0x0000movax,# 0x0000resettedisketteint 0x 13 jmp load _ setup ok _ load _ setup:...

这里有两个我们还没见过的int指令。

注意,这个int是汇编指令,不是高级语言中的整数变量Int13表示启动0x13中断在该指令中,dx,cx,bx和ax被指定为该中断程序的参数

中断是什么如果你不懂,就不要管它如果你就是放不下,那就看看我之前的文章:认真谈中断,很详细

简而言之,这个中断发起后,CPU会通过这个中断号找到对应中断处理程序的入口地址,跳转执行,逻辑上相当于执行一个函数0x13中断的处理程序是BIOS预先写好的,是读盘相关函数的函数

进入操作系统内核后,中断处理程序需要我们自己重新编写在后面的章节中,你会不断看到每个模块都注册了自己相关的中断处理程序,所以不用担心此时,为了方便起见,请提前使用BIOS为我们编写程序

可见,即使是操作系统的源代码,有时为了自身的方便也需要调用现成的函数,并不是车轮建设者要完全从零开始构建。

这段代码的注释已经写的很清楚了这么说吧,最后的功能是启动硬盘第二个扇区,将数据加载到内存0x90200,一共加载四个扇区这实际上是如图所示的情况

可以看到,如果复制成功,就会跳转到标签ok_load_setup如果失败了,你会重复执行这段代码,也就是再试一次那么让我们忘记重试逻辑,只看成功后跳转的标签ok_load_setup后的代码

确定_加载_设置:...movax,#0x1000moves,ax,0x10000callread_it段...jmpi0,0x9020

这段代码省略了很多非主逻辑代码,比如输出加载系统...屏幕上的这个字符串是为了防止用户厌倦等待。

其余的主要代码就写在这里,只有几行它的作用是将硬盘第6扇区的240个扇区加载到内存0x10000中,与上一个相同

至此,整个操作系统的所有代码都已经从硬盘移到了内存中。

然后通过一个大家熟悉的段间跳转指令jmpi0,0x9020,跳转到0x90200,也就是硬盘第二个扇区开头的内容。

这里的内容是什么别急,借此机会说一下整个操作系统的编译过程

1.将bootsect.s编译成bootsect,放在硬盘的1扇区。

2.把setup.s编译成setup,放在硬盘的2~5个扇区。

3.将所有剩余的代码编译到系统中,放入硬盘的下240个扇区。

所以整个路径是这样的。

所以我们要跳转到的内存中0x90200处的代码是从硬盘第二扇区开始加载到内存中的在第二个扇区的开头,这是setup.s文件中的第一行代码

这是什么代码这个我们以后再说,但是先打开setup.s文件看一下

start:movax,# 0x9000thisisdoneinbootsectalready,butmovds,axmovah,# 0x03readcursorposxorbh,bhint0x10saveitinknownplace,con_initfetchesmov,dx,itfrom0x90000。

好了,到目前为止,你觉得,我去,前面编译放在硬盘上的位置,和后面代码写的跳转地址耦合的这么强吗如果整件事都是错的呢

对,就是这样你怎么想呢操作系统刚建立的时候,完全是自己安排的,一个字节都不能有偏差就是这么强的耦合,需要小心翼翼,需要大脑时刻保持清醒,规划好自己写的代码在硬盘什么地方编译存储,然后会加载到内存里,不能搞混

但也很有好处,就是在这个阶段,你完全知道如何设计和规划跳转和数据访问的每一步,没有黑箱。

不像我们写高级语言的时候,我们不知道底层帮助我们做了多少工作虽然这样让程序员不用担心底层细节,但是遇到问题或者想知道原理的时候就很烦了

更何况,之所以在顶层可以为所欲为,是因为很多底层的细节根本不需要考虑,非常省心正是因为像今天以及之后的每一章各种底层代码都做了大量精心的准备

好了,本文到此结束。这也标志着我们已经完成了第一个操作系统源文件bootsect.s,开始进入下一个文件设置. s!

我们身后的世界越来越精彩欲知后事如何,且听下回分解

adl03
adr1
adr2