概述
Linux内核启动流程根据是否与体系结构相关主要可分为两个阶段。
第一阶段:引导过程
==> 系统上电
===> CPU自身初始化
---------------------------------BIOS------------------------------------------
===> 加电自检
===> 加载内核引导程序
------------------------------内核引导程序-----------------------------------
===> 主引导程序
===> 次引导程序
----------------------------------------------------------------------------------
===> 调用内核
1、CPU自身初始化
CPU 自身的初始化是引导过程的第一步,如果有多个 CPU,即多处理器系统,则每个CPU 都要进行自身初始化。CPU自身初始化之后从一个固定的位置(一般是0xfffffff0)取得指令并执行该指令为跳转指令跳转到BIOS代码的首部。
2、BIOS
BIOS 被固化于主板上一个容量相对较小的只读存储器(Read-Only Memory,ROM)中,它的工作主要有两个:加电自检,即进行所谓的 POST(Power On Self Test)和加载内核引导程序。
POST 阶段完成系统硬件的检测,包括内存检测、系统总线检测等。POST 完成之后,BIOS 读取启动设备第一个扇区,即首 512 字节的信息, 该扇区又被称之为主引导记录(Master Boot Record,MBR)。MBR 中保存了内核引导程序的开始部分,BIOS 将其加载到内存并执行。
3、内核引导程序
内核引导程序分为两个阶段:MBR 中的主引导程序;活动分区引导记录中的次引导程序。MBR 中的主引导程序是一个 512 字节的映像,它包含了 446 字节的程序代码和 64 字节的分区表,最后两个字节固定为 0xAA55,用于检查 MBR 是否有效。
主引导程序:扫描分区表,寻找活动分区,将位于活动分区引导记录中的次引导程序加载到内存中并执行。
次引导程序:负责加载 Linux 内核映像,并将控制权转交给内核。
4、内核
函数 | 位置(ARCH为体系架构,如arm、i386....) | 功能 |
start | arch/ARCH/boot/head.S | 进行一些基本的硬件设置 |
startup_32 | arch/ARCH/boot/compressed/head.S | 例程设置一个基本的运行环境(堆栈等),并清除 BSS(Block Started by Symbol) |
decompress_kernel | arch/ARCH/boot/compressed/misc.c | 解压内核 |
startup_32 | arch/ARCH/kernel/head.S | 对页表进行初始化,启用内存分页功能,并为任何可选的浮点单元(FPU)检测 CPU 的类型 |
start_kernel | arch/ARCH/kernel/head.S | 进入体系结构无关的内核部分。自此,内核的引导过程告一段落,进入内核的初始化过程。 |
总结:引导过程可归纳为:CPU 加载 BIOS,BIOS 加载内核引导程序,内核引导程序加载压缩内核,压缩内核加载解压内核。
第二阶段:内核初始化
函数 | 位置 | 功能 |
start_kernel | init/main.c | 完成了内核的大部分初始化工作,相当于内核的 main 函数 |
reset_init | init/main.c | 启动内核线程 kernel_init |
kernel_init | init/main.c | 完成设备驱动程序的初始化 |
init_post | init/main.c | 启动用户空间的 init进程 |
至此,内核已被引导并进行了初始化,且启动了自己的第一个用户空间应用程序,即 init。这是调用的第一个使用标准 C 库编译的程序,其进程编号始终为 1。