3、EDK2工程结构:目录、.dsc、.fdf、.dec 文件
好,咱们正式开始动手之前,得先把 EDK2 的「家底」摸清楚。
很多新手拿到 EDK2 源码,第一反应就是懵——这目录怎么这么多?这些 .dsc、.fdf、.dec 文件到底是干嘛的?
别急,我当年第一次看 EDK2 的时候,也是对着屏幕发呆了半小时。后来踩了不少坑,才慢慢理清楚。今天我就把这些经验掰开揉碎了讲给你听。
3.1 EDK2 的目录结构
EDK2 的源码目录,说白了就是一个大仓库。里面装着各种模块、库、平台配置、工具链脚本等等。
我个人习惯把 EDK2 的顶层目录分成三大块:
- 核心库和驱动——MdePkg、MdeModulePkg 这些,是 UEFI 的「骨架」。
- 平台相关代码——比如 OvmfPkg(虚拟机)、EmulatorPkg(模拟器),还有各种芯片厂商的包。
- 工具和脚本——BaseTools、edksetup.sh 这些,用来编译和配置。
咱们挑几个最常用的目录说说:
| 目录名 | 作用 |
|---|---|
| MdePkg | UEFI 规范定义的基础头文件、数据类型、协议接口。说白了就是「字典」。 |
| MdeModulePkg | 通用的 UEFI 驱动和模块,比如文件系统、网络协议栈。 |
| OvmfPkg | 专门给 QEMU/KVM 虚拟机用的 UEFI 固件。我经常用它做实验。 |
| BaseTools | 编译工具链,把 .c 文件变成 .efi 文件的关键。 |
| Conf | 全局配置文件,比如 tools_def.txt 定义了编译器路径。 |
3.2 .dsc 文件——平台描述文件
.dsc 文件,全称是 Platform Description File。
你可以把它理解成「菜单」。这个平台要编译哪些模块?用哪个编译器?Debug 还是 Release?都在这个文件里定。
我举个例子,打开 OvmfPkg/OvmfPkgX64.dsc,你会看到类似这样的结构:
[Defines]
PLATFORM_NAME = Ovmf
PLATFORM_GUID = ...
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]
# 这里列出要编译的模块
OvmfPkg/PlatformPei/PlatformPei.inf
OvmfPkg/BdsDxe/BdsDxe.inf
嗯,这里要注意:[Defines] 是全局配置,[LibraryClasses] 是库的「接线图」,[Components] 是最终要生成的模块列表。
3.3 .fdf 文件——固件描述文件
.fdf 文件,全称是 Flash Description File。
它和 .dsc 是「搭档」。.dsc 管「装什么菜」,.fdf 管「菜怎么摆盘」。
说白了,.fdf 定义了固件在 Flash 里的布局——哪个模块放在哪个地址?FV(Firmware Volume)怎么划分?
我曾经在项目里遇到过一个问题:固件编译成功,但刷进去就启动不了。查了半天,发现是 .fdf 里一个模块的地址写错了,导致覆盖了关键数据。从那以后,我每次改 .fdf 都会反复核对。
一个典型的 .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_LOCK_CAP = TRUE
READ_LOCK_STATUS = TRUE
WRITE_DISABLED_CAP = FALSE
WRITE_ENABLED = TRUE
WRITE_LOCK_CAP = TRUE
WRITE_LOCK_STATUS = TRUE
INF OvmfPkg/PlatformPei/PlatformPei.inf
INF OvmfPkg/BdsDxe/BdsDxe.inf
3.4 .dec 文件——包声明文件
.dec 文件,全称是 Package Declaration File。
它的作用很简单:声明这个包里有哪些公开的接口、PCD(平台配置数据)、GUID、协议等。
你可以把它理解成「目录索引」。其他模块想用这个包里的东西,就得先看 .dec 文件。
举个例子,MdePkg/MdePkg.dec 里会定义:
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = MdePkg
PACKAGE_GUID = ...
PACKAGE_VERSION = 1.0
[Includes]
Include
[LibraryClasses]
UefiLib|Include/Library/UefiLib.h
BaseLib|Include/Library/BaseLib.h
[PcdsFixedAtBuild]
gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF|UINT8|0x00000001
你看,[Includes] 告诉编译器头文件在哪,[LibraryClasses] 公开了库的接口,[PcdsFixedAtBuild] 定义了编译时可配置的参数。
3.5 三者的关系——一张图看懂
说了这么多,你可能有点晕。这三兄弟到底怎么配合的?
我画了一张图,你看完就明白了:
你看,这三者缺一不可。.dsc 是「菜单」,.fdf 是「摆盘方案」,.dec 是「食材清单」。编译工具把它们组合起来,最终生成一个完整的 UEFI 固件镜像。
- .dsc:定义平台要编译哪些模块和库。
- .fdf:定义固件在 Flash 中的布局。
- .dec:声明包对外提供的接口和配置。
搞懂这三个文件,EDK2 的工程结构你就掌握了七成。
嗯,今天就先聊到这。记住,别急着背目录,先动手打开一个 .dsc 文件看看,对照着我上面讲的,一行一行读下去。读懂了,你就算入门了。