第二章:开发环境搭建
说实话,做UEFI和ATF的协同移植,环境搭建这一步要是没弄好,后面全是坑。我见过太多人上来就编译,结果卡在工具链版本不对、源码路径混乱这些基础问题上。今天咱们就把这事一次性说清楚。
2.1 Linux开发环境配置
我个人习惯用Ubuntu 20.04 LTS,这个版本对EDK2和TF-A的兼容性最好。你问为什么不用最新的22.04?嗯,我在项目里试过,有些老版本的交叉编译工具链在22.04上会有奇怪的依赖问题,犯不着给自己找麻烦。
推荐配置:
- 操作系统:Ubuntu 20.04 LTS(64位)
- 内存:至少8GB(我建议16GB,编译ATF时你就知道为什么了)
- 磁盘:至少50GB空闲空间
- CPU:4核以上
装好系统后,第一件事就是更新软件源并安装基础依赖包。别偷懒,我遇到过有人跳过这步,结果编译到一半报缺少库文件,那才叫一个崩溃。
sudo apt update
sudo apt upgrade -y
sudo apt install -y build-essential git python3 python3-pip \
uuid-dev nasm acpica-tools flex bison \
libssl-dev libncurses-dev
小提示:如果你用的是企业内网环境,记得提前配置好apt的代理或者本地源。我曾经在客户现场折腾了一下午,就是因为网络不通装不了依赖包。
2.2 交叉编译工具链安装
做ARM平台的UEFI和ATF移植,交叉编译工具链是必须的。说白了,你是在x86的电脑上编译出能在ARM芯片上跑的代码,没有交叉工具链这事干不了。
我推荐用ARM官方提供的GNU工具链,稳定可靠。这里有两个选择:
| 工具链 | 适用场景 | 下载方式 |
|---|---|---|
| aarch64-none-elf- | ATF、裸机程序 | ARM官网或Linaro |
| aarch64-linux-gnu- | EDK2、Linux内核 | apt直接安装 |
我个人习惯两种都装,因为EDK2和ATF对工具链的要求不太一样。安装方法如下:
# 安装Linux GNU工具链(用于EDK2)
sudo apt install -y gcc-aarch64-linux-gnu
# 下载ARM裸机工具链(用于ATF)
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/\
gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz
tar -xf gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf.tar.xz
sudo mv gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf /opt/
# 配置环境变量
echo 'export PATH=$PATH:/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-elf/bin' >> ~/.bashrc
source ~/.bashrc
注意:工具链版本一定要匹配!我曾经在移植某款国产芯片时,用了太新的工具链,结果ATF编译出来的二进制在板子上跑不起来,查了两天才发现是工具链的ABI兼容性问题。建议先用文档里推荐的版本,稳定了再升级。
2.3 EDK2源码获取
EDK2是TianoCore社区维护的UEFI固件开发框架。获取源码的方式很简单,用git clone就行。但这里有个讲究——分支选择。
# 克隆EDK2主仓库
git clone https://github.com/tianocore/edk2.git
cd edk2
# 更新子模块(这一步千万别忘)
git submodule update --init --recursive
# 我建议切换到稳定分支
git checkout edk2-stable202305
为什么推荐用稳定分支?你想想看,master分支天天有人提交代码,说不定昨天还能编译通过,今天就挂了。我在项目里吃过这个亏,后来就学乖了,只用打了tag的版本。
EDK2的目录结构大致如下:
- MdePkg/ — 核心的UEFI规范定义和库
- MdeModulePkg/ — 通用的UEFI驱动模块
- ArmPkg/ — ARM平台相关的代码
- ArmVirtPkg/ — ARM虚拟化平台支持
- Platform/ — 各厂商的平台代码
经验之谈:如果你要移植到自己的板子上,建议在Platform/目录下新建一个文件夹,不要直接改别人的代码。这样方便后续同步上游更新。
2.4 TF-A源码获取
TF-A(Trusted Firmware-A)是ARM官方维护的ATF实现。获取方式和EDK2类似,但它的子模块管理更复杂一些。
# 克隆TF-A仓库
git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
cd trusted-firmware-a
# 查看可用版本
git tag | grep -E "^v2\.[0-9]"
# 我建议用最新的LTS版本
git checkout v2.9.0
TF-A的源码结构比EDK2清晰很多:
- bl1/ — 启动阶段1(Boot Loader stage 1)
- bl2/ — 启动阶段2
- bl31/ — 启动阶段3(运行时的安全监控器)
- plat/ — 平台相关代码,移植主要在这里
- drivers/ — 驱动代码
- lib/ — 通用库
2.5 知识体系总览
说了这么多,咱们用一张图把整个环境搭建的逻辑串起来。你一看就明白了:
2.6 环境验证
装完这些东西,怎么知道环境对不对?我教你一个快速验证的方法。写个简单的C程序,用交叉编译器编译一下:
# 创建测试文件
cat > hello.c << EOF
#include <stdio.h>
int main() {
printf("Hello, UEFI + ATF World!\n");
return 0;
}
EOF
# 用aarch64-linux-gnu-gcc编译
aarch64-linux-gnu-gcc -o hello hello.c
# 查看生成的文件类型
file hello
# 输出应该包含:ELF 64-bit LSB executable, ARM aarch64
如果看到ARM aarch64的字样,说明工具链工作正常。接下来验证EDK2和TF-A的编译环境:
# 验证EDK2编译环境
cd edk2
make -C BaseTools
echo $?
# 返回0表示成功
# 验证TF-A编译环境
cd trusted-firmware-a
make -C tools/fiptool
echo $?
# 返回0表示成功
到这里,你的开发环境就搭好了。 整个过程大概需要30分钟到1小时,取决于网络速度。我建议你把这一步的每个命令都保存下来,下次换机器或者重装系统时直接复用。
嗯,环境搭建这部分就这些内容。记住一句话:工欲善其事,必先利其器。环境搭好了,后面的移植工作才能顺风顺水。