2. 固件与启动基础
在讨论 UEFI 之前,必须先建立“固件”这一层认知。固件是介于硬件与操作系统之间的底层软件,通常固化在主板上的 SPI Flash 中,负责在上电后完成最基础的硬件初始化,并把控制权交给操作系统。没有固件,CPU 即使通电也无法知道内存、磁盘、显示设备在哪里,更无法加载操作系统。UEFI 正是现代固件最主流的一种实现规范。
一、固件是什么:从“不可见”到“启动第一棒”
固件(Firmware)可以理解为“写死在硬件里的软件”。它不像普通应用那样安装在硬盘上,而是存放在主板上的非易失存储芯片中。上电后,CPU 从固定地址取第一条指令,这条指令就来自固件。固件的主要职责包括:
- 建立 CPU 运行环境,如设置栈、初始化关键寄存器;
- 初始化内存控制器,让 DRAM 可用;
- 枚举总线与设备,如 PCIe、USB、SATA、NVMe;
- 提供启动设备选择与操作系统加载能力;
- 向操作系统传递硬件描述信息,如 ACPI 表、SMBIOS、设备树等。
传统 BIOS 与 UEFI 都属于固件范畴,但二者在架构、接口和启动模型上有本质差异。传统 BIOS 以 16 位实模式为主,依赖中断向量和固定入口;UEFI 则以 32/64 位保护模式运行,采用协议、句柄、事件等面向对象式机制,具备更强的扩展性和安全性。
二、启动流程概览:从按下电源到 OS 接管
典型 UEFI 启动流程可以概括为“SEC → PEI → DXE → BDS → TSL → RT”六个阶段。每个阶段都有明确目标,前一阶段为后一阶段准备运行环境。
| 阶段 | 全称 | 核心任务 |
|---|---|---|
| SEC | Security Phase | 上电入口、临时内存、建立可信根 |
| PEI | Pre-EFI Initialization | 内存初始化、早期硬件准备 |
| DXE | Driver Execution Environment | 加载驱动、枚举设备、构建协议数据库 |
| BDS | Boot Device Selection | 选择启动项、加载 OS Loader |
| TSL | Transient System Load | OS Loader 运行、调用 Boot Services |
| RT | Runtime | OS 接管,仅保留 Runtime Services |
其中 DXE 是驱动开发最常接触的阶段。大部分 UEFI 驱动以 DXE Driver 形式存在,通过协议匹配设备并完成初始化。BDS 阶段则决定“从哪个设备启动”,它会读取 NVRAM 中的启动项,按优先级尝试加载 EFI 应用或 OS Loader。
关键理解:UEFI 启动不是“一条直线”,而是“阶段推进 + 协议发现 + 启动项选择”的组合过程。驱动在 DXE 阶段注册协议,BDS 阶段再根据启动策略选择入口。
三、UEFI 在系统启动中的位置
从整机视角看,启动链路可以表示为:硬件上电 → 固件(UEFI)→ 引导加载程序(GRUB、Windows Boot Manager)→ 操作系统内核 → 用户空间。UEFI 位于硬件与 OS 之间,是“启动第一棒”和“硬件抽象第一层”。
UEFI 向 OS 提供两类服务:Boot Services 和 Runtime Services。Boot Services 在 OS 接管前可用,包括内存分配、协议访问、事件、镜像加载等;Runtime Services 在 OS 运行后仍可调用,如变量读写、时间服务、复位等。理解这两类服务的边界,是后续驱动开发与排障的基础。
四、常见术语与规范体系
UEFI 不是单一文档,而是一套规范体系。最核心的是 UEFI 规范本身,它定义固件与 OS 之间的接口;与之配套的是 PI(Platform Initialization)规范,定义固件内部各阶段的行为;此外还有 ACPI、SMBIOS、Device Tree 等硬件描述规范。开发中常见的术语包括:
- Protocol:UEFI 中的接口抽象,类似“服务契约”,驱动通过安装协议对外提供服务;
- Handle:协议与设备的关联对象,一个 Handle 可挂载多个 Protocol;
- NVRAM:非易失存储,保存启动项、启动顺序、安全变量等;
- Boot Option:启动项,包含设备路径和加载选项;
- Boot Manager:BDS 阶段负责选择启动项的组件;
- Runtime Variable:OS 运行期间仍可读写的 UEFI 变量。
学习建议:把“规范”和“实现”分开看。UEFI 规范定义接口,EDK II 是常见开源实现,不同芯片厂商还会提供自己的固件代码。理解规范,才能在不同平台上迁移知识。
五、案例与误区:为什么“能进系统”不等于“启动没问题”
一个常见场景是:机器能正常进入 Windows 或 Linux,但 UEFI 驱动开发时却频繁失败。原因往往在于启动阶段被忽略。例如,某 PCIe 设备在 DXE 阶段未被正确枚举,OS 仍可能通过自身驱动识别它,但 UEFI 环境下却无法访问。这说明“OS 能识别”与“固件已初始化”是两件事。
另一个误区是把 UEFI 当成“更快的 BIOS”。实际上,UEFI 的核心变化是接口模型和启动策略:它支持图形化界面、网络启动、安全启动、驱动模块化,也支持从 GPT 分区加载 OS。速度提升只是结果之一,不是本质。
排障提示:如果启动项丢失,优先检查 NVRAM 中的 BootOrder 与 Boot#### 变量;如果驱动未加载,检查 DXE 阶段是否安装了对应 Protocol;如果 OS 无法接管,检查 Boot Services 退出与 Runtime Services 映射是否正常。
六、小结:建立“固件—启动—OS”三层视角
本节的核心是建立三层视角:固件负责硬件初始化与启动服务,UEFI 是固件的一种现代规范实现,OS 通过 Boot Services 和 Runtime Services 与固件交互。后续学习 UEFI 驱动开发时,你会反复回到这些基础概念:协议、句柄、阶段、启动项、变量、服务边界。只有把“启动流程”和“规范体系”放在同一张图上理解,才能在真实项目中定位问题、设计驱动、调试启动链路。