2. 固件与BIOS基础

在开始写第一行UEFI代码之前,必须先把“固件”“BIOS”“UEFI”这三个词的关系理清楚。很多初学者会把它们当成同义词,结果在阅读UEFI规范或调试启动问题时频频踩坑。本节从固件的本质定义出发,梳理BIOS的历史演进,对比Legacy与UEFI的差异,并给出UEFI规范体系与产业生态的整体地图。

一、固件是什么:硬件与操作系统之间的“第一段软件”

固件(Firmware)是存储在非易失性存储器中、与特定硬件平台紧密绑定、负责初始化硬件并把控制权交给上层软件的软件。它介于硬件与操作系统之间,是系统上电后执行的第一段代码。与普通应用软件相比,固件有三个显著特征:

  • 驻留性:固化在SPI Flash、ROM等非易失介质中,掉电不丢失。
  • 平台相关性:与芯片组、主板、外设强绑定,换平台往往需要重新适配。
  • 启动关键路径:固件出错,系统可能连“黑屏”都无法进入,调试手段有限。

在PC体系中,固件最典型的形态就是BIOS/UEFI固件。它承担上电自检(POST)、内存与芯片组初始化、外设枚举、启动设备选择、向操作系统传递硬件描述信息等职责。可以把固件理解为“硬件的操作系统”与“操作系统的引导者”双重角色。

核心认知:固件是平台的一部分,不是可随意替换的应用。UEFI固件开发本质上是“在受限资源与严格时序下,把硬件安全、可预测地交给OS”。

二、BIOS的历史演进:从ROM到UEFI

BIOS(Basic Input/Output System)最早出现在IBM PC时代,其设计目标是提供一套稳定的、面向中断调用的硬件抽象。它的演进大致可分为四个阶段:

  1. ROM BIOS阶段:代码固化在ROM中,通过INT 10h、INT 13h、INT 16h等中断提供显示、磁盘、键盘服务,容量通常只有64KB左右。
  2. Flash BIOS阶段:ROM被可擦写Flash取代,支持在线升级,但仍沿用16位实模式与中断调用模型。
  3. EFI阶段:Intel在1990年代末提出EFI 1.10,引入32/64位保护模式、模块化驱动模型与可扩展接口,突破传统BIOS的容量与寻址限制。
  4. UEFI阶段:2005年UEFI论坛成立,EFI 1.10演化为UEFI 2.x规范,成为当前PC、服务器、嵌入式平台的主流固件接口标准。

需要强调的是:UEFI并不是“另一种BIOS”,而是BIOS的现代替代方案。它保留了“上电初始化并引导OS”的职责,但彻底改变了实现方式与接口模型。

三、Legacy与UEFI对比:不只是“新老”之分

Legacy BIOS与UEFI在启动模型、寻址能力、驱动方式、安全机制上存在本质差异。下表从工程视角给出关键对比:

对比维度 Legacy BIOS UEFI
运行模式 16位实模式 32/64位保护模式
寻址能力 1MB以内,磁盘受INT 13h限制 平坦寻址,支持大容量磁盘与64位地址
启动方式 读取MBR,跳转执行引导扇区 加载FAT分区中的EFI应用(.efi)
驱动模型 中断调用,无标准驱动接口 UEFI Driver Model,支持协议绑定
分区表 MBR(最大2TB) GPT(支持超大容量与多分区)
安全机制 基本无验证 Secure Boot、签名验证、可信启动
扩展性 受容量与中断号限制 模块化、可加载驱动、可扩展协议

从调试角度看,Legacy问题常表现为“MBR损坏、引导扇区被覆盖”,而UEFI问题更多集中在“EFI分区缺失、启动项NVRAM变量错误、Secure Boot签名失败”。理解这些差异,能显著缩短排障时间。

四、UEFI规范体系与产业生态

UEFI不是单一文档,而是一套由UEFI论坛维护的规范族。核心包括:

  • UEFI Specification:定义启动服务、运行时服务、协议、驱动模型等核心接口。
  • PI Specification(Platform Initialization):定义SEC、PEI、DXE、BDS、Runtime等启动阶段与模块间接口。
  • ACPI、SMBIOS、PCIe等配套规范:描述硬件配置与电源管理信息,供OS使用。

产业生态方面,芯片厂商提供参考代码,IBV/ODM进行平台适配,固件团队基于EDK II等开源框架开发。EDK II是当前最主流的UEFI固件开发框架,提供包管理、模块构建、协议实现等基础设施。一个典型的EDK II模块构建命令如下:

# 设置开发环境
edksetup.sh
# 编译指定平台
build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc
# 生成固件镜像
ls Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd
学习建议:先建立“规范—框架—平台”三层认知。规范回答“接口长什么样”,EDK II回答“代码怎么组织”,平台包回答“具体硬件怎么初始化”。三者缺一不可。

五、常见误区与复盘

在实际项目中,以下误区最容易导致返工:

  • 误区一:把UEFI当成Legacy的简单升级。实际上启动模型、驱动模型、内存模型都变了,Legacy经验不能直接套用。
  • 误区二:忽视PI阶段划分。SEC、PEI、DXE、BDS各阶段职责不同,把代码放错阶段会导致时序问题。
  • 误区三:忽略NVRAM启动项。UEFI启动依赖BootOrder与Boot####变量,变量损坏会直接导致无法引导。
  • 误区四:调试只靠打印。UEFI早期阶段串口可能未初始化,需结合JTAG、POST Code、固件日志等多种手段。

复盘建议:每接手一个新平台,先画出该平台的启动阶段图与关键数据结构,再对照PI规范确认各阶段入口与退出条件。这样在遇到“卡在DXE”“BDS找不到启动项”等问题时,能快速定位到具体阶段与模块。

UEFI 固件启动阶段与规范体系 SEC 安全验证/临时RAM PEI 内存初始化 DXE 驱动调度/协议 BDS 启动项选择 TSL/RT 移交OS/运行时 UEFI 规范体系 UEFI Specification 启动服务 / 运行时服务 协议 / 驱动模型 PI Specification SEC / PEI / DXE / BDS 阶段接口与模块调度 配套规范 ACPI / SMBIOS / PCIe 硬件描述与电源管理 产业生态与开发框架 芯片厂商 参考代码 / 芯片初始化 IBV / ODM 平台适配 / 产品化 EDK II 开源开发框架 固件团队 开发 / 调试 / 维护

总结来看,固件是平台的第一段软件,BIOS是其历史形态,UEFI是当前主流规范。掌握SEC→PEI→DXE→BDS→TSL/RT的启动阶段划分,理解UEFI、PI与配套规范的分工,再结合EDK II框架与产业分工,就具备了进入UEFI固件开发实战的基础认知。