3. UEFI启动流程

UEFI规范把平台固件从加电到操作系统接管的过程划分为七个阶段:SEC、PEI、DXE、BDS、TSL、RT、AL。前五个阶段是“启动期”,后两个阶段是“运行期”。理解这条链路的关键,不是背下缩写,而是看清每个阶段解决什么问题、把什么数据交给下一阶段,以及交接时依赖哪些结构。

核心记忆线:SEC 建临时环境 → PEI 初始化内存 → DXE 建立服务 → BDS 选择启动项 → TSL 移交控制权 → RT 提供运行时服务 → AL 收尾退出。

一、七个阶段的职责与执行顺序

SEC(Security Phase)是加电后的第一段代码,运行在只读存储器的复位向量处。此时内存尚未初始化,可用资源只有CPU缓存和极少量SRAM。SEC的核心任务是建立临时RAM(CAR,Cache As RAM)、验证并解压PEI核心、处理复位类型,最后把控制权交给PEI入口。它还要负责最基础的信任根,例如验证固件卷的完整性。

PEI(Pre-EFI Initialization)阶段的目标是“把内存准备好”。它通过PEI核心调度一系列PEIM(PEI Module),完成内存控制器初始化、芯片组早期配置、发现并描述固件卷。PEI结束时会产生HOB(Hand-Off Block)列表,这是PEI交给DXE最重要的数据结构,里面记录了内存布局、已初始化硬件、固件卷位置等信息。

DXE(Driver Execution Environment)阶段是固件功能的主体。DXE调度器按依赖关系加载并执行DXE驱动,建立启动服务、运行时服务、协议数据库。驱动通过Protocol互相发现和调用,形成完整的固件服务生态。DXE结束时,系统已经具备访问磁盘、网络、输入输出等能力。

BDS(Boot Device Selection)阶段负责“选谁启动”。它枚举启动项、执行启动策略、加载启动设备上的UEFI应用或操作系统加载器。BDS是启动期与运行期的分界点:一旦成功移交控制权,固件就进入TSL。

TSL(Transient System Load)是操作系统加载器运行、但操作系统内核尚未完全接管的过渡期。此时Boot Services仍然可用,加载器可以继续调用固件服务读取文件、分配内存。当加载器调用ExitBootServices()后,Boot Services被销毁,进入RT。

RT(Runtime)阶段操作系统已接管系统,固件只保留运行时服务,例如变量读写、时间服务、复位服务。这些服务在OS运行期间仍可被调用,但不再参与设备枚举和启动决策。

AL(After Life)是固件生命周期的最后阶段,发生在系统关机、休眠或复位前。平台在此阶段保存必要状态、执行清理,然后交还控制权给硬件复位或断电流程。

UEFI 启动阶段链路与交接机制 SEC CAR / 信任根 PEI 内存初始化 DXE 驱动 / 协议 BDS 选择启动项 TSL OS加载器 RT 运行时服务 AL 收尾退出 SEC → PEI 临时RAM / 复位向量 PEI → DXE HOB 列表 DXE → BDS 协议 / 启动服务 BDS → TSL 启动项 / 加载器 TSL → RT ExitBootServices() 阶段间交接机制要点 • SEC→PEI:通过复位向量进入,临时RAM已就绪,PEI核心被验证并解压。 • PEI→DXE:以 HOB 列表传递内存、固件卷、已初始化硬件等描述信息。 • DXE→BDS:DXE 建立协议数据库与启动服务,BDS 据此枚举并选择启动项。 • TSL→RT:加载器调用 ExitBootServices(),Boot Services 销毁,仅保留运行时服务。

二、阶段间交接机制:HOB、协议与事件

阶段之间不是简单的函数调用,而是通过规范定义的数据结构交接。PEI到DXE的核心是HOB列表。HOB是一段段连续内存块,每块有类型和长度,常见类型包括PHIT HOB(描述内存范围)、FV HOB(固件卷位置)、GUID HOB(自定义数据)。DXE核心启动后首先解析HOB,把内存和固件卷信息注册到系统表中。

