这篇blog主要是承接上文,看看setup模块都做了哪些事情,同时涉及到一些System模块的内容。
Setup
这个模块主要的工作都是初始化相关的。
获取硬件参数
OS要管理硬件,如内存、显示器等。以内存为例,要管理内存,就需要知道内存到底有多少。在setup模块中,OS会获取扩展内存大小。
8086有20根地址线。所以1M以外的内存都叫扩展内存。
移动System模块
将System模块,也就是操作系统核心内容,移动到0地址处。
这也可以理解为什么cpu设计者不让bios结束时把引导扇区读到0地址,因为那样会影响实际的OS。像bootsect、setup都是用完就用处不大的模块,不该让他们在0地址处。
进入保护模式
上面提到,实模式内存不够用,要进入保护模式,进入保护模式的方法是修改cr0寄存器。
保护模式的寻址规则与实模式不一样。
如图,GDT表就是一个数组,我们的cs相当于数组下标,ip是段内偏移。
(IDT是中断描述符表,道理完全类似,所以放在一起说了)
而GDT表一开始是不存在的,谁来初始化GDT表呢?答案是setup模块。
setup模块会初始化GDT表,在里面添入一些必要的表项,比如0地址(方便一会跳转)。
设置结束后,会进入到system模块。
System
这个模块开始就是核心的os了。在这里有个小问题:System模块由很多个文件组成,如何确定第一部分代码是什么呢?
答案是借助makefile去进行编译。编译的时候,根据文件之间的依赖关系,会形成一颗依赖树。树的根自然就是文件的第一部分。
System模块的第一部分是head.s
head.s进行初始化
head文件要开启A20地址线,以便进行32位寻址。
同时还要继续做其他初始化工作,比如GDT和IDT。刚才提到,setup模块也会做初始化,但都是用多少初始化多少。head会继续做初始化GDT、IDT,以及其它初始化相关的工作。
初始化结束后会跳转到main.c
C语言函数调用栈

如图,C语言的函数调用时会把返回地址放到栈顶,最后执行ret指令的时候会用到,返回调用处继续执行!
函数调用的后花括号"}"会被翻译成ret指令
main.c

开始做其他初始化工作了。
这个main函数是不会返回的。
总结
setup模块主要是做一些初始化工作,进入保护模式,并跳转到System模块。
System模块的head.s会继续做初始化工作,之后跳到main函数,然后继续初始化。
接下来我们会更加深入去学习各种概念。