时间:2025-10-31 18:29
人气:
作者:admin
EDK2工程目录的一级结构ayuan@ayuan-virtual-machine:~/src/edk2$ tree -L 1
.
├── ArmPkg # ARM架构相关代码
├── ArmPlatformPkg
├── ArmVirtPkg
├── BaseTools # 编译EDK2所需基础工具集,包含编译器,链接器等
├── Build # 构建输出目录,编译后生成的文件,包括各种平台的固件镜像
├── Conf # target.txt文件用于定义要构建的平台,构建目标和工具链配置
├── CONTRIBUTING.md
├── CryptoPkg # OpenSSL加密支持
├── DynamicTablesPkg
├── edksetup.bat
├── edksetup.sh # 环境配置脚本,设置编译环境变量,初始化工作环境
├── EmbeddedPkg
├── EmulatorPkg
├── FatPkg
├── FmpDevicePkg
├── IntelFsp2Pkg
├── IntelFsp2WrapperPkg
├── License-History.txt
├── License.txt
├── Maintainers.txt
├── MdeModulePkg # 模块化核心包
├── MdePkg # 最基础的核心包,UEFI标准定义,基本数据类型和库函数
├── NetworkPkg # 网络协议栈
├── OvmfPkg # 虚拟机固件
├── PcAtChipsetPkg
├── pip-requirements.txt
├── PrmPkg
├── ReadMe.rst
├── RedfishPkg
├── SecurityPkg # 安全功能
├── ShellPkg # shell命令行界面
├── SignedCapsulePkg
├── SourceLevelDebugPkg
├── StandaloneMmPkg
├── UefiCpuPkg # x86 CPU相关功能
├── UefiPayloadPkg
└── UnitTestFrameworkPkg
29 directories, 8 files
BaseTools--构建工具链主要的子目录
BaseTools/
├── Source/
│ ├── C/ # 用 C 写的底层工具(如 GenFw、GenFds)
│ ├── Python/ # Python脚本,如 build.py、TargetTool.py
│ └── Vfr/ # 处理 VFR (Visual Form Representation) 文件
└── Scripts/
BaseTools相当于编译器+脚本+构建系统。EDk2中所有工程编译都依赖这个目录里的工具,在编译EDk2工程之前,首先就要执行make -C BaseTools。编译出的关键命令如:GenFw、GenFds、build、VfrCompile等。随后执行edksetup.sh,上面编译出的命令就会被添加到环境变量PATH中。
Conf--配置目录主要的目录文件
Conf/
├── target.txt # 构建目标(最重要!)
├── tools_def.txt # 定义编译器工具链
└── build_rule.txt # 定义构建规则
# 以上文件在执行 source edksetup.sh 之后自动从 BaseTools/Conf 复制到当前的 Conf/ 目录中
Conf中最主要的文件是target.txt。它告诉编译系统使用哪个平台(.dsc),目标架构是什么,使用的编译工具链是什么,输出的目录位置等。要修改的主要参数如下:
# 适用于本地x86_64的最小配置
ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc
TARGET = DEBUG
TARGET_ARCH = X64
TOOL_CHAIN_TAG = GCC5
BUILD_RULE_CONF = Conf/build_rule.txt
也可以build的时候设置临时参数build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG。
MdePkg--基础核心包内容
Include/ # 各种 UEFI 接口头文件(例如 Uefi.h)
Library/ # 各种库(如 DebugLib、BaseLib)
Protocol/ # UEFI 协议定义
MdePkg相当于C标准库和操作系统内核API,提供了整个EDK2架构所需的基础定义和接口。
MdeModulePkg -- 常用模块包目录结构
MdeModulePkg/
├── Application/ # 应用(比如 HelloWorld)
├── Library/
├── Universal/ # 通用驱动模块
└── Bus/ # 各种总线类驱动
MdeModulePkg在MdePkg的基础上实现了很多实际可用的模块,比如,UEFI驱动(Driver),UEFI 应用(Application),常见的服务(如Variable服务、Boot Manager)。
OvmfPkg--OVMF固件工程目录Open Virtual Machine Firmware Package
目录结构
OvmfPkg/
├── OvmfPkgX64.dsc # 平台描述文件
├── OvmfPkgX64.fdf # 镜像布局文件
├── PlatformDxe/ # 平台初始化驱动
├── Include/
└── Library/
这是用于在QEMU虚拟机上运行的完整的UEFI固件工程,支持X64、IA32平台。该虚拟平台固件实现包在编译后输出文件OVMF.fd(完整的固件镜像)和OVMF_CODE.fd / OVMF_VARS.fd分区镜像(代码和变量区分离版本)。要编译该镜像,前面我们配置了target.txt中ACTIVE_PLATFORM=OvmfPkg/OvmfPkgX64.dsc。
EDKII 的编译输出路径高度依赖与构建目标,它由以下几部分组成:[架构]/[工具链]/[构建模式]。
X64, IA32, ARM, AARCH64 等。VS2017x86 (Windows), GCC5 (Linux), XCODE5 (macOS) 等。DEBUG, RELEASE。编译出的镜像文件
# 典型的路径结构
<Your_Edk2_Workspace>/Build/<PlatformPkg>/<Architecture>/<Toolchain>/<BuildMode>
# 假设编译的是 OvmfPkg,目标架构是 X64,使用 GCC5 工具链,编译为 DEBUG 模式。
~/edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd
FV 目录是指固件卷,包含了构成固件的各个模块和最终镜像。
OVMF.fd: 这是最终的 扁平化镜像,包含了所有代码和数据,可以直接被虚拟机加载。这是用于 QEMU/KVM 的最重要的文件。OVMF_CODE.fd: 代码部分的镜像,通常需要与 OVMF_VARS.fd 配对使用。OVMF_VARS.fd: 变量存储部分的镜像,用于保存 UEFI 设置。\*.fv: 其他固件卷文件,它们是 OVMF.fd 的组成部分。在 UFFI Shell 下运行的驱动程序或应用程序,它们的路径与模块的编译方式(是否被包含在平台 DSC 文件中)有关。
作为平台固件的一部分被编译。当应用/驱动在平台的 DSC 文件 ([Components] 部分) 中定义时,它会被编译并链接到最终的 .fd 文件中。同时,它也会有一个独立的 .efi 文件被生成。
# 路径结构
<Your_Edk2_Workspace>/Build/<PlatformPkg>/<Architecture>/<Toolchain>/<BuildMode>/[Architecture]
# 举例
# 假设我们编译了 MdeModulePkg/Application/HelloWorld/HelloWorld.inf 这个应用。
~/edk2/Build/OvmfX64/DEBUG_GCC5/X64/HelloWorld.efi
单独编译一个模块。使用 build 命令单独编译一个模块时,输出路径类似,但 PlatformPkg 部分会被替换。
build -p MdeModulePkg/MdeModulePkg.dsc -m MdeModulePkg/Application/HelloWorld/HelloWorld.inf -a X64 -t GCC5
# 输出路径
~/edk2/Build/MdeModule/DEBUG_GCC5/X64/HelloWorld.efi
build 命令中,-p/--platform 用于指定平台描述文件的路径。MdeModulePkg/MdeModulePkg.dsc表示使用 MdeModulePkg 目录下的 MdeModulePkg.dsc 文件作为平台配置文件。该文件定义了模块的构建规则、库依赖、编译选项等全局配置。
-m/--module指定要单独构建的模块描述文件(.inf 文件)的路径。例子中的命令表示仅构建 HelloWorld 模块,其配置由 HelloWorld.inf 文件定义(如源代码文件、依赖的库等)。
# 构建平台所有模块
build -p MdeModulePkg/MdeModulePkg.dsc -a X64 -t GCC5
.dsc 和 .inf是什么
上面涉及到两个平台描述文件,编译固件镜像时使用到的OvmfPkg/OvmfPkgX64.dsc和编译模块时使用到的MdeModulePkg/MdeModulePkg.dsc,二者的差异本质是平台级配置和模块级配置的分工。
平台描述模块(.dsc)的作用:
[Components] 字段列出所有需编译的模块(.inf 文件),并指定模块间的依赖关系。如OvmfPkgX64.dsc 会包含虚拟化相关的驱动(如 VirtioBlkDxe.inf),而 MdeModulePkg.dsc 可能包含通用模块(如 UefiShell.inf)。模块描述文件(.inf)的作用:
UEFI_APPLICATION、DXE_DRIVER)、源文件、依赖库([LibraryClasses])和编译选项。如,HelloWorld.inf 会指定源文件 HelloWorld.c 和依赖库 UefiLib。[BuildOptions] 覆盖平台级的编译选项(如优化级别、警告处理)。如:为 HelloWorld.inf 添加 -O2 优化标志,仅影响该模块。| 维度 | OvmfPkgX64.dsc | MdeModulePkg.dsc |
|---|---|---|
| 角色 | 平台级配置,定义虚拟化固件的整体构建规则。 | 模块集合,提供通用 UEFI 模块的默认配置。 |
| 内容 | 包含虚拟化驱动、平台初始化代码、内存布局等。 | 包含文件系统、网络栈、Shell 等通用模块。 |
| 使用场景 | 构建完整的 OVMF(Open Virtual Machine Firmware)固件。 | 作为模块库,供其他平台或自定义固件引用。 |
| 依赖关系 | 可能依赖 MdeModulePkg 中的模块。 |
独立提供模块,无外部平台依赖。 |
DSC 文件的全称是 Platform Description File,它像一个项目的“总编译清单”或“Makefile”。它描述了要构建一个完整的、可启动的固件镜像,需要编译哪些模块,以及如何编译它们。它通常以平台名命名比如OvmfPkg/OvmfPkgX64.dsc,如果是我们自己的硬件开发平台包YourBoardPkg/YourBoardPkg.dsc。它定义了全局的编译选项、支持的架构、使用的库、以及最重要的——需要编译的模块组件列表。
[Components] 是DSC文件中的一个特定区块,它通过节 来定义。作用是列出所有需要被编译并链接到最终固件镜像中的模块。
DSC 文件举例:
[Defines]
PLATFORM_NAME = OvmfX64
PLATFORM_GUID = ...
SUPPORTED_ARCHITECTURES = X64
BUILD_TARGETS = DEBUG|RELEASE|NOOPT
# ... 其他部分,比如 [LibraryClasses] ...
[Components]
# 首先,包含来自其他Package的组件
MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
MdeModulePkg/Core/Dxe/DxeMain.inf
MdeModulePkg/Universal/Console/ConPlatformDxe/ConPlatformDxe.inf
# 平台自身的组件
OvmfPkg/VirtioBlkDxe/VirtioBlk.inf
OvmfPkg/VirtioNetDxe/VirtioNet.inf
# !!!这里就是关键所在!!!
# 如果HelloWorld应用被包含在这里,它就会被编译进固件
MdeModulePkg/Application/HelloWorld/HelloWorld.inf
# ... 还有很多很多其他的组件 ...
当你在EDKII根目录下执行 build -p OvmfPkg/OvmfPkgX64.dsc ... 时,构建系统会读取这个DSC文件。
构建系统会找到 [Components] 这一节。
然后,它会依次去编译列表中每一个 .inf 文件所描述的模块。
构建系统根据 HelloWorld.inf 的指导,将C源代码编译、链接,生成一个独立的UEFI应用程序。
链接到最终的 .fd 文件。
本文只是对EDK2工程主要文件的一个大概理解,有助于建立系统性的思考,后续深入学习中会继续补充。
寄语:每天进步一点点,践踏实地!