DXE到BDS的交接依赖协议数据库和启动服务。DXE驱动通过InstallProtocolInterface把能力暴露出去,BDS通过LocateProtocol查找启动策略、设备路径、控制台等协议。BDS本身也是一个DXE应用,它调用Boot Services完成启动项枚举和加载。

TSL到RT的交接由ExitBootServices()触发。这个调用会销毁所有Boot Services,包括内存分配、事件、协议接口。调用前加载器必须获取内存映射键值,调用时传入该键值,若内存映射已变化则调用失败,需要重新获取。这是实际开发中最容易踩坑的交接点。

三、典型场景:一次正常启动的日志观察

在QEMU或真实平台上打开串口日志,可以看到阶段切换的痕迹。下面是一段简化日志,展示了从SEC到BDS的关键输出:

SEC: CAR initialized, reset vector 0xFFFFFFF0
PEI: PEI Core dispatched, HOB list created
PEI: Memory init done, 0x00000000 - 0x7FFFFFFF
DXE: DXE Core started, protocol database ready
DXE: Loaded driver: PciBusDxe, ScsiBusDxe, GraphicsOutputDxe
BDS: Boot option #1: UEFI Shell
BDS: Connecting device path PciRoot(0x0)/Pci(0x1F,0x2)/Sata(0x0)
TSL: ExitBootServices() called, memory map key = 0x9A3C
RT: Runtime services available

从日志可以看出,PEI结束时打印内存范围,说明HOB已生成;DXE阶段出现驱动加载,说明协议数据库在扩展;BDS阶段出现启动项和设备路径,说明启动策略生效;TSL阶段出现ExitBootServices,说明控制权即将完全移交。

四、常见误区与复盘

误区一:把BDS当成“操作系统启动”。 BDS只负责选择和加载启动项,真正的OS内核接管发生在TSL之后。BDS失败通常表现为找不到启动设备或启动项,而不是OS崩溃。
误区二:认为PEI只做内存初始化。 PEI还要发现固件卷、执行早期硅片初始化、生成HOB。如果HOB缺失,DXE可能找不到固件卷,导致驱动无法加载。
误区三:在RT阶段继续调用Boot Services。 ExitBootServices之后,Boot Services指针已失效,继续调用会导致异常。运行时驱动必须只使用Runtime Services。
阶段 核心职责 关键交接物 典型失败现象
SEC 建立临时RAM、验证信任根 复位向量、CAR 无串口输出、复位循环
PEI 初始化内存、生成HOB HOB列表 内存大小识别错误、DXE无法启动
DXE 加载驱动、建立协议 协议数据库、启动服务 设备不可见、驱动依赖缺失
BDS 枚举启动项、加载启动器 启动项、设备路径 找不到启动设备、启动项丢失
TSL OS加载器运行、移交控制权 ExitBootServices() 内存映射键值失效、移交失败
RT 提供运行时服务 变量服务、时间服务 变量读写异常、复位服务不可用
AL 关机/休眠前收尾 状态保存、清理 休眠恢复失败、状态丢失
调试建议:在SEC和PEI早期没有完整控制台时,优先使用端口0x80或平台特定的早期调试口输出阶段标记;进入DXE后再切换到串口或图形控制台。这样可以在“黑屏”阶段快速定位是SEC、PEI还是DXE出了问题。

把七个阶段串起来看,UEFI启动流程本质上是一条“资源逐步可用、服务逐步建立、控制权逐步移交”的链路。SEC解决“能跑”,PEI解决“有内存”,DXE解决“有服务”,BDS解决“启动谁”,TSL解决“交给谁”,RT解决“留下什么”,AL解决“怎么收尾”。掌握每个阶段的交接物,比记住缩写顺序更有实战价值。