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 在系统启动链路中的位置 硬件上电 CPU / DRAM / 总线 UEFI 固件 SEC→PEI→DXE→BDS OS Loader GRUB / BootMgr 操作系统内核 Linux / Windows Boot Services 内存 / 协议 / 事件 镜像加载 / 退出 Runtime Services 变量 / 时间 / 复位 OS 运行后仍可用 常见术语: UEFI 规范 · PI 规范 · ACPI · SMBIOS · NVRAM · 启动项 · 协议 · 句柄 · 驱动 · 镜像 · 变量 · 可信根

四、常见术语与规范体系

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 驱动开发时,你会反复回到这些基础概念:协议、句柄、阶段、启动项、变量、服务边界。只有把“启动流程”和“规范体系”放在同一张图上理解,才能在真实项目中定位问题、设计驱动、调试启动链路。