B03 —— 完整的 Boot 流程:从按下电源键到控制权交给内核
金句:每一次开机,都是一场精密的接力赛——每一棒都不能掉。
Boot 的完整流程总览
按下电源键后,计算机经历一系列阶段,最终把控制权交给操作系统内核:
完整的 Boot 流程:
[硬件上电] → CPU Reset → BIOS/UEFI → Bootloader → Kernel
详细阶段:
1. 硬件上电(Power-On)
2. CPU 复位(Reset Vector)
3. BIOS/UEFI 初始化(PEI)
4. 固件驱动和内存初始化(DXE)
5. 系统启动设备选择(BDS)
6. Bootloader 加载(GRUB/SYSTEMD-BOOT)
7. 内核解压和执行(Linux Kernel)阶段 1:硬件上电和 CPU 复位
按下电源键后:
1. 电源启动 → 供电稳定(约 100~500ms)
2. VR(Voltage Regulator)输出稳定电压
3. CPU 的 RESET# 引脚被释放
4. CPU 内部寄存器初始化(x86: CR3, CR4, EFLAGS = 0)
5. CPU 开始执行第一条指令
第一条指令在哪里:
x86 架构:
CS:IP = 0xF000:0xFFF0(CS = 0xF000, IP = 0xFFF0)
这个地址在 BIOS ROM 里
→ CPU 执行的第一条指令是 JMP 到 BIOS 入口点
ARM 架构:
PC = 0x00000000(复位向量)
在 ARM 设计中,这个地址通常映射到 BootROM(SoC 内置)
→ 第一条指令可能是固化在 ROM 中的 Bootloader阶段 2:BIOS/UEFI 初始化(PEI)
UEFI 的 Boot 阶段(UEFI PI Architecture):
PEI(Pre-EFI Initialization):
- CPU 微码加载(Microcode Patch)
- 最小硬件初始化(栈、指针)
- 内存初始化(读取 SPD,开始 Training)
- 固件卷(FV)发现和解密
SEC(Security)→ PEI→ DXE→ BDS→ TSL→ RT→ AL:
SEC(Security):CPU 初始化的第一步,信任根
PEI:内存初始化,固件卷加载
DXE(Driver Execution Environment):设备驱动初始化,PCIe 枚举
BDS(Boot Device Selection):选择启动设备
TSL(Transient System Load):加载 Short Boot Loader
RT(Runtime):操作系统运行
AL(After Life):关机后清理阶段 3:内存初始化(SPD 读取 + Training)
BIOS 内存初始化(在 PEI 阶段):
1. I2C 总线扫描
→ 探测每个通道的 DIMM(地址 0x50/0x51/0x52)
→ 读取 SPD,存储容量/频率/时序
2. 内存控制器配置
→ 基于 SPD 配置时序(CL/tRCD/tRP/tRAS)
→ 配置频率(优先 XMP,否则 JEDEC)
→ 配置电压(1.2V 或 1.35V)
3. Memory Training(内存培训)
- Write Leveling:校准 DQS 和 CK 的相位
- Read Gate Training:找到读数据的最佳采样点
- Write DQ Calibration:校准每个 DQ 引脚
- Per-DQS Training:精细校准每个 DQS
4. 内存测试
- BIOS 写一小段测试数据,读出验证
- 如果失败,显示"Memory error"并停机
5. 构建 e820 表
→ 已知物理内存分布
→ 加上 MMIO 区域
→ 操作系统将收到这份完整的内存地图阶段 4:Bootloader 加载
BIOS 找到启动设备后,执行 Bootloader:
1. BIOS 遍历启动设备顺序(UEFI Boot Order)
→ 检查第一个设备的 Bootable Flag
→ 如果是 MBR:读取 0扇区(512B),跳转到 Bootloader 代码
→ 如果是 GPT/UEFI:读取 EFI 分区,加载 .efi 文件
2. GRUB(Grand Unified Bootloader)加载:
阶段 1.5(可选):读取 MBR 后的扇区(GRUB Stage 1.5)
阶段 2:加载 GRUB 配置文件(/boot/grub/grub.cfg)
→ 显示启动菜单(Kernel 选择、恢复模式等)
→ 用户选择后,加载 Kernel
3. UEFI 直接启动(无 GRUB):
→ UEFI Shell 或 SYSTEMD-BOOT
→ 从 ESP(EFI System Partition)读取 .efi 文件
→ 直接跳转到 Kernel(跳过 GRUB)阶段 5:内核加载和执行
GRUB 加载 Linux Kernel 的过程:
1. GRUB 读取 vmlinuz(压缩 Kernel 镜像)
2. GRUB 读取 initramfs(初始 RAM 文件系统)
3. GRUB 把控制权交给 Kernel
Kernel 启动(arch/x86/boot/):
0x100000:Kernel 代码开始(解压前的位置)
解压:从 0x100000 解压到更高的地址
arch/x86/boot/header.S:
入口点:start_of_setup
→ 设置临时 GDT(Global Descriptor Table)
→ 设置临时 IDT(Interrupt Descriptor Table)
→ 切换到 32-bit 保护模式(CR0.PE=1)
→ 跳转到 32-bit 入口点(compressed/head.o)
arch/x86/boot/compressed/:
decompress: 解压 vmlinuz
→ 调用 startup_32 或 startup_64
跳转到真正内核入口:
→ 内核入口点:startup_64(x86_64)
→ 内存管理初始化(paging_setup)
→ 系统数据结构初始化(kmem_cache)内核启动阶段的内存初始化
Linux Kernel 的内存初始化顺序(startup_64):
1. early_fixmap_init():
- 建立早期固定映射(用于 early console, ACPI 等)
2. setup_arch():
- 读取 e820(从 BIOS 传递的参数)
- 调用 e820__memory_setup() → 构建内核内存映射
- 调用 e820__reserve_memory() → 保留特殊区域
3. paging_init():
- 初始化页表(PGDIR)
- 开启分页机制(CR0.PG=1)
- 虚拟地址空间开始工作
4. mem_init():
- 释放未使用的内存(bootmem → buddy system)
- 计算实际可用内存
- 输出:Memory: 32768MB available
5. kmem_cache_init():
- SLAB/SLUB 分配器初始化
- 用于内核对象分配
6. 启动用户空间:
→ init 进程(PID 1)开始执行
→ 用户空间程序开始运行总结
- Boot 完整流程:上电 → CPU Reset(0xF000:0xFFF0)→ BIOS/UEFI → Bootloader(GRUB)→ Kernel
- BIOS 阶段:SEC → PEI(内存 SPD 读取 + Training)→ DXE(驱动)→ BDS(启动设备选择)
- 内存初始化:读取 SPD → 配置控制器 → Write Leveling / Read Gate Training → e820 表构建
- Bootloader:MBR 读取 → GRUB Stage 1.5/2 → 加载 vmlinuz + initramfs
- 内核启动:解压 → setup_arch(e820)→ paging_init(分页开启)→ mem_init(buddy system)→ kmem_cache
下篇预告(B04):CPU 复位后,怎么从实模式跳到保护模式?GDT 表、段选择子、以及 CR0 寄存器怎么设置。
关注公众号「AI不着急」,回复”资料”获取内存学习路线图。
评论