EDK II模块开发与集成 - 第1节

1.1 UEFI 与 PI 规范简介

UEFI(统一可扩展固件接口)和 PI(平台初始化)规范是 EDK II 开发的两大基石。UEFI 定义了操作系统与固件之间的接口,而 PI 则规范了固件内部各模块的协作方式。

UEFI 规范核心概念

  • 启动管理器:负责选择启动设备、管理启动顺序,是 UEFI 固件的入口点。
  • 运行时服务:在操作系统接管后仍可调用的服务,如变量存储、时间管理。
  • 启动服务:仅在启动阶段可用的服务,包括内存分配、协议安装、事件处理。
  • 协议:UEFI 模块间通信的接口,每个协议由 GUID 唯一标识。
  • 映像加载:支持 PE32+ 格式的驱动和应用加载。

PI 规范核心概念

PI 规范将固件初始化过程划分为七个阶段,每个阶段有明确的职责和接口:

阶段 全称 主要职责
SEC 安全验证 CPU 初始复位、缓存作为临时 RAM、安全验证入口
PEI EFI 预初始化 检测内存、发现早期硬件、传递 HOB 列表
DXE 驱动执行环境 加载驱动、枚举设备、分配资源、产生 ACPI/SMBIOS 表
BDS 启动设备选择 显示启动菜单、执行启动策略、加载操作系统引导器
TSL 短暂系统加载 操作系统引导器运行阶段,准备退出启动服务
RT 运行时 操作系统已接管,仅保留运行时服务
AL 灾难恢复 系统崩溃或固件更新失败时的恢复处理
关键理解:UEFI 规范面向操作系统与固件的接口,PI 规范面向固件内部模块的协作。EDK II 同时实现了这两套规范,开发者编写的模块通常运行在 PEI 或 DXE 阶段。
UEFI 与 PI 规范关系图 UEFI 规范 操作系统 ↔ 固件接口 启动管理器 · 协议 · 服务 PI 规范 固件内部模块协作 SEC → PEI → DXE → BDS → TSL → RT → AL EDK II 实现 同时实现 UEFI + PI 规范的开源框架 开发者编写的模块(PEIM/DXE Driver)运行在 PI 定义的阶段中,通过 UEFI 协议与操作系统交互

1.2 EDK II 项目历史与社区

发展历程

时间 里程碑 说明
1999 Intel 启动 EFI 1.0 Intel 提出可扩展固件接口概念,替代传统 BIOS
2005 UEFI 论坛成立 统一 EFI 规范管理,发布 UEFI 2.0
2007 EDK 开源 Intel 开源 EFI 开发套件(EDK)
2010 EDK II 发布 重构为模块化架构,引入 .dsc/.fdf/.inf 构建系统
2017 tianocore 成为核心 EDK II 主仓库迁移至 tianocore/edk2 GitHub 组织
至今 活跃社区维护 每月稳定标签发布,支持 ARM/RISC-V 等新架构

社区生态

  • tianocore 组织:GitHub 上的核心仓库,包含 edk2、edk2-platforms、edk2-non-osi。
  • 邮件列表:edk2-devel 是主要技术讨论渠道,所有补丁和 RFC 在此审查。
  • Bugzilla:缺陷跟踪和功能请求管理平台。
  • 年度 UEFI 研讨会:社区成员分享固件开发经验和最新进展。
  • 企业贡献者:Intel、AMD、ARM、Microsoft、Google 等持续贡献代码。
社区参与建议:新手可以从修复 Bugzilla 中的低优先级缺陷开始,或为现有模块添加单元测试。提交补丁前务必阅读 EDK II 补丁提交规范。

1.3 EDK II 源码获取与目录结构

获取源码

推荐使用 Git 克隆 tianocore 官方仓库:

# 克隆核心 EDK II 仓库
git clone https://github.com/tianocore/edk2.git

# 初始化子模块(包含加密库、编译工具等)
cd edk2
git submodule update --init --recursive

# 克隆平台代码(可选,用于特定硬件)
git clone https://github.com/tianocore/edk2-platforms.git

顶层目录结构

目录/文件 用途
MdePkg/ 核心协议定义、数据类型、基础库(UEFI/PI 规范头文件)
MdeModulePkg/ 通用模块实现:内存管理、事件、协议数据库、启动管理器
UefiCpuPkg/ CPU 架构相关模块:MP 服务、异常处理、SMM
PcAtChipsetPkg/ 传统 PC 芯片组支持:8259 PIC、8254 定时器
NetworkPkg/ 网络协议栈:TCP/IP、HTTP Boot、iSCSI
ShellPkg/ UEFI Shell 实现及内置命令
SecurityPkg/ 安全功能:TPM、Secure Boot、Measured Boot
BaseTools/ 编译工具链:GenFw、GenFds、Ecc 代码检查
Conf/ 构建配置文件:target.txt、tools_def.txt
edk2.nsh Windows 环境变量设置脚本
edk2.sh Linux/macOS 环境变量设置脚本

模块包内部结构

每个 Package(如 MdeModulePkg)内部遵循统一布局:

MdeModulePkg/
├── MdeModulePkg.dsc          # 包级构建描述文件
├── MdeModulePkg.dec          # 包声明文件(GUID、PPIs、协议、PCD)
├── Include/                  # 公共头文件
│   ├── Protocol/             # 协议定义
│   ├── Ppi/                  # PEI PPIs 定义
│   ├── Guid/                 # GUID 定义
│   └── Library/              # 库类头文件
├── Library/                  # 库实例实现
├── Universal/                # 通用模块(PEIM/DXE Driver)
├── Bus/                      # 总线驱动
├── Application/              # UEFI 应用
└── Test/                     # 单元测试和 SCT 测试
注意:不要直接修改 MdePkg 和 MdeModulePkg 中的核心文件。自定义模块应放在独立的 Package 中,通过 .dsc 文件引用标准包。这能保证未来升级 EDK II 版本时不会产生冲突。
EDK II 源码目录结构 edk2/ (根目录) MdePkg MdeModulePkg UefiCpuPkg NetworkPkg BaseTools Include/ Library/ Universal/ Bus/ 关键构建文件 .dsc — 包构建描述,定义模块列表和库映射 .dec — 包声明,导出 GUID、PPI、协议、PCD .inf — 模块信息文件,描述源文件、依赖库、编译选项

构建系统核心文件

EDK II 使用三文件构建模型,每个模块必须包含以下文件:

文件类型 扩展名 作用 示例
包声明文件 .dec 声明包内所有 GUID、协议、PPI、PCD 和库类 MdePkg/MdePkg.dec
包构建描述 .dsc 定义包内模块列表、库实例映射、PCD 默认值 MdeModulePkg/MdeModulePkg.dsc
模块信息文件 .inf 描述单个模块的源文件、依赖库、编译选项、入口点 MdeModulePkg/Universal/DiskIoDxe/DiskIoDxe.inf
固件卷描述 .fdf 定义固件映像的布局、FVs、FD 区域 OvmfPkg/OvmfPkgX64.fdf
快速上手:使用 edk2/BaseTools/Source/C/bin/Build 工具编译。首次编译建议从 OvmfPkg 开始,它支持 QEMU 模拟运行,无需真实硬件。