Zwlin's Blog

BIOS 启动过程

Last updated: 2019/01/13     Published at: 2019/01/13

搬运自我的 Linux0.11 仓库

BIOS 启动过程

当计算机加电后,一般不直接执行操作系统,而是执行系统初始化软件完成基本 IO 初始化和引导加载功能。简单地说,系统初始化软件就是在操作系统内核运行之前运行的一段小软件。通过这段小软件,我们可以初始化硬件设备、建立系统的内存空间映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核准备好正确的环境。最终引导加载程序把操作系统内核映像加载到 RAM 中,并将系统控制权传递给它。

对于绝大多数计算机系统而言,操作系统和应用软件是存放在磁盘 (硬盘/软盘)、光盘、EPROM、ROM、Flash 等可在掉电后继续保存数据的存储介质上。计算机启动后,CPU 一开始会到一个特定的地址开始执行指令,这个特定的地址存放了系统初始化软件,负责完成计算机基本的 IO 初始化,这是系统加电后运行的第一段软件代码。对于 Intel 80386 的体系结构而言,PC 机中的系统初始化软件由 BIOS (Basic Input Output System,即基本输入/输出系统,其本质是一个固化在主板 Flash/CMOS 上的软件) 和位于软盘/硬盘引导扇区中的 OS Boot Loader (在 ucore 中的 bootasm.S 和 bootmain.c) 一起组成。BIOS 实际上是被固化在计算机 ROM (只读存储器) 芯片上的一个特殊的软件,为上层软件提供最底层的、最直接的硬件控制与支持。更形象地说,BIOS 就是 PC 计算机硬件与上层软件程序之间的一个“桥梁”,负责访问和控制硬件。

以 Intel 80386 为例,计算机加电后,CPU 从物理地址 0xFFFFFFF0 (由初始化的 CS:EIP 确定,此时 CS 和 IP 的值分别是 0xF000 和 0xFFF0))开始执行。在 0xFFFFFFF0 这里只是存放了一条跳转指令,通过跳转指令跳到 BIOS 例行程序起始点。BIOS 做完计算机硬件自检和初始化后,会选择一个启动设备 (例如软盘、硬盘、光盘等),并且读取该设备的第一扇区 (即主引导扇区或启动扇区) 到内存一个特定的地址 0x7c00 处,然后 CPU 控制权会转移到那个地址继续执行。至此 BIOS 的初始化工作做完了,进一步的工作交给了 bootloader。

补充信息

Intel 的 CPU 具有很好的向后兼容性。在 16 位的 8086 CPU 时代,内存限制在 1MB 范围内,且 BIOS 的代码固化在 EPROM 中。在基于 Intel 的 8086 CPU 的 PC 机中的 EPROM 被编址在 1MB 内存地址空间的最高 64KB 中。PC 加电后,CS 寄存器初始化为 0xF000,IP 寄存器初始化为 0xFFF0,所以 CPU 要执行的第一条指令的地址为 CS:IP=0xF000:0XFFF0 (Segment:Offset 表示)=0xFFFF0 (Linear 表示)。这个地址位于被固化 EPROM 中,指令是一个长跳转指令 JMP F000:E05B。这样就开启了 BIOS 的执行过程。

到了 32 位的 80386 CPU 时代,内存空间扩大到了 4G,多了段机制和页机制,但 Intel 依然很好地保证了 80386 向后兼容 8086。地址空间的变化导致无法直接采用 8086 的启动约定。如果把 BIOS 启动固件编址在 0xF000 起始的 64KB 内存地址空间内,就会把整个物理内存地址空间隔离成不连续的两段,一段是 0xF000 以前的地址,一段是 1MB 以后的地址,这很不协调。为此,intel 采用了一个折中的方案:默认将执行 BIOS ROM 编址在 32 位内存地址空间的最高端,即位于 4GB 地址的最后一个 64KB 内。在 PC 系统开机复位时,CPU 进入实模式,并将 CS 寄存器设置成 0xF000,将它的 shadow register 的 Base 值初始化设置为 0xFFFF0000,EIP 寄存器初始化设置为 0x0000FFF0。所以机器执行的第一条指令的物理地址是 0xFFFFFFF0。80386 的 BIOS 代码也要和以前 8086 的 BIOS 代码兼容,故地址 0xFFFFFFF0 处的指令还是一条长跳转指令 jmp F000:E05B。注意,这个长跳转指令会触发更新 CS 寄存器和它的 shadow register,即执行 jmp F000 : E05B 后,CS 将被更新成 0xF000。表面上看 CS 其实没有变化,但 CS 的 shadow register 被更新为另外一个值了,它的 Base 域被更新成 0x000F0000,此时形成的物理地址为 Base+EIP=0x000FE05B,这就是 CPU 执行的第二条指令的地址。此时这条指令的地址已经是 1M 以内了,且此地址不再位于 BIOS ROM 中,而是位于 RAM 空间中。由于 Intel 设计了一种映射机制,将内存高端的 BIOS ROM 映射到 1MB 以内的 RAM 空间里,并且可以使这一段被映射的 RAM 空间具有与 ROM 类似的只读属性。所以 PC 机启动时将开启这种映射机制,让 4GB 地址空间的最高一个 64KB 的内容等同于 1MB 地址空间的最高一个 64K 的内容,从而使得执行了长跳转指令后,其实是回到了早期的 8086 CPU 初始化控制流,保证了向下兼容。