开机按下电源键后到底发生了什么?

0 阅读9分钟

开机按下电源键后到底发生了什么?

🔥 UEFI/BSP 开发系列第 003 篇 | 难度:⭐ 入门

作者:BSP 开发工程师

系列目标:300 篇由浅入深,构建完整的 UEFI 固件知识体系


写在前面

这可能是整个系列最核心的一篇。

因为所有的 BIOS/UEFI/BSP 知识,最终都要回到这个问题:

你按下电源键的那一刻,到屏幕亮起的那几秒钟,CPU 到底在忙什么?

今天我们来一步步拆解这个过程。不需要任何前置知识,但看完你对电脑的理解会升级一个维度。


一、按下电源键的第 0 秒

你按下电源键,其实触发的是主板上的 电源管理芯片(PMC / EC) 的一个信号。

这个芯片会做几件事:

  1. 通知电源(PSU):给各路电压上电——12V、5V、3.3V
  2. 等待电源稳定:电压稳定后,PSU 会发出一个 POWER_GOOD 信号
  3. 释放 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-TSEC 末尾设置临时内存(CAR)
FSP-MPEI 阶段内存初始化(MRC)
FSP-SDXE 早期硅平台初始化(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)

八、总结

阶段全称核心任务可用资源
SECSecurityCPU 复位, 建立临时内存CAR (几百KB)
PEIPre-EFI Init内存初始化CAR -> DRAM
DXEDriver Execution加载所有硬件驱动全部 DRAM
BDSBoot 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