开机按下电源键后到底发生了什么?
🔥 UEFI/BSP 开发系列第 003 篇 | 难度:⭐ 入门
作者:BSP 开发工程师
系列目标:300 篇由浅入深,构建完整的 UEFI 固件知识体系
写在前面
这可能是整个系列最核心的一篇。
因为所有的 BIOS/UEFI/BSP 知识,最终都要回到这个问题:
你按下电源键的那一刻,到屏幕亮起的那几秒钟,CPU 到底在忙什么?
今天我们来一步步拆解这个过程。不需要任何前置知识,但看完你对电脑的理解会升级一个维度。
一、按下电源键的第 0 秒
你按下电源键,其实触发的是主板上的 电源管理芯片(PMC / EC) 的一个信号。
这个芯片会做几件事:
- 通知电源(PSU):给各路电压上电——12V、5V、3.3V
- 等待电源稳定:电压稳定后,PSU 会发出一个
POWER_GOOD信号 - 释放 CPU 的复位信号:CPU 的
RESET#引脚从低电平变为高电平
此时 CPU 才真正"醒来"。
注意:按下电源键并不是直接给 CPU 通电。中间有一个"电源管理芯片"在当门卫,它要确认电压稳定后才放行。
二、CPU 醒来的第一件事
CPU 复位后,所有寄存器都被清零或设为固定初始值。但有一个特殊的寄存器——CS:IP(代码段:指令指针)——被硬编码为一个固定地址。
在 x86 架构上,这个地址是:
CS = 0xF000, IP = 0xFFF0
实际物理地址 = 0xFFFFFFF0
这就是传说中的 Reset Vector(复位向量)。
等一下,0xFFFFFFF0 是什么地方?
内存地址空间(简化):
0x00000000 +------------------+
| |
| 物理内存(DRAM) | <-- 这时候还没初始化!不能用!
| |
0x???????? +------------------+
| ... |
| |
0xFFFFFFF0 +------------------+
| SPI Flash 映射 | <-- CPU 从这里开始执行
0xFFFFFFFF +------------------+
0xFFFFFFF0 是 4GB 地址空间的倒数第 16 个字节。这个位置不是内存(DRAM),而是主板上 SPI Flash 芯片 通过地址映射"投射"到这里的。
所以 CPU 醒来后,执行的第一条指令来自 SPI Flash——也就是 BIOS/UEFI 固件。
就像一个刚睡醒的人,睁开眼第一件事是看床头的便签纸(SPI Flash)上写了什么,然后按照上面的指示行动。
三、没有内存怎么办?
这是一个非常反直觉的问题——
CPU 刚上电时,内存(DRAM)还没初始化。DDR 内存条不是通电就能用的,它需要经过复杂的训练(Training)过程才能正常读写。
但 CPU 要跑代码、要有栈、要存临时变量——没有内存怎么办?
答案是 CAR(Cache As RAM)——把 CPU 的缓存当内存用。
正常工作时:
CPU <--> L1/L2/L3 缓存 <--> DRAM 内存
(自动缓存)
CAR 模式:
CPU <--> L2/L3 缓存 (当作 RAM 用) DRAM (还没初始化)
(手动锁定, 不回写)
原理:CPU 缓存本身就是一块高速 SRAM。正常情况下,缓存是 DRAM 的"影子"——CPU 读内存时,数据先进缓存;CPU 写缓存时,数据最终要回写到 DRAM。
但在 CAR 模式下,固件代码把一段缓存锁住(通过设置 MTRR 寄存器为 Write-Back 并且不让它被驱逐),让它不和 DRAM 关联。这样 CPU 就把这块缓存当成了一块独立的 RAM 来用。
通常 L2 缓存可以提供几百 KB 到几 MB 的临时空间。够用吗?够了——这个阶段只需要运行初始化内存的代码,不需要跑操作系统。
四、UEFI 启动的四个阶段
好了,现在 CPU 醒来了,有了临时内存(CAR),可以开始正经干活了。
UEFI 的启动流程分为四个阶段,每个阶段有明确的职责:
SEC ---------> PEI ---------> DXE ---------> BDS
安全初始化 预EFI初始化 驱动执行环境 启动设备选择
(Security) (Pre-EFI Init) (Driver Exec) (Boot Device)
临时内存(CAR) 初始化真正内存 加载所有驱动 找到OS并启动
几百KB 几GB可用 PCI/USB/NVMe... Windows/Linux
Stage 1: SEC(Security,安全初始化)
一句话:CPU 醒来后执行的第一段代码。
干了什么:
- 从 Reset Vector (0xFFFFFFF0) 开始执行
- 设置临时内存(CAR)
- 找到 PEI 模块的入口点
- 跳转到 PEI
时间:几毫秒
SEC 阶段的代码很少,核心任务就是"让 CPU 有个能跑 C 代码的最小环境"。这个阶段通常用汇编写。
Stage 2: PEI(Pre-EFI Initialization,预 EFI 初始化)
一句话:初始化内存和最基本的硬件。
干了什么:
- 初始化真正的 DRAM 内存(调用 MRC / FSP-M)
- 初始化 CPU 的基本设置
- 初始化芯片组(PCH)的基本功能
- 通过 HOB(Hand-Off Block)把初始化结果传给下一阶段
时间:几百毫秒到几秒(内存训练最耗时)
PEI 是整个启动过程中最关键的阶段。如果内存初始化失败,后面什么都别想干了——没有内存,就没有操作系统。
PEI 阶段有一个重要概念:PEIM(PEI Module)。每个 PEIM 负责初始化一个硬件子系统。PEIM 之间通过 PPI(PEI-to-PEI Interface) 通信。
Stage 3: DXE(Driver Execution Environment,驱动执行环境)
一句话:加载和执行所有硬件驱动。
到了这个阶段,内存已经可用了(几 GB),CPU 运行在 64 位模式,可以干大事了。
干了什么:
- DXE Dispatcher 加载几十到几百个驱动模块
- PCI 总线枚举——发现连接了哪些设备
- 初始化显卡(GOP 驱动)——屏幕开始能显示东西了
- 初始化 USB 控制器——键盘鼠标开始能用了
- 初始化 NVMe/SATA——硬盘可以访问了
- 初始化网络——PXE 启动需要
时间:1-3 秒
DXE 阶段的驱动通过 Protocol(协议) 互相通信。Protocol 本质上就是一个函数指针表——你可以理解为"我提供这些接口,你来调用"。
显卡驱动安装 GOP Protocol:
+-- DrawPixel()
+-- SetMode()
+-- GetInfo()
其他驱动想显示文字:
找到 GOP Protocol -> 调用 DrawPixel()
Stage 4: BDS(Boot Device Selection,启动设备选择)
一句话:找到操作系统并把控制权交出去。
干了什么:
- 读取启动顺序(UEFI 变量 BootOrder)
- 在 EFI 系统分区(ESP)中找到
.efi启动文件 - Secure Boot 验证(如果开启了的话)
- 加载操作系统的 bootloader
- 把控制权交给操作系统
时间:几百毫秒
BDS 的选择过程:
BootOrder = [0001, 0003, 0002]
Boot0001: Windows Boot Manager
-> ESP:\EFI\Microsoft\Boot\bootmgfw.efi [找到了!]
-> Secure Boot 签名验证... OK
-> 加载执行
-> 交接给 Windows
(如果 Windows 启动失败, 继续尝试 Boot0003...)
五、从零到桌面:完整时间线
以一台现代笔记本为例(总时间约 5-8 秒):
时间 事件
------ ------------------------------------
0.00s 按下电源键
0.01s PMC/EC 给各路电压上电
0.05s POWER_GOOD 信号, CPU 复位释放
0.05s SEC: Reset Vector, 设置 CAR
0.06s PEI: 开始执行
0.10s PEI: CPU 初始化
0.50s PEI: 内存训练 (DDR5 Training) <-- 最耗时
1.00s PEI: 内存初始化完成, 切换到 DRAM
1.00s DXE: Dispatcher 开始加载驱动
1.50s DXE: PCI 枚举完成
2.00s DXE: 显卡初始化, 屏幕亮了!
2.50s DXE: USB/NVMe/网络初始化
3.00s BDS: 找到启动项
3.10s BDS: 加载 Windows Boot Manager
3.20s OS Loader 开始执行
5-8s Windows 桌面出现
注意内存训练(DDR5 Training)占了将近一半时间。这就是为什么BSP工程师要花大量时间优化内存初始化——因为它直接影响开机速度。
六、一个经常被忽略的角色:FSP
在 Intel 平台上,PEI 阶段的核心工作不是由 BIOS 厂商自己写的,而是由 Intel 以二进制形式提供的 FSP(Firmware Support Package)。
FSP 分三部分:
| 组件 | 调用时机 | 核心功能 |
|---|---|---|
| FSP-T | SEC 末尾 | 设置临时内存(CAR) |
| FSP-M | PEI 阶段 | 内存初始化(MRC) |
| FSP-S | DXE 早期 | 硅平台初始化(PCH、IO等) |
为什么 Intel 不直接给源码?
因为内存初始化代码涉及 Intel 的核心 IP(知识产权)——DDR 控制器的 Training 算法、时序参数、错误恢复策略……这些是 Intel 花几十亿美元研发的成果,不可能公开。
所以 Intel 把这些代码编译成二进制库(FSP),提供标准的 C 语言接口。BIOS 厂商和 BSP 工程师调用接口,传入配置参数(UPD),FSP 内部完成实际的初始化工作。
BSP 工程师的工作:
你不需要写内存初始化代码
你需要:
1. 了解你的硬件板子的内存拓扑
2. 配置正确的 UPD 参数
3. 调用 FSP-M 的入口函数
4. 检查返回值是否成功
5. 如果失败, 分析 MRC 日志排查问题
七、如果把开机过程比作盖房子
SEC = 工人到达工地, 搭了个临时帐篷 (CAR)
工地上还没水没电, 只有帐篷能遮风挡雨
PEI = 先把自来水接上 (内存初始化)
水通了才能开始施工
DXE = 装修开始: 水电(PCI), 墙面(显卡), 门窗(USB), 家具(NVMe)
每个工种是一个"驱动", 各干各的
BDS = 装修完毕, 通知业主(操作系统)可以搬进来了
验收 (Secure Boot), 交钥匙 (ExitBootServices)
八、总结
| 阶段 | 全称 | 核心任务 | 可用资源 |
|---|---|---|---|
| SEC | Security | CPU 复位, 建立临时内存 | CAR (几百KB) |
| PEI | Pre-EFI Init | 内存初始化 | CAR -> DRAM |
| DXE | Driver Execution | 加载所有硬件驱动 | 全部 DRAM |
| BDS | Boot Device Selection | 找到并启动 OS | 全部硬件 |
记住这四个字母 SEC-PEI-DXE-BDS,它是整个 UEFI 世界的骨架。后面 297 篇文章展开的所有知识,都挂在这个骨架上。
下一篇预告
004. UEFI vs Legacy BIOS:一张图看懂区别
用一张完整的对比图,把传统 BIOS 和 UEFI 的所有差异一网打尽。
📌 本系列共 300 篇,从入门到芯片原厂 BSP 能耗优化
👨💻 作者:在职 BSP 开发工程师,持续更新中
🏷️ 标签:UEFI、开机流程、SEC、PEI、DXE、BDS、FSP、CAR
📁 GitHub:UEFI-BSP-300