EDKII 工程结构介绍

EDK2工程结构介绍

目录

一、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

二、常用的目录文件

2.1 BaseTools--构建工具链

  1. 主要的子目录

    BaseTools/
    ├── Source/
    │   ├── C/        # 用 C 写的底层工具(如 GenFw、GenFds)
    │   ├── Python/   # Python脚本,如 build.py、TargetTool.py
    │   └── Vfr/      # 处理 VFR (Visual Form Representation) 文件
    └── Scripts/
    
  2. BaseTools相当于编译器+脚本+构建系统。EDk2中所有工程编译都依赖这个目录里的工具,在编译EDk2工程之前,首先就要执行make -C BaseTools。编译出的关键命令如:GenFwGenFdsbuildVfrCompile等。随后执行edksetup.sh,上面编译出的命令就会被添加到环境变量PATH中。

2.2 Conf--配置目录

  1. 主要的目录文件

    Conf/
    ├── target.txt     # 构建目标(最重要!)
    ├── tools_def.txt  # 定义编译器工具链
    └── build_rule.txt # 定义构建规则
    
    # 以上文件在执行 source edksetup.sh 之后自动从 BaseTools/Conf 复制到当前的 Conf/ 目录中
    
  2. 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
    
  3. 也可以build的时候设置临时参数build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG

2.3 MdePkg--基础核心包

  1. 内容

    Include/	# 各种 UEFI 接口头文件(例如 Uefi.h)
    Library/	# 各种库(如 DebugLib、BaseLib)
    Protocol/	# UEFI 协议定义
    
  2. MdePkg相当于C标准库和操作系统内核API,提供了整个EDK2架构所需的基础定义和接口。

2.4 MdeModulePkg -- 常用模块包

  1. 目录结构

    MdeModulePkg/
    ├── Application/     # 应用(比如 HelloWorld)
    ├── Library/
    ├── Universal/       # 通用驱动模块
    └── Bus/             # 各种总线类驱动
    
  2. MdeModulePkgMdePkg的基础上实现了很多实际可用的模块,比如,UEFI驱动(Driver),UEFI 应用(Application),常见的服务(如Variable服务、Boot Manager)。

2.5 OvmfPkg--OVMF固件工程目录

Open Virtual Machine Firmware Package

  1. 目录结构

    OvmfPkg/
    ├── OvmfPkgX64.dsc   # 平台描述文件
    ├── OvmfPkgX64.fdf   # 镜像布局文件
    ├── PlatformDxe/     # 平台初始化驱动
    ├── Include/
    └── Library/
    
  2. 这是用于在QEMU虚拟机上运行的完整的UEFI固件工程,支持X64、IA32平台。该虚拟平台固件实现包在编译后输出文件OVMF.fd(完整的固件镜像)和OVMF_CODE.fd / OVMF_VARS.fd分区镜像(代码和变量区分离版本)。要编译该镜像,前面我们配置了target.txtACTIVE_PLATFORM=OvmfPkg/OvmfPkgX64.dsc

2.6 Build 编译输出路径

EDKII 的编译输出路径高度依赖与构建目标,它由以下几部分组成:[架构]/[工具链]/[构建模式]。

  • 架构:例如 X64, IA32, ARM, AARCH64 等。
  • 工具链:例如 VS2017x86 (Windows), GCC5 (Linux), XCODE5 (macOS) 等。
  • 构建模式DEBUG, RELEASE
  1. 编译出的镜像文件

    # 典型的路径结构
    <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 的组成部分。
  2. 在 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
      
  3. .dsc.inf是什么

    上面涉及到两个平台描述文件,编译固件镜像时使用到的OvmfPkg/OvmfPkgX64.dsc和编译模块时使用到的MdeModulePkg/MdeModulePkg.dsc,二者的差异本质是平台级配置和模块级配置的分工。

    平台描述模块(.dsc)的作用:

    • 定义构建目标(X64,DEBUG/RELEASE,GCC5等)
    • 模块列表与依赖,通过 [Components] 字段列出所有需编译的模块(.inf 文件),并指定模块间的依赖关系。如OvmfPkgX64.dsc 会包含虚拟化相关的驱动(如 VirtioBlkDxe.inf),而 MdeModulePkg.dsc 可能包含通用模块(如 UefiShell.inf)。

    模块描述文件(.inf)的作用:

    • 描述单个模块:定义模块类型(如 UEFI_APPLICATIONDXE_DRIVER)、源文件、依赖库([LibraryClasses])和编译选项。如,HelloWorld.inf 会指定源文件 HelloWorld.c 和依赖库 UefiLib
    • 模块级编译控制:通过 [BuildOptions] 覆盖平台级的编译选项(如优化级别、警告处理)。如:为 HelloWorld.inf 添加 -O2 优化标志,仅影响该模块。
    维度 OvmfPkgX64.dsc MdeModulePkg.dsc
    角色 平台级配置,定义虚拟化固件的整体构建规则。 模块集合,提供通用 UEFI 模块的默认配置。
    内容 包含虚拟化驱动、平台初始化代码、内存布局等。 包含文件系统、网络栈、Shell 等通用模块。
    使用场景 构建完整的 OVMF(Open Virtual Machine Firmware)固件。 作为模块库,供其他平台或自定义固件引用。
    依赖关系 可能依赖 MdeModulePkg 中的模块。 独立提供模块,无外部平台依赖。

附录

DSC 文件说明

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工程主要文件的一个大概理解,有助于建立系统性的思考,后续深入学习中会继续补充。


寄语:每天进步一点点,践踏实地!

posted @ 2025-10-31 18:29  阿源-  阅读(72)  评论(0)    收藏  举报