2. 固件与BIOS基础
在开始写第一行UEFI代码之前,必须先把“固件”“BIOS”“UEFI”这三个词的关系理清楚。很多初学者会把它们当成同义词,结果在阅读UEFI规范或调试启动问题时频频踩坑。本节从固件的本质定义出发,梳理BIOS的历史演进,对比Legacy与UEFI的差异,并给出UEFI规范体系与产业生态的整体地图。
一、固件是什么:硬件与操作系统之间的“第一段软件”
固件(Firmware)是存储在非易失性存储器中、与特定硬件平台紧密绑定、负责初始化硬件并把控制权交给上层软件的软件。它介于硬件与操作系统之间,是系统上电后执行的第一段代码。与普通应用软件相比,固件有三个显著特征:
- 驻留性:固化在SPI Flash、ROM等非易失介质中,掉电不丢失。
- 平台相关性:与芯片组、主板、外设强绑定,换平台往往需要重新适配。
- 启动关键路径:固件出错,系统可能连“黑屏”都无法进入,调试手段有限。
在PC体系中,固件最典型的形态就是BIOS/UEFI固件。它承担上电自检(POST)、内存与芯片组初始化、外设枚举、启动设备选择、向操作系统传递硬件描述信息等职责。可以把固件理解为“硬件的操作系统”与“操作系统的引导者”双重角色。
二、BIOS的历史演进:从ROM到UEFI
BIOS(Basic Input/Output System)最早出现在IBM PC时代,其设计目标是提供一套稳定的、面向中断调用的硬件抽象。它的演进大致可分为四个阶段:
- ROM BIOS阶段:代码固化在ROM中,通过INT 10h、INT 13h、INT 16h等中断提供显示、磁盘、键盘服务,容量通常只有64KB左右。
- Flash BIOS阶段:ROM被可擦写Flash取代,支持在线升级,但仍沿用16位实模式与中断调用模型。
- EFI阶段:Intel在1990年代末提出EFI 1.10,引入32/64位保护模式、模块化驱动模型与可扩展接口,突破传统BIOS的容量与寻址限制。
- 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
五、常见误区与复盘
在实际项目中,以下误区最容易导致返工:
- 误区一:把UEFI当成Legacy的简单升级。实际上启动模型、驱动模型、内存模型都变了,Legacy经验不能直接套用。
- 误区二:忽视PI阶段划分。SEC、PEI、DXE、BDS各阶段职责不同,把代码放错阶段会导致时序问题。
- 误区三:忽略NVRAM启动项。UEFI启动依赖BootOrder与Boot####变量,变量损坏会直接导致无法引导。
- 误区四:调试只靠打印。UEFI早期阶段串口可能未初始化,需结合JTAG、POST Code、固件日志等多种手段。
复盘建议:每接手一个新平台,先画出该平台的启动阶段图与关键数据结构,再对照PI规范确认各阶段入口与退出条件。这样在遇到“卡在DXE”“BDS找不到启动项”等问题时,能快速定位到具体阶段与模块。
总结来看,固件是平台的第一段软件,BIOS是其历史形态,UEFI是当前主流规范。掌握SEC→PEI→DXE→BDS→TSL/RT的启动阶段划分,理解UEFI、PI与配套规范的分工,再结合EDK II框架与产业分工,就具备了进入UEFI固件开发实战的基础认知。