首页 > Kernel, linux > 系统引导

系统引导

本文基于 i386 架构分析.

计算机开机通电后 BIOS 将可启动设备(在 BIOS 里由用户设置, U盘, 硬盘, 光盘等)的第一个 扇区的 512 个字节读入内存绝对地址 0x7C00 处, 然后跳转到这个地方执行, 注意此时 CPU 处于 16 位地址的实模式.

远古时代的 Linux 的启动引导

在 boot 目录下共有三个文件 bootsect.S, setup.S, head.S 来做系统开始初始化的一些工作.

bootsect.S

bootsect.S 被编译链接后驻留在启动设备的第一个扇区的前 512 个字节处. 计算机加点启动后 BIOS 将会把 bootsect 加载到 内存 0x7C00 处并开始执行.

这个文件的主要目的是把 setup 和 system(Linux的真正代码)的代码加载到内存中.

bootsect 的执行流程如下:

  1. 用 movw 指令将 0x7C00 开始的 512 字节移动到 0x90000 处, 并跳转到 0x90000 开始执行.
  2. 从磁盘第二扇区开始读取4个扇区到 0x90200 处.
  3. 从磁盘的第扇区开始加载 0x30000(196KB) 的数据到 0x10000 处.
  4. 做完文件系统设备号的检查后, 通过 jmpi 0, SETUPSEG(0x90200) 跳转到 setup 处开始执行.

setup.S

setup 的主要目的是利用 BIOS 提供的中断服务程序(这些中断向量表存放在 0x000开始的位置, 所以 bootsect 加载 system 时候只能从 0x10000 开始) 从设备上提取内核运行所需的机器系统数据, 其中包括光标位置和显示页面, 硬盘参数表等数据, 把它们存放在 0x90000(覆盖 bootsect)开始的位置. 然后移动 system 到 0x000000, 然后设置各种参数, 为 linux 进入 保护模式做好准备.

setup 的执行流程如下:

  1. 将一些系统参数(内存, 硬盘等)存在 0x90000 处.
  2. 关闭中断(cli指令), 将 linux(system模块) 移动到 0x00000, 此时 BIOS 提供 的 16 位的中断机制已经没有了(被覆盖了).
  3. 打开 A20, 实现线性寻址.
  4. 对中断重新编程.
  5. 切换到保护模式.
  6. 跳转到(jmpi 0,8) , 8 = 0x00001000(表示0x00000的特权级, 全局描述符表)

head.S

注意, 此时开始采用 AT&T 的汇编语法,

head 的执行流程如下:

  1. 把相应的段寄存器设置为新的保护模式下的值.
  2. 重新设置中断描述符表(只是简单的初始化, 真正的中断以后再安装)
  3. 重新设置全局描述符表(段限长改为16M)
  4. 确定 A20 线是否开启, 是否含有协处理器.
  5. 以下几步非常关键, 把 main 需要的参数(三个空), L6, 和 main 压栈
  6. 然后设置分页: 开启分页功能. 在内存 0x0 处的 5K 存放一页页目录和四页页表 (此时这四页内核专用, 可寻址 16 M, 页表共用)

现代 Linux 的启动引导

Grub + kernel(): 未完待续

分类: Kernel, linux 标签: ,
  1. 2014年10月5日01:53 | #1

    I’m grueftal you made the post. It’s cleared the air for me.

  1. 本文目前尚无任何 trackbacks 和 pingbacks.