1. 计算机启动概述:从按下电源键到操作系统启动的完整硬件与固件流程概览
计算机的启动过程是一个从硬件初始化到软件加载的精密协作流程。当用户按下电源键时,系统从完全断电状态开始,依次经历电源供给、固件自检、硬件枚举、引导加载程序执行,最终将控制权移交给操作系统内核。本章将拆解这一完整链条,为后续深入分析 Linux 内核启动奠定基础。
1.1 启动流程全景图
下图展示了从按下电源键到操作系统内核启动的完整硬件与固件流程。每个阶段都有明确的输入、输出和关键组件参与。
1.2 启动阶段详细分解
计算机启动过程可以划分为七个核心阶段,每个阶段都有明确的硬件/软件组件参与和特定的输出结果。
| 阶段 | 名称 | 主要参与者 | 关键输出 | 典型耗时 |
|---|---|---|---|---|
| ① | 电源上电 | 电源管理单元 (PMU)、时钟发生器 | PWR_OK 信号、时钟稳定 | 100-500ms |
| ② | CPU 复位 | CPU 内部逻辑、复位向量 | CS:IP = 0xF000:0xFFF0 | < 1ms |
| ③ | BIOS/UEFI 初始化 | 固件 ROM、CMOS、NVRAM | POST 完成、硬件枚举表 | 0.5-3s |
| ④ | 引导设备选择 | 固件、引导顺序列表 | MBR/GPT 扇区读取 | 0.1-1s |
| ⑤ | Bootloader 执行 | GRUB/syslinux/LILO | 内核映像加载到内存 | 1-5s |
| ⑥ | 内核初始化 | Linux 内核 (start_kernel) | 调度器、内存管理就绪 | 0.5-3s |
| ⑦ | init 进程启动 | systemd / SysV init | 用户态服务启动 | 1-10s |
1.3 电源上电与硬件复位
按下电源键后,系统首先经历电源稳定和硬件复位两个关键子阶段。
1.3.1 电源上电时序
- 电源键触发:电源键按下后,主板上的电源管理单元 (PMU) 检测到电平变化。
- 电源就绪 (PWR_OK):ATX 电源输出稳定的 +3.3V、+5V、+12V 后,向主板发送 PWR_OK 信号。
- 时钟发生器启动:主板上的时钟发生器 (Clock Generator) 开始输出稳定的系统时钟信号 (通常为 100MHz 基准时钟)。
- 复位信号释放:芯片组在确认电源和时钟稳定后,释放 CPU 的 RESET# 引脚。
1.3.2 CPU 复位状态
当 RESET# 引脚从低电平变为高电平时,CPU 进入复位状态。x86 架构 CPU 复位后的初始状态如下:
| 寄存器 | 复位值 | 说明 |
|---|---|---|
| CS (代码段) | 0xF000 | 基地址 = 0xFFFF0000 (实模式) |
| IP (指令指针) | 0xFFF0 | 偏移量 |
| EFLAGS | 0x00000002 | IF=0 (中断关闭) |
| CR0 | 0x60000010 | PE=0 (实模式), EM=1 |
| GDTR | 0x00000000 | 全局描述符表基址清零 |
CPU 复位后,第一条指令从物理地址 0xFFFFFFF0 开始执行(对应 CS:IP = 0xF000:0xFFF0,在实模式下 CS 基址为 0xFFFF0000)。这个地址映射到固件 ROM 的最后 16 字节,包含一条跳转指令,指向 BIOS/UEFI 的入口代码。
0x00000000 或 0xFFFF0000(取决于实现),且复位后 CPU 处于 SVC (Supervisor) 模式。RISC-V 架构的复位向量由硬件设计决定,通常位于内存映射的高地址区域。
1.4 BIOS 与 UEFI 固件阶段
固件阶段是硬件初始化的核心环节,负责将系统从原始硬件状态提升到可引导状态。现代系统主要使用 UEFI,但 BIOS (Legacy) 仍在大量嵌入式系统和旧硬件中存在。
1.4.1 BIOS 与 UEFI 对比
| 特性 | BIOS (Legacy) | UEFI |
|---|---|---|
| 接口模式 | 16 位实模式 | 32/64 位保护模式 |
| 引导扇区 | MBR (512 字节) | GPT + ESP 分区 |
| 磁盘容量 | 最大 2.2TB | 最大 9.4ZB |
| 启动速度 | 较慢 (串行初始化) | 较快 (并行初始化) |
| 网络支持 | PXE (扩展) | 内置 HTTP/iSCSI |
| 安全启动 | 不支持 | Secure Boot |
| 驱动模型 | Option ROM | UEFI 驱动 |
1.4.2 POST 执行流程
加电自检 (POST) 是固件阶段的核心任务,按以下顺序执行:
- CPU 测试:验证 CPU 内部寄存器和缓存。
- 芯片组初始化:配置内存控制器、PCIe 根复合体。
- 内存检测:检测并初始化 DRAM,建立内存映射表。
- 总线枚举:扫描 PCI/PCIe 总线,分配资源 (MMIO、IRQ)。
- 外设初始化:初始化存储控制器、USB 控制器、显示适配器。
- 引导设备枚举:列出可引导设备,按优先级排序。
dmesg 或 UEFI Shell 查看。
1.5 引导设备选择与 MBR/GPT
固件完成 POST 后,根据配置的引导顺序列表依次尝试从各设备加载引导代码。
1.5.1 引导设备优先级
典型的引导顺序配置如下:
| 优先级 | 设备类型 | 典型接口 | 备注 |
|---|---|---|---|
| 1 | USB 闪存盘 | USB 2.0/3.0 | 系统安装/救援 |
| 2 | NVMe SSD | PCIe 3.0/4.0 | 现代主存储 |
| 3 | SATA SSD/HDD | SATA 3.0 | 传统主存储 |
| 4 | 网络 (PXE) | 以太网 | 无盘工作站 |
| 5 | 光驱 | SATA/USB | 已逐渐淘汰 |
1.5.2 MBR 与 GPT 分区表结构
固件读取引导设备的第一个扇区(LBA 0),根据分区表类型决定后续加载方式。
| 项目 | MBR (Legacy) | GPT (UEFI) |
|---|---|---|
| 扇区位置 | LBA 0 (512 字节) | LBA 0 (保护 MBR) + LBA 1 (GPT 头) |
| 分区数量 | 最多 4 个主分区 | 最多 128 个分区 (默认) |
| 分区大小 | 最大 2.2TB | 最大 9.4ZB |
| 冗余备份 | 无 | GPT 头备份在磁盘末尾 |
| 校验机制 | 无 | CRC32 校验 |
| 引导代码 | MBR 前 446 字节 | ESP 分区中的 .efi 文件 |
1.6 Bootloader 加载与执行
Bootloader 是固件与操作系统内核之间的桥梁。以 GRUB 2 为例,其加载过程分为多个阶段:
1.7 内核启动入口
Bootloader 将控制权交给内核时,CPU 处于特定状态。x86 架构下,内核入口点根据引导协议约定:
- 实模式入口:
startup_32(32 位) 或startup_64(64 位),位于内核映像的偏移 0x200 处。 - 引导协议版本:Linux 内核支持多个引导协议版本 (v2.00 ~ v2.15),Bootloader 必须设置正确的
hdr结构体。 - 初始状态要求:Bootloader 需要提供
boot_params结构体,包含内存映射、命令行参数、initrd 地址等信息。
// Linux 内核引导协议头结构 (arch/x86/include/uapi/asm/bootparam.h)
struct setup_header {
__u8 setup_sects; // 设置扇区数
__u16 root_flags; // 根文件系统标志
__u32 syssize; // 系统大小
__u16 ram_size; // 内存大小
__u16 vid_mode; // 视频模式
__u16 root_dev; // 根设备
__u16 boot_flag; // 0xAA55 引导标志
__u16 jump; // 跳转指令
__u32 header; // 头部签名 "HdrS"
// ... 更多字段
__u32 cmd_line_ptr; // 命令行指针
__u32 initrd_addr_max; // initrd 最大地址
__u32 kernel_alignment; // 内核对齐要求
} __attribute__((packed));
set debug=all 开启详细日志,观察内核加载过程中的内存地址和参数传递。内核启动后,通过 dmesg | grep -i "boot" 查看引导阶段的内核日志。
1.8 启动流程中的关键时序指标
以下表格汇总了启动流程中各阶段的关键时序指标,帮助工程师定位性能瓶颈:
| 阶段 | 理想时间 | 可接受时间 | 异常阈值 | 常见瓶颈 |
|---|---|---|---|---|
| POST | < 1s | 1-3s | > 5s | 内存检测、PCIe 枚举 |
| Bootloader | < 1s | 1-3s | > 5s | 磁盘 I/O、文件系统加载 |
| 内核解压 | < 0.5s | 0.5-2s | > 3s | CPU 性能、压缩算法 |
| 内核初始化 | < 1s | 1-3s | > 5s | 驱动加载、ACPI 解析 |
| init 启动 | < 2s | 2-5s | > 10s | 服务依赖、网络等待 |
systemd-analyze blame 分析各服务耗时,或使用 bootchart 生成启动时序图。对于嵌入式系统,可以考虑使用 initramfs 裁剪和内核模块静态编译来缩短启动时间。