3、BIOS/UEFI固件架构:BIOS与UEFI的区别,UEFI的六个阶段概述

好,我们进入第三章。这一章聊的是固件架构,说白了就是服务器上电后,第一个跑起来的软件长什么样。

我刚开始做芯片验证那会儿,总觉得固件就是个“黑盒子”——按一下电源键,屏幕亮了,系统起来了。至于中间发生了什么,完全没概念。直到有一次调试一个内存训练失败的问题,我才被迫把UEFI的启动流程从头到尾啃了一遍。嗯,从那以后,我再也不敢小看固件了。

3.1 BIOS vs UEFI:到底差在哪?

先说说传统BIOS。BIOS的全称是Basic Input/Output System,它诞生于1980年代。说实话,它的设计思路非常“古老”——16位实模式,1MB地址空间限制,用中断向量表做I/O。你想想看,现在的服务器动辄几百GB内存、几十个核心,BIOS这套东西根本跑不动。

UEFI(统一可扩展固件接口)就是来取代BIOS的。它不是BIOS的升级版,而是完全重写的。我个人习惯把UEFI理解成一个“微型操作系统”——它有驱动模型、有协议栈、有内存管理,甚至还能跑网络。

对比项 传统BIOS UEFI
处理器模式 16位实模式 32/64位保护模式+长模式
地址空间 1MB限制 无限制(取决于CPU)
磁盘分区 MBR(最大2TB) GPT(最大9.4ZB)
驱动模型 无,依赖Option ROM UEFI Driver Model
启动速度 慢(逐项检测) 快(并行初始化)
安全性 Secure Boot

核心区别一句话:BIOS是固件,UEFI是固件+操作系统接口规范。UEFI定义了固件和操作系统之间的标准接口,而BIOS没有。

3.2 UEFI的六个阶段:从按下电源键到操作系统

UEFI把启动过程分成了六个阶段。每个阶段都有明确的任务和边界。我在项目中遇到过不少问题,最后发现都是某个阶段的初始化顺序搞错了。所以,理解这六个阶段非常关键。

3.2.1 SEC阶段(安全验证)

SEC是Security的缩写。这是CPU复位后执行的第一段代码。它的任务很简单:验证下一个阶段(PEI)的代码是否可信。

为什么会需要这个?因为如果PEI阶段的代码被篡改了,整个系统就不可信了。SEC阶段通常放在CPU内部的缓存(Cache as RAM)里运行,因为这时候内存还没初始化。

避坑指南:我曾经遇到过一个案例,SEC阶段的签名验证算法实现有bug,导致某些合法的固件更新被拒绝。排查了整整两天才发现是哈希计算的长度参数传错了。嗯,这种底层代码,一个bit都不能错。

3.2.2 PEI阶段(EFI前初始化)

PEI的全称是Pre-EFI Initialization。这个阶段的主要工作是:初始化CPU、芯片组、内存控制器,然后检测并初始化内存。

PEI阶段的代码非常精简,因为它运行在“临时内存”里——通常是CPU缓存模拟的内存(Cache as RAM,简称CAR)。等真正的DRAM初始化完成后,PEI会把控制权交给DXE阶段。

PEI的核心数据结构叫HOB(Hand-Off Block),它记录了PEI阶段发现的所有硬件信息。DXE阶段会读取HOB来继续初始化。

// PEI阶段的一个典型HOB结构
typedef struct {
    UINT16    HobType;      // HOB类型
    UINT16    HobLength;    // HOB长度
    UINT32    Reserved;     // 保留
} EFI_HOB_GENERIC_HEADER;

3.2.3 DXE阶段(驱动执行环境)

DXE是Driver Execution Environment的缩写。这是UEFI最核心的阶段。说白了,DXE就是一个驱动框架——它加载各种硬件驱动,初始化PCIe设备、存储控制器、网络接口等。

DXE阶段运行在真正的内存里,可以访问全部地址空间。它使用一种叫“DXE Dispatcher”的调度器,按依赖关系依次加载驱动。比如,PCIe根桥驱动必须先加载,然后才能加载PCIe设备驱动。

关键点:DXE阶段会构建UEFI的系统表(System Table)和启动服务表(Boot Services Table)。这些表是操作系统启动时获取硬件信息的标准接口。

3.2.4 BDS阶段(启动设备选择)

BDS是Boot Device Selection的缩写。这个阶段的任务是:决定从哪个设备启动操作系统。

BDS会遍历所有可启动设备——硬盘、SSD、USB、网络(PXE)等。它按照用户配置的启动顺序,依次尝试加载启动项。如果第一个设备启动失败,就尝试下一个。

我记得有一次调试一个服务器,它总是从网络启动而不是本地硬盘。查了半天,发现是BDS阶段的启动顺序配置被重置了。嗯,这种问题通常和NVRAM(非易失性内存)的校验和错误有关。

3.2.5 TSL阶段(临时系统加载)

TSL是Transient System Load的缩写。这个阶段很短,它的任务就是:加载操作系统的启动加载器(Boot Loader),比如GRUB、Windows Boot Manager等。

TSL阶段会调用UEFI的启动服务(Boot Services),比如ExitBootServices()。这个调用很关键——一旦调用了ExitBootServices,UEFI就把硬件的控制权完全交给了操作系统,UEFI自己退居二线,只提供运行时服务(Runtime Services)。

注意:ExitBootServices()调用之后,UEFI的启动服务就不可用了。如果你在操作系统里还想调用UEFI的某些功能,只能通过运行时服务接口。我见过有人写内核驱动时忘了这个限制,结果系统直接挂掉。

3.2.6 RT阶段(运行时)

RT是Runtime的缩写。这是UEFI的最后一个阶段。操作系统已经接管了硬件,UEFI只提供一些基本的运行时服务,比如:

  • 设置系统时间(GetTime/SetTime)
  • 读写UEFI变量(GetVariable/SetVariable)
  • 重启/关机(ResetSystem)

RT阶段的代码会常驻在内存中,操作系统可以通过UEFI的运行时服务表来调用它们。这些服务通常用SMI(系统管理中断)或虚拟化技术来实现隔离。

3.3 六个阶段的时间分布

在实际项目中,这六个阶段的时间占比大概是这样:

阶段 典型耗时 说明
SEC < 10ms 纯软件验证,很快
PEI 100ms - 500ms 内存训练是瓶颈
DXE 500ms - 2s 驱动加载和初始化
BDS < 100ms 遍历启动设备
TSL < 50ms 加载启动加载器
RT 持续运行 操作系统运行期间

优化建议:如果你发现服务器启动慢,90%的瓶颈在PEI阶段的内存训练和DXE阶段的驱动加载。我曾经通过优化内存训练参数,把一台服务器的启动时间从45秒降到了12秒。嗯,这就是为什么理解这六个阶段很重要——你知道该从哪里下手。

3.4 小结

这一章我们聊了BIOS和UEFI的区别,以及UEFI的六个阶段。说白了,UEFI就是一套标准化的启动框架,把“从按下电源键到操作系统启动”这个过程拆成了六个清晰的阶段。每个阶段各司其职,环环相扣。

下一章,我们会深入PEI阶段,看看内存训练到底是怎么做的。到时候我会分享一个我在调试DDR5内存时遇到的“玄学”问题——嗯,保证让你大开眼界。