Linux0.11 内核引导启动流程
计算机加电后,最开始 BIOS 中的程序会先开始执行,BIOS 程序执行结束后,将由操作系统接管。
引导启动过程中会用到的内核文件说明
boot / bootsect.s : 该程序是磁盘引导块程序,编译后会驻留在磁盘的第一个扇区中(即引导扇区中,0 磁道(柱面),0 磁头,第一个扇区)。计算机机加电 ROM BIOS 自检后,将被 BIOS 加载到内存 0x7C00 处执行。
boot / setup.s : 该程序主要用于读取机器的硬件配置参数,并把内核模块 system 移动到适当的内存位置处。
boot / head.s : 该程序会被编译连接在 system 模块的最前部分,主要进行硬件设备的探测设置和内存管理页面的初始化设置工作。
引导启动过程中文件运行顺序图
BIOS 程序执行流程
- 计算机加电,80x86 结构的 CPU 自动进入实模式,并从地址 0xFFFF0 开始自动执行代码。这个地址也就是 ROM-BIOS 中的地址。
- BIOS 执行系统检测,并在物理地址 0 处初始化中断向量。
- BIOS 将可启动设备的第一个扇区(磁盘引导扇区,512字节)读入内存绝对地址 0x7C00 处并跳转到这个地方。
接下来将由操作系统文件接管启动流程。
操作系统程序执行流程
Linux 的最最前面部分是用 8086 汇编语言编写的(bootsect.s)。它由 BIOS 读入到内存绝对地址 0x7C00(31KB)处。
- bootsect.s 执行时会把自己移动到内存绝对地址 0x90000(576KB)处。
- bootsect.s 将启动设备中后 2KB 字节代码(setup.s)读入内存 0x90200 处,将内核代码的其他部分(system 模块)读入从内存地址 0x10000(64KB)开始处。
- setup.s 程序将 system 模块移动到物理内存起始位置处,这样 system 模块中代码的地址也即等于实际的物理地址,便于对内核代码和数据进行操作。
- setup.s 程序识别主机的某些特性以及 VGA 卡的类型。如果需要,它会要求用户为控制台选择显示模式。然后将整个系统从地址 0x10000 移至 0x0000 处,进入保护模式并跳转至系统的余下部分(0x0000)处。
- head.s 程序加载 IDT、GDT 以及 LDT,确认处理器和协处理器,设置分页等。
- head.s 调用 main.c 中的 main() 程序。
启动引导时内核在内存中的位置和移动后的位置情况
Issues
-
bootsect 的代码为什么不把系统模块直接加载到物理地址 0x0000 开始处而要在 setup 程序中再进行移动呢?
这是因为在随后执行的 setup 代码开始部分还需要利用 ROM BIOS中的中断调用来获取机器的一些参数(例如显示卡模式、硬盘参数表等)。当 BIOS 初始化时会在物理内存开始处放置一个大小为 0x400 字节(1KB)的中断向量表,因此需要在使用完 BIOS 的中断调用后才能将这个区域覆盖掉。
-
bootsect 程序将 system 模块读入物理地址 0x10000 开始位置处时会不会覆盖在 0x90000(576KB)开始处的内容?
由于 Linux 0.11 内核 system 模块在当时不会超过 0x80000 字节(即 512KB),所以 bootsect 程序将 system 模块读入物理地址 0x10000 开始位置处时并不会覆盖在 0x90000(576KB)处开始的 bootsect 和 setup 模块。