从开机 main 函数执行

Linux 从开机到加电执行 main 函数之前的过程 #

flowchart LR bootsect[执行 bootsect]--> setup[执行 setup]--> head[执行 head.s]--> main[main 函数]

1.1 启动 BIOS,准备中断向量表和中断服务程序 #

  • 加电时,内存 RAM 是空的
  • BIOS 负责把操作系统内核程序加载到内存中

具体过程:

  • 靠硬件完成,将 CPU 的硬件逻辑设计为加电瞬间 CS:IP 指向 0xFFFF0, 即 BIOS 程序入口地址。
  • BIOS 在内存中建立中断向量表和中断服务程序。利用中断,才能加载内核程序。

1.2 加载内核程序 #

  • 产生 int 0x19 中断,找到并加载启动扇区,从而 bootsecct 程序被拷贝到内存。
    BIOS 负责找到并加载第一扇区,与具体的Linux内核无关,即两头约定 + 定位识别。
  • bootsecct 程序复制自身到另一个地方,并调整CS:IP、DS(数据段寄存器)、ES(附加段寄存器)、SS(栈基址寄存器)+SP(栈顶指针).
    意味着从现在起,操作系统已经不需要完全依赖BIOS,可以按照自己的意志进行内存规划和程序执行。
  • 执行 int 0x13 中断,加载 setup 程序。
    • 需要传参给中断服务程序,包括指定的扇区和加载的内存信息等;
    • 通过几个通用寄存器来实现传参,非函数调用
  • 加载system系统内核程序
  • 开始执行 setup 程序,读取机器系统数据,放在原bootsect程序所在的部分内存区域。

1.3 转变为32位模式,为调用 main 函数做准备 #

  1. system 系统内核程序复制到 0x00000 的位置
    • 这个位置本来放的是 BIOS 建立的中断向量表和BIOS数据区,相当于废掉了BIOS提供的实模式下的中断服务程序;
    • 同时收回寿命结束的内存空间;
    • 让内核代码占据内存物理地址最开始、最天然、最有利的位置。
    • 这一过程是在关中断的状态下进行。
  2. 初始化两个表:
    • GDT(全局描述符表) + GDTR
    • IDT(中断描述符表) + IDTR
  3. 打开A20,实现32位寻址
  4. 对 中断控制芯片8259A 重新编程