在 Windows 上交叉编译 AARCH64 UEFI 固件(ArmVirtQemu)
本文档记录了在 Windows 10/11 上使用 EDK2 源码和 GCC 交叉编译工具链,构建支持 Secure Boot 与 TPM 2.0 的 AARCH64 UEFI 固件(.fd)的完整流程,并使用 QEMU 验证固件启动。
1. 环境要求
| 组件 | 版本 | 说明 |
|---|---|---|
| EDK2 源码 | edk2 2508Full | 工作目录E:\code\edk22508Full |
| ARM GCC 交叉工具链 | arm-gnu-toolchain-15.3.rel1-mingw-w64-x86_64-aarch64-none-elf | 安装于C:\Tools\ |
| Host GCC (MinGW-W64) | 13.2.0 (Strawberry Perl 自带) | 用于编译 BaseTools C 工具 |
| GNU Make | 4.4.1 (Strawberry Perl 自带gmake.exe) | BaseTools 编译用 |
| Python | 3.10.9 | EDK2 build 系统依赖 |
| NASM | 2.x (Strawberry Perl 自带) | 汇编编译用 |
| iasl (ACPI 编译器) | 20250807 | 从 ACPICA GitHub Releases 下载 |
| QEMU | system-aarch64 | 用于固件启动验证 |
1.1 工具链路径一览
C:\Tools\arm-gnu-toolchain-15.3.rel1-mingw-w64-x86_64-aarch64-none-elf\bin\ ├── aarch64-none-elf-gcc.exe # 交叉编译器 ├── aarch64-none-elf-gcc-ar.exe # 静态库归档 ├── aarch64-none-elf-objcopy.exe # 目标文件转换 └── aarch64-none-elf-ld.exe # 链接器 C:\Strawberry\c\bin\ ├── gcc.exe # Host GCC (编译 BaseTools) ├── gmake.exe # GNU Make └── nasm.exe # NASM 汇编器 C:\Program Files\Python310\python.exe # Python 3.10 C:\Program Files\qemu\ └── qemu-system-aarch64.exe # QEMU (验证用)1.2 获取 iasl
从 ACPICA GitHub Releases 下载 Windows 预编译版本:
# 下载 iaslInvoke-WebRequest-Uri'https://github.com/user-attachments/files/21674608/iasl-win-20250807.zip'`-OutFile'iasl.zip'# 解压Expand-Archive-Path'iasl.zip'-DestinationPath'iasl_temp'# 复制到 BaseTools\Bin\Win32Copy-Item'iasl_temp\iasl.exe''E:\code\edk22508Full\BaseTools\Bin\Win32\iasl.exe'2. 编译 EDK2 BaseTools
BaseTools 是 EDK2 的构建工具集(C 工具 + Python 脚本),需要先编译。
2.1 初始化配置文件
运行edksetup.bat生成Conf\target.txt、Conf\tools_def.txt和Conf\build_rule.txt:
cd /d E:\code\edk22508Full call edksetup.bat如果
edksetup.bat因环境问题报错,可手动从BaseTools\Conf\目录复制.template文件到Conf\目录并去掉.template后缀。
2.2 编译 BaseTools C 工具
使用 Strawberry Perl 的 GNU Make 和 GCC 编译:
cd /d E:\code\edk22508Full\BaseTools\Source\C set HOST_ARCH=X64 set CC=gcc set CXX=g++ set PYTHON_COMMAND=py -3 set PATH=C:\Strawberry\c\bin;%PATH% C:\Strawberry\c\bin\gmake.exe -j4编译成功后,在BaseTools\Source\C\bin\下生成 12 个.exe文件:
BrotliCompress.exe DevicePath.exe EfiRom.exe GenCrc32.exe GenFfs.exe GenFv.exe GenFw.exe GenSec.exe LzmaCompress.exe TianoCompress.exe VfrCompile.exe VolInfo.exe2.3 复制工具到 Bin\Win32
mkdir E:\code\edk22508Full\BaseTools\Bin\Win32 2>nul copy E:\code\edk22508Full\BaseTools\Source\C\bin\*.exe ^ E:\code\edk22508Full\BaseTools\Bin\Win32\2.4 创建 GNU make 副本
EDK2 的 GCC 工具链通过GCC_HOST_BIN环境变量查找make。Strawberry Perl 提供的是gmake.exe,需要复制一份为make.exe:
copy C:\Strawberry\c\bin\gmake.exe C:\Strawberry\c\bin\make.exe3. 配置工具链
3.1 关键环境变量
| 环境变量 | 值 | 说明 |
|---|---|---|
GCC5_AARCH64_PREFIX | C:\Tools\arm-gnu-toolchain-...\bin\aarch64-none-elf- | ARM 交叉工具链前缀 |
GCC_HOST_BIN | C:\Strawberry\c\bin\ | Host GNU make 路径 |
NASM_PREFIX | C:\Strawberry\c\bin\ | NASM 前缀 |
PYTHON_COMMAND | py -3 | Python 命令 |
EDK_TOOLS_BIN | ...\BaseTools\Bin\Win32 | BaseTools 二进制路径 |
3.2 tools_def.txt 中的 GCC5 工具链
EDK2 的Conf\tools_def.txt已内置 GCC5 工具链定义,关键行:
# 工具链前缀通过环境变量设置 DEFINE GCC_HOST_PREFIX = ENV(GCC_HOST_BIN) # AARCH64 交叉编译器路径 *_GCC5_AARCH64_CC_PATH = ENV(GCC5_AARCH64_PREFIX)gcc *_GCC5_AARCH64_SLINK_PATH = ENV(GCC5_AARCH64_PREFIX)gcc-ar *_GCC5_AARCH64_DLINK_PATH = ENV(GCC5_AARCH64_PREFIX)gcc *_GCC5_AARCH64_ASM_PATH = ENV(GCC5_AARCH64_PREFIX)gcc *_GCC5_AARCH64_PP_PATH = ENV(GCC5_AARCH64_PREFIX)gcc *_GCC5_AARCH64_RC_PATH = ENV(GCC5_AARCH64_PREFIX)objcopy # Host make 路径 *_GCC5_*_MAKE_PATH = DEF(GCC_HOST_PREFIX)make4. 构建固件
4.1 构建脚本
创建build_armvirt.bat:
@echo off setlocal set "WORKSPACE=E:\code\edk22508Full" set "EDK_TOOLS_PATH=E:\code\edk22508Full\BaseTools" set "BASE_TOOLS_PATH=E:\code\edk22508Full\BaseTools" set "EDK_TOOLS_BIN=E:\code\edk22508Full\BaseTools\Bin\Win32" set "CONF_PATH=E:\code\edk22508Full\Conf" set "PYTHON_COMMAND=py -3" set "PYTHONPATH=E:\code\edk22508Full\BaseTools\Source\Python" set "GCC5_AARCH64_PREFIX=C:\Tools\arm-gnu-toolchain-15.3.rel1-mingw-w64-x86_64-aarch64-none-elf\bin\aarch64-none-elf-" set "GCC_HOST_BIN=C:\Strawberry\c\bin\" set "NASM_PREFIX=C:\Strawberry\c\bin\" set "PATH=E:\code\edk22508Full\BaseTools\Bin\Win32;E:\code\edk22508Full\BaseTools\BinWrappers\WindowsLike;C:\Strawberry\c\bin;C:\Program Files\Python310;C:\Program Files\qemu;%PATH%" cd /d E:\code\edk22508Full build -a AARCH64 -t GCC5 -b RELEASE -p ArmVirtPkg/ArmVirtQemu.dsc ^ -D SECURE_BOOT_ENABLE=TRUE ^ -D TPM2_ENABLE=TRUE ^ -D TPM2_CONFIG_ENABLE=TRUE ^ %*4.2 参数说明
| 参数 | 值 | 说明 |
|---|---|---|
-a | AARCH64 | 目标架构 |
-t | GCC5 | 工具链标签 |
-b | RELEASE | 构建类型(DEBUG / RELEASE / NOOPT) |
-p | ArmVirtPkg/ArmVirtQemu.dsc | 平台描述文件 |
-D SECURE_BOOT_ENABLE=TRUE | — | 启用 Secure Boot(镜像签名验证) |
-D TPM2_ENABLE=TRUE | — | 启用 TPM 2.0 支持 |
-D TPM2_CONFIG_ENABLE=TRUE | — | 启用 TPM 2.0 配置界面 |
4.3 执行构建
cd /d E:\code\edk22508Full build_armvirt.bat构建过程约 3~15 分钟(取决于 CPU 核心数),输出如下关键信息表示成功:
Fd File Name:QEMU_EFI (...\Build\ArmVirtQemu-AARCH64\RELEASE_GCC5\FV\QEMU_EFI.fd) Fd File Name:QEMU_VARS (...\Build\ArmVirtQemu-AARCH64\RELEASE_GCC5\FV\QEMU_VARS.fd) FV Space Information FVMAIN [99%Full] 7131712 total, 7131656 used, 56 free FVMAIN_COMPACT [38%Full] 3141632 total, 1199736 used, 1941896 free - Done -4.4 构建产物
| 文件 | 大小 | 说明 |
|---|---|---|
QEMU_EFI.fd | 3 MB | 主固件文件(包含 SEC/PEI/DXE/BDS 全部模块) |
QEMU_VARS.fd | 768 KB | NVRAM 变量存储(Secure Boot 密钥等) |
路径:Build\ArmVirtQemu-AARCH64\RELEASE_GCC5\FV\
5. Secure Boot 与 TPM 2.0 模块说明
5.1 Secure Boot 相关模块
启用SECURE_BOOT_ENABLE=TRUE后,以下模块被编入固件:
| 模块 | 阶段 | 功能 |
|---|---|---|
DxeImageVerificationLib | DXE | UEFI 镜像签名验证 |
SecureBootConfigDxe | DXE | Secure Boot 配置界面 |
EnrollDefaultKeys | DXE | 默认密钥注册 |
VariableRuntimeDxe | DXE | 认证变量服务(AuthVar) |
相关 PCD:
gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x04 gEfiSecurityPkgTokenSpaceGuid.PcdFixedMediaImageVerificationPolicy|0x04 gEfiSecurityPkgTokenSpaceGuid.PcdRemovableMediaImageVerificationPolicy|0x045.2 TPM 2.0 相关模块
启用TPM2_ENABLE=TRUE后,以下模块被编入固件:
| 模块 | 阶段 | 功能 |
|---|---|---|
Tcg2ConfigPei | PEI | TPM 2.0 早期配置 |
Tcg2Pei | PEI | PEI 阶段 TPM 度量 |
Tcg2Dxe | DXE | DXE 阶段 TCG2 协议 |
Tcg2ConfigDxe | DXE | TPM 2.0 配置界面 |
DxeTpm2MeasureBootLib | DXE | 启动度量(需同时启用 Secure Boot) |
Tpm2CommandLib | — | TPM 2.0 命令库 |
Tpm2DeviceLibDTpm | — | dTPM MMIO 设备访问库 |
注意:TPM 2.0 模块已编入
.fd,但实际运行需要 QEMU 提供 TPM 设备模拟(tpm-tis-device前端 +swtpm后端)。Windows 版 QEMU 不支持 TPM 后端,需在 Linux 环境验证。
6. QEMU 验证固件启动
6.1 准备 pflash 镜像
QEMUvirt机器的 pflash 设备要求 64 MB 镜像,需要将 3 MB 的QEMU_EFI.fd填充到 64 MB:
# 填充 QEMU_EFI.fd 到 64MB$content=[System.IO.File]::ReadAllBytes('...\FV\QEMU_EFI.fd')$padded=New-Objectbyte[]67108864[Array]::Copy($content,$padded,$content.Length)[System.IO.File]::WriteAllBytes('...\FV\QEMU_EFI_64M.fd',$padded)# 填充 QEMU_VARS.fd 到 64MB(可写副本)$content=[System.IO.File]::ReadAllBytes('...\FV\QEMU_VARS.fd')$padded=New-Objectbyte[]67108864[Array]::Copy($content,$padded,$content.Length)[System.IO.File]::WriteAllBytes('...\FV\QEMU_VARS_64M.fd',$padded)6.2 启动 QEMU
qemu-system-aarch64.exe ^ -machine virt ^ -cpu cortex-a57 ^ -m 512 ^ -nographic ^ -drive if=pflash,format=raw,file=QEMU_EFI_64M.fd,readonly=on ^ -drive if=pflash,format=raw,file=QEMU_VARS_64M.fd ^ -net none6.3 预期输出
固件正常启动时,串口输出如下:
UEFI firmware (version built at 12:13:16 on Jul 27 2026) BdsDxe: No bootable option or device was found. BdsDxe: Press any key to enter the Boot Manager Menu.按任意键后进入 Boot Manager 菜单:
Please select boot device: EFI Firmware Setup ^ and v to move selection ENTER to select boot device ESC to exit这表明固件从 SEC → PEI → DXE → BDS 全流程正常执行。
7. 常见问题
Q1:make tbuild失败,提示 “Unable to open makefile”
原因:系统 PATH 中的 Embarcaderomake.exe优先于 GNU make。
解决:复制 Strawberry Perl 的gmake.exe为make.exe,并确保GCC_HOST_BIN指向C:\Strawberry\c\bin\。
Q2:iasl未找到
原因:RamDiskDxe 等模块需要 iasl 编译 ACPI 表。
解决:从 ACPICA GitHub Releases 下载iasl-win-*.zip,解压后将iasl.exe放入BaseTools\Bin\Win32\。
Q3:HOST_ARCH is not defined
原因:BaseTools 的header.makefile无法自动检测 host 架构。
解决:编译时显式传入set HOST_ARCH=X64。
Q4: Pccts/antlr 编译失败(ccnot found)
原因:Pccts 的 makefile 默认使用cc而非gcc。
解决:编译时设置set CC=gcc和set CXX=g++。
Q5: QEMU 报错 “requires 67108864 bytes, pflash0 provides 3145728 bytes”
原因:QEMUvirt机器的 pflash 设备要求 64 MB 镜像。
解决:用零字节将.fd文件填充到 64 MB(见第 6.1 节)。
Q6: QEMU 不支持 TPM(-tpmdev: invalid option)
原因:QEMU 在 Windows 平台上不支持 TPM 后端(meson.build中限制host_os != 'windows')。
解决:固件端 TPM 2.0 模块已编入.fd。如需验证 TPM 功能,需在 Linux 环境使用 QEMU + swtpm。
8. 目录结构参考
E:\code\edk22508Full\ ├── ArmVirtPkg\ # ArmVirt 平台包 │ ├── ArmVirtQemu.dsc # 平台描述文件(构建入口) │ ├── ArmVirtQemu.fdf # Flash 描述文件(FD 布局) │ └── ArmVirtQemuFvMain.fdf.inc # FVMAIN 内容定义 ├── BaseTools\ │ ├── Bin\Win32\ # 编译后的 C 工具 + iasl.exe │ ├── Source\C\ # C 工具源码 │ └── Source\Python\ # build 系统 Python 脚本 ├── Conf\ │ ├── target.txt # 构建目标配置 │ ├── tools_def.txt # 工具链定义 │ └── build_rule.txt # 构建规则 ├── Build\ │ └── ArmVirtQemu-AARCH64\ │ └── RELEASE_GCC5\ │ ├── AARCH64\ # 编译中间产物 │ └── FV\ │ ├── QEMU_EFI.fd # ★ 主固件 (3MB) │ └── QEMU_VARS.fd # ★ 变量存储 (768KB) └── build_armvirt.bat # 一键构建脚本增加一张带有电池功能的截图,看起来Windows On ARM的还可以