linux0.12内核剖析 - 引导启动(一)

 

从PC上电到进入系统初始化main函数的过程中,内核做了哪些事情?

  • 相关文件:boot/*

其中,bootsect.Ssetup.S实模式下运行的16位代码程序,采用近似于Intel的汇编语言语法,并且需要使用8086汇编编译器as86和链接器ld86。 head.s则使用一种AT&T的汇编语法格式,并且运行在保护模式下,需要用GNU的as(gas)汇编器进行编译。

内核映像在磁盘中的格式

linux_in_disk

CPU执行权的移交

CPU执行权的移交如下图所示:

cpu_exec_turn

当PC的电源打开后,80x86结构的CPU将自动进入实模式,并从地址0xFFFF0开始自动执行程序代码,这个地址通常是ROM BIOS中的地址。PC机的BIOS将执行系统的某些硬件检测和诊断功能,并在物理地址0处开始设置和初始化中断向量。此后,它将可启动设备的第一个扇区(磁盘引导扇区,512字节,也就是bootsect)读入内存绝对地址0x7C00处,并跳转到这个地方开始引导启动机器运行了。

内核在内存中的移动情况

  1. BIOS将引导设备的第一个扇区(bootsect)读入到内存绝对地址0x7C00处;
  2. bootsect执行时将自己移动到内存绝对地址0x90000处;
  3. bootsect之后会将紧接着的4个扇区代码(setup)读入到内存0x90200处;再将之后的system模块读入到内存0x10000处(当时system不会超过0x80000字节,不会覆盖0x90000处开始的bootsectsetup);
  4. bootsect最后跳转到setup中执行;
  5. setup又会把system移动到物理内存起始处0x00000

mem_kernel_turn

bootsect、setup、head各自干了啥

bootsect

bootsect把整个内核映像加载到了内存是它最大的贡献了(PS:只有它保存在0x901FC处的ROOT_DEV和0x901FA处的SWAP_DEV还被记得)。

  1. 将自己从0x7c00移动到0x90000处;
  2. 为了更快地加载内核,修改了软驱参数表;
  3. 加载setup模块到0x90000处;
  4. 加载system模块到0x10000处
  5. 干完活,跳转去setup

setup

setup主要做了三件事:获取系统的一些参数,移动system模块,开启保护模式。

  1. 获取系统初始化所需要的参数;

    setup_some_param

  2. 把整个system模块移动到0x00000位置;
  3. 因为要开启保护模式,所以设置了一个临时的gdt表和ldt表;
  4. 将控制寄存器CR0位0置1,从而开启保护模式;
  5. 跳转到head中执行。

setup结束后,内存中的程序示意图如下所示

after_setup

head很大一部分代码都是一次性的;用完就被页目录表和页表覆盖掉了。head主要为之后操作系统的运行留下了几件重要的东西:1个页目录表和4个内核专属的页表,中断描述符表IDT和全局段描述符表GDT,以及一个哑中断ignore_int

  1. 将系统堆栈放置在stack_start指向的数据区(之后,该栈就被用作任务0和任务1共同使用的用户栈);
  2. 重新加载了新的中断描述符表IDT和全局段描述符表GDT;
  3. 检查数学协处理器芯片是否存在;
  4. 初始化页目录表和4个内核专属的页表;
    1. 页目录表(4KB)从物理地址0处开始,紧接着4个内核专属的页表(4*4KB)
  5. 通过ret跳转到init/main.c中的main运行。