3. EDK2 工程结构:目录、描述文件与固件布局
EDK2 是 UEFI 驱动开发的标准参考实现框架。理解其工程结构是编写可移植、可维护驱动的基础。本章将解析 EDK2 的顶层目录布局,并深入说明 .dsc、.fdf、.dec 三种核心元数据文件的作用与协作关系。
3.1 EDK2 顶层目录结构
一个标准的 EDK2 工作空间(通常称为 edk2 或 WORKSPACE)包含以下关键目录与文件:
| 目录/文件 | 作用 |
|---|---|
MdePkg/ | 基础定义包:包含 UEFI 规范定义的数据类型、协议头、PI 规范定义、库类声明。 |
MdeModulePkg/ | 基础模块包:提供通用的 UEFI 驱动、库实例(如磁盘 I/O、控制台、BDS 等)。 |
UefiCpuPkg/ | CPU 架构相关包:包含 CPU 驱动、MP 服务、SMM 基础库。 |
NetworkPkg/ | 网络协议栈:SNP、ARP、IP4/IP6、TCP/UDP、TLS 等。 |
ShellPkg/ | UEFI Shell 实现:命令行解释器及内置命令。 |
OvmfPkg/ | OVMF(开源虚拟机固件):用于 QEMU/KVM 的 UEFI 固件示例。 |
ArmPkg/ | ARM/AArch64 架构支持:包含 ARM 特定库、异常处理、GIC 驱动。 |
BaseTools/ | 构建工具集:包含 GenFw、GenFds、Trim、Ecc 等编译与固件生成工具。 |
Conf/ | 构建配置文件:target.txt、tools_def.txt 定义工具链与目标平台。 |
edk2.bat / edksetup.sh | 环境初始化脚本:设置 WORKSPACE、PACKAGES_PATH 等环境变量。 |
包(Package)概念:EDK2 以
Pkg 为组织单元。每个包是一个逻辑模块集合,包含头文件、库、驱动、协议定义。包名通常以 Pkg 结尾,如 MyDriverPkg。
3.2 三种核心描述文件:.dsc / .fdf / .dec
EDK2 构建系统通过三个描述文件定义“构建什么”、“如何组合”、“依赖什么”。它们分别对应平台级、固件布局级、模块接口级。
3.2.1 .dec 文件 — 包声明(Declaration)
.dec 文件位于每个包的根目录,声明该包对外提供的接口、协议 GUID、PPI GUID、PCD 条目、库类。它是模块间依赖的契约。
# MdePkg/MdePkg.dec 片段
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = MdePkg
PACKAGE_GUID = 1E73767F-8A52-4b2c-BF3E-7B5B3B6F5B2A
PACKAGE_VERSION = 1.08
[Includes]
Include # 公共头文件路径
[LibraryClasses]
UefiLib|Include/Library/UefiLib.h
BaseLib|Include/Library/BaseLib.h
[Guids]
gEfiGlobalVariableGuid = {0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C}}
[PcdsFixedAtBuild]
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF|UINT8|0x00000001
3.2.2 .dsc 文件 — 平台描述(Platform Description)
.dsc 文件定义整个固件映像的构建范围:包含哪些模块、使用哪些库实例、PCD 值、编译选项。它是构建系统的入口。
# OvmfPkg/OvmfPkgX64.dsc 片段
[Defines]
PLATFORM_NAME = Ovmf
PLATFORM_GUID = 5a9e7754-8270-4b2c-bf3e-7b5b3b6f5b2a
PLATFORM_VERSION = 0.1
DSC_SPECIFICATION = 0x00010005
OUTPUT_DIRECTORY = Build/OvmfX64
SUPPORTED_ARCHITECTURES = X64
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
SKUID_IDENTIFIER = DEFAULT
[LibraryClasses]
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
[Components]
MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
OvmfPkg/PlatformDxe/PlatformDxe.inf
# 用户自定义驱动
MyDriverPkg/MyDriver/MyDriver.inf
3.2.3 .fdf 文件 — 固件描述(Flash Description)
.fdf 文件定义固件在 Flash 中的物理布局:FD(Flash Device)区域划分、FVs(Firmware Volumes)、FFS(Firmware File System)文件放置顺序。它决定最终生成的 .fd 二进制映像的二进制布局。
# OvmfPkg/OvmfPkgX64.fdf 片段
[FD.BFV]
BaseAddress = 0x00000000
Size = 0x00200000
ErasePolarity = 1
BlockSize = 0x00001000
NumBlocks = 0x200
[FV.SECFV]
FvAlignment = 16
ERASE_POLARITY = 1
MEMORY_MAPPED = TRUE
STICKY_WRITE = TRUE
LOCK_CAP = TRUE
LOCK_STATUS = TRUE
READ_DISABLED_CAP = FALSE
READ_ENABLED = TRUE
READ_STATUS = TRUE
READ_LOCK_CAP = TRUE
READ_LOCK_STATUS = TRUE
INF UefiCpuPkg/SecCore/SecCore.inf
INF OvmfPkg/Sec/SecMain.inf
[FV.DXEFV]
INF MdeModulePkg/Core/Dxe/DxeMain.inf
INF MyDriverPkg/MyDriver/MyDriver.inf
三文件协作流程:
.dsc 告诉构建系统“编译哪些模块”,.fdf 告诉构建系统“把这些模块的 FFS 文件按什么顺序放入哪个 FV”,.dec 提供模块编译所需的头文件路径、GUID 和 PCD 声明。三者缺一不可。
3.3 三文件关系图
下图展示了 .dsc、.fdf、.dec 在 EDK2 构建流程中的角色与数据流:
3.4 文件作用对比表
| 维度 | .dec | .dsc | .fdf |
|---|---|---|---|
| 所属层级 | 包(Package) | 平台(Platform) | 平台(Platform) |
| 核心职责 | 声明接口与依赖 | 选择模块与库实例 | 定义 Flash 布局 |
| 包含内容 | GUID、PPI、协议、PCD、库类、头文件路径 | 模块 INF 列表、库绑定、PCD 赋值、编译选项 | FD 区域、FV 划分、FFS 文件放置顺序 |
| 是否必须 | 每个包必须有 | 每个平台必须有 | 每个平台必须有 |
| 生成产物 | 无直接产物,供编译时解析 | 控制编译过程 | 最终 .fd 映像 |
| 修改影响 | 影响所有依赖该包的模块 | 影响当前平台所有模块 | 影响固件二进制布局 |
3.5 模块 INF 文件 — 模块描述
除了上述三个平台级文件,每个模块(驱动或库)还包含一个 .inf 文件,用于描述该模块自身的源文件、依赖库、PCD 需求、架构支持等。INF 文件是 .dsc 中 [Components] 引用的基本单元。
# MyDriverPkg/MyDriver/MyDriver.inf 示例
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MyDriver
FILE_GUID = 1B2F3C4D-5E6F-7890-ABCD-EF1234567890
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = MyDriverEntryPoint
[Sources]
MyDriver.c
MyDriver.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiDriverEntryPoint
UefiLib
BaseLib
MemoryAllocationLib
[Protocols]
gEfiSimpleTextOutProtocolGuid
gEfiBlockIoProtocolGuid
[Depex]
TRUE
常见错误:初学者常忘记在
.dsc 的 [LibraryClasses] 中为模块使用的库类绑定具体库实例,导致构建报“未解析的外部符号”。务必确保每个 .inf 中声明的 [LibraryClasses] 在 .dsc 中都有对应的库实例映射。
3.6 构建流程总结
- 解析 .dsc:读取平台定义,确定目标架构、编译类型(DEBUG/RELEASE)、模块列表。
- 解析模块 .inf:对每个模块,读取其源文件、依赖包、库类、协议 GUID。
- 解析 .dec:根据
[Packages]找到对应.dec,解析 GUID、PCD、头文件路径。 - 编译:调用编译器(如 GCC、MSVC、ICC)生成
.efi文件。 - 解析 .fdf:读取 Flash 布局规则,将
.efi文件打包为 FFS,按 FV 组织,最终生成.fd固件映像。