1. 课程导论与实验环境搭建:UEFI与TEE联合启动的背景、应用场景、开发板选型与交叉编译环境

各位同学,欢迎来到《UEFI与TEE联合启动实战》的第一章。

我先说说为什么开这门课。做了这么多年固件安全,我见过太多设备在启动阶段被攻破的例子。UEFI负责把系统拉起来,TEE负责保护敏感数据,但这两者之间如果没打通,安全就成了空话。说白了,联合启动就是让UEFI在引导过程中,把TEE也初始化好,并建立一条可信的通信管道。

核心观点:UEFI与TEE联合启动不是锦上添花,而是现代设备安全的刚需。从手机到服务器,从IoT到车机,只要涉及可信启动和敏感数据隔离,就绕不开这个组合。

1.1 为什么需要UEFI与TEE联合启动?

我简单梳理一下背景。传统UEFI启动只负责加载OS,安全方面主要靠Secure Boot验签。但验签之后呢?OS内核一旦有漏洞,整个系统就裸奔了。TEE(可信执行环境)提供了一个与Rich OS隔离的安全世界,但TEE自己也需要一个可信的启动过程。

联合启动要解决三个核心问题:

  • 信任链传递:UEFI验证TEE固件签名,确保TEE没有被篡改
  • 内存隔离:在启动阶段就把安全世界和非安全世界的内存划分好
  • 通信通道建立:UEFI和TEE之间需要一条安全的IPC通道

我在项目中遇到过最典型的情况:某款车机使用OP-TEE做数字钥匙管理,但UEFI启动时没有正确配置TZASC(TrustZone地址空间控制器),导致安全内存被非安全世界访问。嗯,这个问题排查了整整两周。从那以后,我对联合启动的每个细节都不敢马虎。

1.2 应用场景概览

你想想看,哪些场景需要UEFI+TEE联合启动?我列几个常见的:

场景 UEFI角色 TEE角色 联合启动关键点
移动支付终端 验证TEE镜像,配置安全内存 保护PIN输入和密钥 启动时建立安全通道
智能汽车网关 多级Secure Boot 隔离CAN总线密钥 TEE必须在CAN通信前就绪
云服务器 UEFI测量启动 保护平台密钥 TPM+TEE联合度量
工业PLC 锁定启动设备 运行安全控制逻辑 实时性要求下的启动时序

说白了,只要你的设备需要「启动时就安全」,而不是「启动后再安全」,就离不开联合启动。

1.3 开发板选型:QEMU vs 树莓派

做嵌入式开发,选对硬件能省一半时间。我个人建议初学者从QEMU开始,等流程跑通了再上树莓派。为什么?

  • QEMU(虚拟方案):调试方便,gdb直接连,断点随便打。不用烧录,不用串口线,不用怕变砖。适合学习阶段反复折腾。
  • 树莓派3B/4B(物理方案):真实硬件,有TrustZone支持(BCM2837/2711),能验证实际的内存隔离效果。但调试手段有限,出问题只能靠串口日志。

我的建议:先用QEMU把EDK2和OP-TEE的联合启动跑通,理解整个流程。然后切换到树莓派,解决真实硬件上的时序和内存配置问题。我在带团队时都是这个路线,效果很好。

两种方案的对比:

特性 QEMU 树莓派3B/4B
成本 免费 约200-400元
调试能力 强(gdb+图形化) 弱(串口+GPIO)
TrustZone支持 模拟(完整) 硬件(真实)
启动速度 快(秒级) 慢(分钟级)
适合阶段 学习、原型验证 产品化、性能测试

1.4 搭建EDK2与OP-TEE交叉编译环境

好,到了动手环节。搭建环境是这门课的第一个门槛,我尽量把步骤说清楚。

1.4.1 整体架构

先看一张图,理解EDK2和OP-TEE在联合启动中的位置:

UEFI与TEE联合启动架构图 硬件层(QEMU / 树莓派 SoC) ARM TrustZone | TZASC | GIC | UART 固件层(BL1 → BL2 → BL31 → BL32 → BL33) ARM Trusted Firmware (TF-A) 负责启动序列 BL31: EL3 Monitor | BL32: OP-TEE | BL33: UEFI 安全世界(Secure World) OP-TEE OS 安全存储 | 密码学服务 可信应用(TA) 通过SMC与UEFI通信 非安全世界(Normal World) UEFI (EDK2) Secure Boot | 变量服务 OS Loader 通过SMC调用TEE SMC 联合启动核心:UEFI通过SMC调用OP-TEE,完成安全世界初始化,建立信任链

1.4.2 环境准备

我习惯在Ubuntu 20.04/22.04 LTS上搭建,64位系统。需要安装的依赖包如下:

# 基础编译工具
sudo apt update
sudo apt install -y build-essential git python3 python3-pip \
  uuid-dev nasm acpica-tools

# ARM交叉编译链
sudo apt install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu

# QEMU
sudo apt install -y qemu-system-arm qemu-efi-aarch64

# 其他工具
sudo apt install -y device-tree-compiler flex bison \
  libssl-dev libncurses-dev

注意:交叉编译链版本很重要。我曾经因为用了gcc-arm-none-eabi(那是给裸机用的)去编译OP-TEE,结果链接阶段各种报错。一定要用gcc-aarch64-linux-gnu,这是针对Linux用户空间的。

