3. EDK II概述
EDK II(EFI Development Kit II)是UEFI固件开发领域最主流的开源框架,也是Intel主导并持续维护的固件工程基础设施。理解EDK II的历史脉络、架构分层、包与模块的组织方式,以及如何搭建可编译的开发环境,是进入平台固件开发的第一步。
3.1 从EFI到EDK II:项目演进
EDK II并非凭空出现,它经历了从EFI Framework到EDK,再到EDK II的演进过程。早期EFI 1.10规范配套的Framework代码结构松散,构建系统依赖大量手工配置,跨平台复用困难。2006年前后,Intel推出EDK(EFI Development Kit),首次尝试用统一的包描述和构建工具组织固件代码。随着UEFI 2.x规范逐步取代EFI,EDK II在2007年后成为主力项目,其核心变化包括:引入包(Package)作为代码组织单元,引入模块(Module)作为编译单元,采用DEC/INF/DSC/FDF四类描述文件驱动构建,并支持多种编译器与目标架构。
EDK II的版本迭代与UEFI规范演进紧密相关。UEFI 2.0到2.10的协议、服务、启动管理变化,都会反映到EDK II的MdePkg、MdeModulePkg等基础包中。对于平台开发者而言,EDK II既是规范落地的参考实现,也是实际产品固件的开发底座。
3.2 架构组成:分层与包结构
EDK II的架构可以概括为“规范层—基础库层—模块层—平台层”的纵向分层,以及“包”作为横向组织边界。最底层是UEFI/PI规范定义的服务与协议;其上是MdePkg提供的基础库和协议头文件;再往上是MdeModulePkg、UefiCpuPkg、PcAtChipsetPkg等通用模块包;最上层是具体平台包,如OvmfPkg、MinPlatformPkg或厂商自定义平台包。
每个包通常包含:.dec包声明文件、Include/头文件目录、Library/库实例、Drivers/驱动模块、Application/应用模块,以及可选的.dsc和.fdf。包与包之间通过Packages路径和LibraryClasses建立依赖关系,构建系统据此解析依赖并生成固件镜像。
3.3 包与模块:EDK II的组织核心
包(Package)是EDK II中代码复用和依赖管理的基本单位。一个包通过.dec文件声明自身名称、GUID、版本、包含的头文件目录、库类、协议和PCD(Platform Configuration Database)等。其他包若要使用该包中的库或协议,只需在自身.dsc或.inf中声明包路径即可。
模块(Module)是可独立编译和链接的代码单元,通常对应一个驱动、一个应用或一个库实例。模块由.inf文件描述,其中包含模块类型(如DXE_DRIVER、UEFI_APPLICATION、BASE)、源文件列表、库类依赖、协议依赖、PCD使用等。模块不直接引用其他模块的源文件,而是通过库类和协议接口进行解耦。
| 描述文件 | 作用 | 典型位置 |
|---|---|---|
.dec |
声明包内容:头文件、库类、协议、PCD、GUID | 包根目录 |
.inf |
描述单个模块:类型、源文件、库依赖、协议依赖 | 模块目录 |
.dsc |
平台构建描述:选择包、库实例、模块、PCD值 | 平台包根目录 |
.fdf |
固件镜像布局:FD、FV、FFS、CAPSULE等 | 平台包根目录 |
核心关系:包提供“可被依赖的接口与实现”,模块提供“可被编译的代码单元”,DSC负责“平台级选择与配置”,FDF负责“镜像级布局与封装”。四者协同,构成EDK II从源码到固件的完整构建链路。
3.4 开发环境搭建:从零到可编译
EDK II官方推荐在Linux环境下使用GCC工具链,在Windows环境下使用VS工具链。以下以Ubuntu 22.04 + GCC为例,给出最小可编译环境的搭建步骤。
# 1. 安装依赖
sudo apt update
sudo apt install -y build-essential uuid-dev nasm acpica-tools python3 python3-pip git
# 2. 获取EDK II源码
git clone https://github.com/tianocore/edk2.git
cd edk2
git submodule update --init
# 3. 初始化构建环境
source edksetup.sh
# 4. 配置Conf/target.txt
# ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
# TARGET_ARCH = X64
# TOOL_CHAIN_TAG = GCC5
# 5. 编译BaseTools
make -C BaseTools
# 6. 构建平台固件
build
构建成功后,固件镜像通常位于Build/OvmfX64/DEBUG_GCC5/FV/目录下,其中OVMF.fd可直接用于QEMU启动验证。若使用QEMU,可执行:
qemu-system-x86_64 -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd \
-drive format=raw,file=fat:rw:./esp -nographic
环境搭建要点:BaseTools必须先编译成功,否则build命令无法运行;edksetup.sh负责设置WORKSPACE和PACKAGES_PATH;若使用多个包路径,需在Conf/target.txt或环境变量中正确配置。
3.5 常见误区与复盘
- 误区一:把包当成目录。包不仅是目录,更是带有
.dec声明的依赖单元。缺少.dec或声明不完整,会导致构建系统无法解析依赖。 - 误区二:模块直接include其他模块的源文件。这破坏了EDK II的库类解耦机制,正确做法是通过库类接口或协议调用。
- 误区三:忽略DSC中的库实例映射。同一个库类在不同平台可以映射到不同实现,若未在DSC中正确指定,链接阶段会报未解析符号。
- 误区四:环境变量未持久化。
edksetup.sh只在当前shell生效,重新打开终端后需重新执行,或将其写入~/.bashrc。
复盘来看,EDK II的学习曲线主要集中在对“包—模块—DSC—FDF”四层描述文件的理解上。一旦掌握这套组织逻辑,后续阅读OvmfPkg、MinPlatformPkg等平台代码时,就能快速定位模块入口、库依赖和镜像布局,从而高效开展平台固件开发。