计算机系统引导过程

从BIOS启动到Kernel加载

大家天天使用电脑,有没有想过整个系统是如何启动的?从你按下电源键,到显示登录界面,中间究竟经历了什么?

本文主要讲述加载计算机内核系统的全过程,主要参考了MIT 6.828lab1实验以及其他参考资料。某些地址、行为在不同计算机上可能不同,这里仅用JOS系统做例子,重要的是理解整个过程。

-----------------------------------内存示意--------------------------------------
    
+------------------+  <- 0x00100000 (1MB)
|     BIOS ROM     |  <- 0x000FFFF0 (BIOS起始地址)
+------------------+  <- 0x000F0000 (960KB)
|  16-bit devices, |
|  expansion ROMs  |
+------------------+  <- 0x000C0000 (768KB)
|   VGA Display    |
+------------------+  <- 0x000A0000 (640KB)
|                  |
|    Low Memory    |  <- 0x00007C00 (Boot Loader将要载入的地址)
|                  |
+------------------+  <- 0x00000000

第一步 从BIOS开始

首先,我们必须知道,程序只有加载到内存中后,才能被使用。由于某些历史原因,计算机在开机时运行于实模式下,实模式采用16位寻址模式,最大寻址空间为1MB,即在实模式下,CPU仅能访问到1MB的内存地址,而BIOS就被固化在这1MB中(实际会更复杂一些,BIOS存储在可读写ROM中,通过硬接线到物理地址0x000f0000-0x000fffff)。

CPU硬件逻辑设计为在加电瞬间强行将CS值置为0XF000,IP为0XFFF0。该CS:IP地址正是BIOS程序的入口地址。所以,一旦接通电源,计算机将从BIOS指令开始执行

  1. BIOS首先对机器进行加电自检(POST),目的是检查电脑各部件是否良好,包括加载显卡、检查内存总量等操作。
  2. 而后,BIOS将开始初始化工作,主要是设置中断向量表、对外部设备进行一些初始化和检查工作。
  3. 完成一系列初始化工作后,BIOS将磁盘中的第一个扇区载入到内存中(放在 0x7c00-0x7dff 处),该扇区为引导扇区,存储着Boot Loader程序(引导程序)。之后,BIOS使用跳转指令到0x7c00(Boot Loader程序入口)处,将计算机的控制权交给Boot Loader程序,由其继续进行Kernel的引导。

第二步 Boot Loader加载Kernel

在JOS中,Boot Loader包括boot.S汇编程序和main.c两个部分

BIOS使用跳转指令后,来到0x7c00,即boot.S的入口。

boot.S主要是将处理器从实模式转换到 32 位的保护模式,让CPU可以访问到1MB以上的内存区域

  1. 首先,初始化常用寄存器
  2. 而后,打开A20地址线,让程序可以访问1MB以上的内存地址。
  3. 加载全局描述符表,打开保护模式
  4. 跳转到main.c程序地址,执行bootmain函数

bootmain函数负责从硬盘中将kernel读入到内存之中。如何读取的呢?首先,bootmain从第一个扇区开始读入4K数据(引导扇区一般称为第0个扇区),该数据为ELF头和程序头表,保存着整个Kernel的地址、格式信息,获得了一系列信息后,按表中数据将内核读入到内存0x00100000中。至此内核已经被转载至内存中。最后,bootmain函数跳转到Kernel的入口处,将计算机控制权交给内核。