1.4.3 源码获取与目录结构

我们需要三个主要仓库。我个人习惯把它们放在同一个工作目录下:

mkdir ~/uefi-tee-lab && cd ~/uefi-tee-lab

# 1. EDK2(UEFI固件)
git clone https://github.com/tianocore/edk2.git --recursive
cd edk2
git checkout edk2-stable202311

# 2. OP-TEE(可信执行环境)
cd ..
git clone https://github.com/OP-TEE/optee_os.git
cd optee_os
git checkout 4.1.0

# 3. ARM Trusted Firmware(ATF/BL31)
cd ..
git clone https://github.com/ARM-software/arm-trusted-firmware.git
cd arm-trusted-firmware
git checkout v2.10

目录结构应该是这样的:

~/uefi-tee-lab/
├── edk2/                    # UEFI固件源码
│   ├── ArmPkg/
│   ├── MdeModulePkg/
│   └── ...
├── optee_os/                # OP-TEE内核
│   ├── core/
│   ├── ta/
│   └── ...
└── arm-trusted-firmware/    # ATF(提供BL31)
    ├── bl31/
    ├── plat/
    └── ...

1.4.4 编译OP-TEE

先编译OP-TEE,因为UEFI需要引用它的头文件。这里以QEMU virt平台为例:

cd ~/uefi-tee-lab/optee_os

# 设置交叉编译环境变量
export CROSS_COMPILE=aarch64-linux-gnu-
export PLATFORM=vexpress-qemu_armv8a

# 编译
make -j$(nproc)

# 编译产物
# out/arm-plat-vexpress/core/tee-pager_v2.bin  (分页版本)
# out/arm-plat-vexpress/core/tee-raw.bin       (非分页版本)

小技巧:第一次编译时加上CFLAGS=-g,这样后续调试能看到源码级别的信息。我每次做联合启动调试都这么干,省去了反汇编的麻烦。

1.4.5 编译EDK2(带OP-TEE支持)

EDK2需要配置成支持OP-TEE的版本。关键是要在dsc文件中打开对应的Feature:

cd ~/uefi-tee-lab/edk2

# 设置环境
export EDK_TOOLS_PATH=$(pwd)/BaseTools
export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-
source edksetup.sh

# 编译BaseTools
make -C BaseTools

# 配置(以QEMU为例)
# 修改 ArmVirtPkg/ArmVirtQemu.dsc
# 在[Defines]段添加:
#   DEFINE OP_TEE_SUPPORT = TRUE

# 编译
build -a AARCH64 -t GCC5 -p ArmVirtPkg/ArmVirtQemu.dsc \
  -b DEBUG -D OP_TEE_SUPPORT=TRUE

# 编译产物
# Build/ArmVirtQemu-AARCH64/DEBUG_GCC5/FV/QEMU_EFI.fd

1.4.6 编译ATF(BL31)

BL31是EL3的固件,负责切换安全世界和非安全世界:

cd ~/uefi-tee-lab/arm-trusted-firmware

make CROSS_COMPILE=aarch64-linux-gnu- \
  PLAT=vexpress_qemu \
  ARM_LINUX_KERNEL_AS_BL33=0 \
  SPD=opteed \
  BL32=../optee_os/out/arm-plat-vexpress/core/tee-pager_v2.bin \
  all fip

# 编译产物
# build/vexpress_qemu/release/bl31.bin
# build/vexpress_qemu/release/fip.bin

重要:SPD=opteed这个参数不能写错。它告诉ATF使用OP-TEE的调度器。我见过有人写成SPD=optee(少了个d),结果BL31启动后找不到TEE,直接卡死在EL3。检查了三天才发现是拼写问题。

1.4.7 启动QEMU验证

所有东西编译好后,用QEMU启动验证:

qemu-system-aarch64 \
  -machine virt,secure=on,virtualization=on \
  -cpu cortex-a57 \
  -smp 2 \
  -m 1024 \
  -bios ~/uefi-tee-lab/arm-trusted-firmware/build/vexpress_qemu/release/fip.bin \
  -device loader,file=~/uefi-tee-lab/edk2/Build/ArmVirtQemu-AARCH64/DEBUG_GCC5/FV/QEMU_EFI.fd,addr=0x2000000 \
  -serial stdio

如果一切正常,你会看到UEFI启动画面,然后进入UEFI Shell。在Shell中可以通过SMC命令测试与OP-TEE的通信。

1.5 常见问题与避坑

我把这些年踩过的坑整理一下:

  • QEMU版本太旧:QEMU 5.0以下对TrustZone模拟不完整,建议用6.0以上。我目前用7.2,很稳定。
  • EDK2子模块拉不下来:国内网络问题,建议用代理或者手动下载。git clone时加--recursive容易失败,可以分步拉取。
  • OP-TEE编译报错:检查Python版本,需要3.6以上。另外pip install pyelftools这个包必须装。
  • 启动后看不到UEFI:检查fip.bin的地址是否正确。QEMU的secure=on参数必须加,否则BL31不会运行。

一句话总结:环境搭建是这门课最枯燥但最关键的一步。把EDK2、OP-TEE、ATF三者的编译和链接关系理清楚,后续的联合启动开发就会顺畅很多。别怕出错,每个错误都是学习的机会。