3、EDK2开发环境搭建:源码获取、编译配置、模拟器运行与第一个UEFI应用

好,咱们进入实战环节。这一章我带你亲手把EDK2环境搭起来,跑通模拟器,再写个Hello World级别的UEFI应用。说实话,环境搭建这一步卡住过不少人,我自己早期也被Python版本和工具链路径折腾过。别急,跟着我的节奏来,一步步走稳。

3.1 源码获取:从GitHub拉取EDK2

EDK2的源码托管在GitHub上,项目名叫tianocore/edk2。我建议你直接克隆主分支,别用那些过时的稳定版——UEFI规范更新快,主分支反而更靠谱。

git clone https://github.com/tianocore/edk2.git
cd edk2
git submodule update --init --recursive

这里有个坑:子模块一定要更新。EDK2依赖了MdeModulePkg、BaseTools等子仓库,不拉全的话编译会报一堆莫名其妙的错误。我当年第一次编译时偷懒没执行submodule update,结果卡了半小时查错。

我的习惯:克隆完后先跑一遍git status确认子模块状态。如果看到modified: xxx (new commits),说明子模块没对齐,重新执行git submodule update --remote即可。

3.2 编译环境配置:Python、工具链与EDK2设置

EDK2的编译系统基于Python 3,所以Python环境是必须的。我推荐Python 3.8以上版本,太老的版本有些脚本跑不动。

接下来配置工具链。Linux下我习惯用GCC5,Windows下用VS2019或VS2022。这里以Linux为例:

export WORKSPACE=$PWD
export PACKAGES_PATH=$WORKSPACE/edk2
export EDK_TOOLS_PATH=$WORKSPACE/edk2/BaseTools
source edk2/edksetup.sh

执行edksetup.sh后,脚本会自动检测工具链。如果报错说找不到Python,检查一下python3命令是否在PATH里。我个人习惯把Python路径写进.bashrc,省得每次重设。

注意:Windows用户需要以管理员身份运行edksetup.bat,否则某些符号链接创建会失败。我曾经因为这个折腾了一下午,最后发现是权限问题。

编译BaseTools也很关键:

make -C BaseTools

这一步会生成GenFw、GenFds等工具,没有它们后续编译会卡住。编译完成后,可以用build -v测试一下环境是否正常。

3.3 模拟器运行:用QEMU启动UEFI Shell

环境搭好了,咱们先跑个模拟器验证一下。EDK2自带了一个EmulatorPkg,但说实话,那个在Linux下不太好用。我更推荐用QEMU + OVMF(UEFI固件模拟器)。

先安装QEMU:

sudo apt-get install qemu-system-x86

然后编译OVMF:

build -a X64 -t GCC5 -p OvmfPkg/OvmfPkgX64.dsc -b DEBUG

编译完成后,在Build/OvmfX64/DEBUG_GCC5/FV目录下会生成OVMF.fd。用QEMU加载它:

qemu-system-x86_64 -bios Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd -m 1024

你会看到一个UEFI Shell界面。输入map -r可以列出所有设备,输入help查看命令列表。嗯,看到这个界面,说明你的环境已经跑通了。

避坑指南:如果QEMU启动后黑屏,检查一下-m参数是否给了足够内存。我建议至少512MB,否则UEFI固件可能加载失败。

3.4 第一个UEFI应用程序:HelloWorld

好,重头戏来了。咱们写一个最简单的UEFI应用,打印"Hello, UEFI!"。

首先,在edk2目录下创建一个MyHelloPkg文件夹,里面放两个文件:

MyHelloPkg/MyHelloPkg.dsc

[Defines]
  PLATFORM_NAME                  = MyHelloPkg
  PLATFORM_GUID                  = 12345678-1234-1234-1234-123456789abc
  PLATFORM_VERSION               = 0.1
  DSC_SPECIFICATION              = 0x00010005
  OUTPUT_DIRECTORY               = Build/MyHelloPkg
  SUPPORTED_ARCHITECTURES        = X64
  BUILD_TARGETS                  = DEBUG|RELEASE
  SKUID_IDENTIFIER               = DEFAULT

[Components]
  MyHelloPkg/HelloWorld.inf

MyHelloPkg/HelloWorld.inf

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = HelloWorld
  FILE_GUID                      = abcdef01-2345-6789-abcd-ef0123456789
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

[Sources]
  HelloWorld.c

[Packages]
  MdePkg/MdePkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib

MyHelloPkg/HelloWorld.c

#include <Uefi.h>
#include <Library/UefiApplicationEntryPoint.h>
#include <Library/UefiLib.h>

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print (L"Hello, UEFI!\n");
  Print (L"Welcome to EDK2 development!\n");
  return EFI_SUCCESS;
}

编译命令:

build -a X64 -t GCC5 -p MyHelloPkg/MyHelloPkg.dsc -b DEBUG

编译成功后,在Build/MyHelloPkg/DEBUG_GCC5/X64目录下找到HelloWorld.efi。把这个文件放到QEMU的虚拟磁盘里,或者用-drive参数挂载一个FAT分区,然后在UEFI Shell中运行它:

fs0:\> HelloWorld.efi
Hello, UEFI!
Welcome to EDK2 development!
小技巧:如果不想折腾虚拟磁盘,可以用-fw_cfg参数直接把EFI文件传给QEMU。命令如下:
qemu-system-x86_64 -bios OVMF.fd -fw_cfg name=opt/HelloWorld.efi,file=HelloWorld.efi
然后在Shell里用load命令加载它。

3.5 知识体系总览

下面这张图帮你理清本章的核心逻辑:从源码获取到应用运行的全流程。

EDK2开发环境搭建流程 1. 源码获取 git clone + submodule 2. 环境配置 Python + 工具链 + edksetup 3. 编译BaseTools make -C BaseTools 4. 编译OVMF build -p OvmfPkgX64.dsc 5. QEMU运行 qemu + OVMF.fd 6. 编写UEFI应用 HelloWorld.c + .inf + .dsc 7. 编译并运行 build → HelloWorld.efi → Shell 输出:Hello, UEFI! UEFI Shell中运行成功 图:EDK2开发环境搭建全流程(从源码到第一个UEFI应用)

这张图把整个流程串起来了。你想想看,从拉代码到跑通应用,其实就七个步骤。每一步都有对应的命令和文件,照着做就行。

3.6 常见问题与避坑

  • 编译报错"Python not found":检查python3 --version,如果没装就sudo apt install python3。我建议用Python 3.8+。
  • QEMU启动后卡在"Press ESC for boot menu":按ESC进入菜单,选择"Boot Manager"然后选"UEFI Shell"。如果没看到Shell,检查OVMF是否编译正确。
  • HelloWorld.efi运行时报"Image not found":大概率是文件路径不对。用map -r确认磁盘映射,然后cd fs0:进入正确分区。
  • Windows下编译失败:确保VS的nmake在PATH里。我习惯用"Developer Command Prompt for VS"启动终端。
核心要点:环境搭建最怕半途而废。我的经验是——先跑通模拟器,再写应用。模拟器能跑起来,说明工具链和编译环境没问题。剩下的就是代码细节了。

好,这一章的内容就到这儿。你跟着步骤走,应该能顺利跑出"Hello, UEFI!"。下一章咱们会深入UEFI驱动的开发模型,到时候见。

可可精品资料库