2、UEFI启动流程全景:平台初始化(PEI阶段)、驱动执行环境(DXE阶段)、启动设备选择(BDS阶段)、运行时服务(RT阶段)
UEFI的启动流程,说白了就是一台电脑从按下电源键到操作系统接管前的「热身运动」。我做了这么多年固件,见过不少工程师把UEFI当成黑盒子,出了问题就抓瞎。其实它的四个核心阶段——PEI、DXE、BDS、RT——就像接力赛,每一棒都有明确的任务。
今天我就把这四个阶段掰开揉碎了讲。你想想看,搞懂了这些,以后遇到启动问题,你就能像老中医一样「望闻问切」了。
2.1 PEI阶段:从零开始的「侦察兵」
PEI(Pre-EFI Initialization)是UEFI启动的第一棒。这时候内存还没初始化,CPU刚复位,整个系统就像一张白纸。
PEI的核心任务:
- 检测CPU、芯片组、主板的初始状态
- 初始化临时内存(Cache as RAM,简称CAR)
- 发现并启动主内存控制器
- 传递系统信息给下一阶段
我个人习惯把PEI比作「侦察兵」。它不需要大部队(完整内存),只需要带点干粮(CPU缓存当内存用)就能摸清地形。
避坑指南:我曾经在一个项目中,PEI阶段死活过不去。查了三天,发现是CAR的栈指针设置错了。嗯,这里要注意——CAR的大小通常只有4KB到64KB,千万别放太多全局变量。
PEI阶段的代码以「PEIM」(PEI Module)的形式存在。它们被打包在固件卷(FV)里,由PEI调度器按依赖关系执行。典型的PEIM包括:
- CPU PEIM:初始化CPU微码、设置MTRR
- 芯片组PEIM:配置南北桥寄存器
- 内存PEIM:训练DDR、初始化内存控制器
2.2 DXE阶段:驱动大军的「阅兵式」
DXE(Driver Execution Environment)是UEFI最庞大的阶段。这时候内存已经就绪,各种驱动可以尽情加载了。
DXE的核心任务:
- 初始化完整的系统服务(Boot Services、Runtime Services)
- 枚举并加载所有DXE驱动
- 创建系统表(System Table)、启动服务表(Boot Services Table)
- 初始化控制台、存储设备、网络等
DXE阶段的驱动执行顺序由依赖关系决定。每个驱动都有一个DEPEX(Dependency Expression),比如「等我需要的协议准备好了再叫我」。这有点像现代操作系统的设备树——先有根节点,再有子节点。
个人经验:我记得有一次调试一个NVMe驱动,它总在DXE阶段崩溃。后来发现是DEPEX写错了,它依赖的PCI IO协议还没准备好。你想想看,驱动就像排队打饭,前面的人没打好,后面的人只能干瞪眼。
DXE阶段结束后,系统已经具备了完整的硬件抽象层(HAL)。这时候UEFI会调用BDS阶段。
2.3 BDS阶段:选择「谁来接班」
BDS(Boot Device Selection)阶段的任务很明确——决定从哪个设备启动操作系统。
BDS的核心流程:
- 枚举所有可启动设备(硬盘、光驱、USB、网络等)
- 读取启动顺序(BootOrder变量)
- 尝试每个启动项,直到成功
- 加载启动项对应的引导程序(如bootmgfw.efi)
BDS阶段会调用「Boot Manager」——这是UEFI内置的一个小程序。它负责维护启动菜单、处理用户按键、执行启动策略。
注意:我曾经遇到一个坑——客户说机器偶尔无法进入系统。查了半个月,发现是BootOrder变量被意外修改了。嗯,这里要提醒大家:BDS阶段对NVRAM的写入操作一定要加锁,否则并发访问会搞乱启动顺序。
BDS阶段还有一个重要功能:加载UEFI Shell。如果你在启动时按某个热键(通常是F2或Del),就会进入Shell环境。这相当于一个迷你操作系统,可以用来调试、更新固件。
2.4 RT阶段:退居二线的「后勤部」
RT(Runtime Services)阶段是UEFI的最后一个阶段。当操作系统接管后,UEFI的大部分代码会被释放,只保留一小部分「运行时服务」常驻内存。
RT阶段保留的服务:
| 服务名称 | 功能说明 |
|---|---|
| GetVariable / SetVariable | 读写NVRAM变量 |
| GetTime / SetTime | 获取/设置系统时间 |
| ResetSystem | 重启或关机 |
| UpdateCapsule | 固件更新接口 |
RT阶段的代码必须非常精简,因为它要和操作系统共享内存空间。我见过一些固件在RT阶段还保留着调试打印,结果导致系统蓝屏——说白了,RT阶段不是让你玩的地方。
关键点:RT阶段的服务必须遵循UEFI规范中的「Runtime Calling Convention」。这意味着它们不能使用Boot Services(如AllocatePool),也不能依赖中断。我曾经在RT阶段调用了一个DXE阶段的函数,结果系统直接挂死——嗯,这个教训很深刻。
2.5 四个阶段的协作关系
这四个阶段不是孤立的。它们通过「Hand-Off Block」(HOB)传递信息。PEI阶段把内存信息、CPU信息打包成HOB,DXE阶段读取这些HOB来初始化驱动,BDS阶段再根据DXE提供的协议选择启动设备。
我画了一张图,帮你理解这个流程:
从这张图你可以看到,PEI是起点,DXE是主力,BDS是决策者,RT是后勤。每个阶段都有明确的职责边界,不能越俎代庖。
实用技巧:调试启动问题时,我建议你在每个阶段入口加一个串口打印。比如PEI阶段打印「PEI Entry」,DXE阶段打印「DXE Entry」。这样一旦系统卡住,你就能快速定位是哪个阶段出了问题。这招我用了十年,屡试不爽。
好了,UEFI启动流程的全景就讲到这里。这四个阶段是固件工程师的必修课,搞懂了它们,你就能理解为什么有些机器启动快、有些慢,为什么某些外设能识别、某些不能。说白了,UEFI启动就是一场精心编排的交响乐,每个乐器(阶段)都在正确的时间发出正确的声音。
最后提醒:RT阶段的服务是「只读」的——操作系统可以调用它们,但不能修改它们。我曾经见过一个团队在RT阶段尝试分配内存,结果导致系统崩溃。记住:RT阶段不是DXE,别想着搞大动作。
可可精品资料库