Linux内核设计与实现-笔记-第一章
参考书籍:
- 《Linux内核设计艺术》
从开机到main函数执行
主要三步:
- 启动BIOS
- 启动盘加载操作系统到内存
- 为执行32位的main函数做过渡
启动BIOS,准备实模式下的中断向量表和中断服务程序
BIOS启动原理
-
BIOS程序是由
0xFFFF0
来执行的。BIOS程序的第一条指令就设计在这个位置。 -
Intel将所有的80x86系列的CPU,包括最新型号的CPU的硬件都设计为加电即进入16位实模式状态运行。在加电的瞬间将CS的值设置为
0xF000
,IP的值设置为0xFFF0
,这样CS:IP的值就指向了0xFFFF0
这个地址.
-
IP/EIP(Instruction Pointer)
:指令指针寄存器,存在于CPU中,记录将要执行的指令在代码段内的便宜地址,和CS组合即为将要执行的指令的内存地址。实模式为绝对模式,指令指针为16位,即IP;保护模式下为线性地址,指令指针为32位,即EIP。 -
CS(Code Segment Register):代码段寄存器,存在于CPU中,指向CPU当前执行代码在内存中的区域。(定义了存放代码的存储器的起始地址)。
BIOS在内存中加载中断向量表和中断服务程序
-
我们选用的BIOS程序只有8 KB
-
BIOS程序在内存最开始的位置(0x00000) 用1KB的内存空间构建中断向量表
- 在紧挨着它的位置用256字节的内存空间构建BIOS数据区
- 在大约57KB以后的位置加载8KB左右与中断向量表相应的若干中断服务程序
-
中断向量表中有256个中断向量,每个中断向量占4个字节。
加载操作系统内核程序并为保护模式做准备
对于Linux 0.11操作系统而言,计算机将分三批逐次加载操作系统的内核代码。
- 第一批由BIOS中断int 0x19把第一扇区bootsect的内容加载到内存;
- 第二批、第三批在bootsect的指挥下,分别把其后的4个扇区和随后的240个扇区的内容加载至内存。
加载第一部分内核代码——引导程序(bootsect)
-
执行一系列BIOS代码,计算机自检完成
-
CPU收到一个
int 0x19
中断。cpu收到这个中断之后,会立刻在中断表中查询到这个中断向量 -
int 0x19
中断向量在内存中的位置,紧挨着0x00000
-
接下来中断向量把cpu指向
0x0E6F2
这个位置,这个位置是int 0x19
中断服务程序的入口地址。这个中断的作用就是把软盘中第一个扇区中断的程序(512B)加载到内存指定位置。 -
这个中断服务程序是BIOS事先设计好的,代码是固定的,与操作系统没有关系
- 中断向量表:实模式中断机制的重要组成部分,记录所有中断号对应的中断服务程序的内存地址
-
加载中断服务程序,将软驱0号磁头对应的盘面的0磁道1扇区的内容复制到内存的
0x07C00
处,这个扇区的内容就是Linux 0.11的引导程序。也就是bootsect
加载第二部分内核代码——setup
bootsect开始主导:
-
规划内存
对后续操作涉及到的内存位置进行规划设置:
- 将要加载的setup程序扇区数和被加载到的位置
- 启动扇区被BIOS加载的位置,以及将要移动到的新位置
- 内核被加载的位置
- 内核末尾的位置
- 根文件系统设备好
-
复制bootsect
-
bootsect将自己(全部的512B内容)从内存
0x07C00
处复制到内存0x90000
处 -
因为bootsect被复制到了新的地方,并且要在新的地方执行,整体代码位置发生了变化,所以代码中的各个段也会发生变化。需要对CS、DS、ES、SS、SP进行设置
-
执行以下代码
1 2 3 4 5 6 7 8 9 10
… go: mov ax, cs mov ds, ax mov es, ax !put stack at 0x9ff00. mov ss, ax mov sp, # 0xFF00 !arbitrary value >> 512 !load the setup - sectors directly after the bootblock. !Note that 'es' is already set up. …
上述代码的作用是通过ax,用CS的值
0x9000
来把数据段寄存器(DS)、附加段寄存器(ES)、栈基址寄存器(SS)设置成与代码段寄存器(CS)相同的位置,并将栈顶指针SP指向偏移地址为0xFF00
处。图1-8对此做了非常直观的描述。
-
-
将setup程序加载到内存中
加载setup这个程序,要借助BIOS提供的int 0x13中断向量所指向的中断服务程序(也就是磁盘服务程序)来完成。图1-9标注了int 0x13中断向量的位置以及这个中断向量所指向的磁盘服务程序的入口位置。