3. OP-TEE 环境搭建:从源码到调试的全流程

说实话,搭建 OP-TEE 开发环境这件事,我前前后后折腾过不下十次。每次换新机器、换新版本,总会冒出些新问题。这一章我就把踩过的坑、总结的经验,一次性讲清楚。

咱们的目标很明确:让 OP-TEE 在 QEMU 模拟器上跑起来,并且能调试。这样你才能在上面跑国密算法,验证 TrustZone 下的可信执行逻辑。

3.1 环境概览:你需要什么?

先看一张整体架构图,心里有个谱。

OP-TEE 开发环境整体架构 主机开发环境(Ubuntu 20.04/22.04) 交叉编译工具链 | OP-TEE 源码 | QEMU 模拟器 | GDB 调试器 QEMU 模拟器(ARMv8-A 平台) 模拟 4 核 Cortex-A53,支持 TrustZone 扩展 OP-TEE 目标系统(ARM TrustZone) 非安全世界(REE) Linux 内核 | CA 客户端 | 普通应用 安全世界(TEE) OP-TEE OS | TA 可信应用 | 国密算法 安全监控模式(Monitor) SMC

整个环境分三层:主机(你面前的电脑)、QEMU 模拟层(虚拟的 ARM 开发板)、目标系统(OP-TEE 跑在 TrustZone 上)。

我个人习惯用 Ubuntu 22.04 LTS,64 位版本。其他 Linux 发行版也行,但包管理器的命令你得自己调整。

3.2 下载 OP-TEE 源码

OP-TEE 项目用 repo 工具管理多个 Git 仓库。我第一次用的时候也觉得麻烦,但用顺手了就知道——这玩意儿确实适合管理这种多仓库的嵌入式项目。

3.2.1 安装 repo 工具

# 创建 bin 目录并加入 PATH
mkdir -p ~/bin
export PATH=~/bin:$PATH

# 下载 repo 工具
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
小提示: 如果 curl 下载慢,可以用国内镜像源。我一般用 https://mirrors.tuna.tsinghua.edu.cn/git/git-repo,速度快不少。

3.2.2 初始化并同步代码

# 创建工作目录
mkdir op-tee
cd op-tee

# 初始化 repo(以 4.0.0 版本为例)
repo init -u https://github.com/OP-TEE/manifest.git -m qemu_v8.xml -b 4.0.0

# 同步所有仓库(这一步时间较长,建议挂代理)
repo sync -j4

-j4 表示用 4 个线程并行下载。你的 CPU 核心多可以调大,比如 -j8。我曾经在 4 核机器上开 -j16,结果网络连接数太多被服务器限流了……嗯,适可而止就好。

同步完成后,你会看到这些核心组件:

目录/仓库 作用
optee_os/ OP-TEE 内核(安全世界 OS)
optee_client/ REE 端客户端 API 库
optee_examples/ 示例 TA 和 CA 代码
build/ 构建脚本和 Makefile
qemu/ QEMU 模拟器源码
linux/ Linux 内核源码(REE 端)
toolchains/ 交叉编译工具链(自动下载)

3.3 配置交叉编译工具链

说白了,交叉编译就是在 x86 的电脑上编译出 ARM 能跑的程序。OP-TEE 的 build/ 目录里已经集成了工具链的下载脚本,但有时候网络不好会失败。

3.3.1 自动下载(推荐)

cd build
make toolchains

这个命令会下载两个工具链:

  • aarch64-linux-gnu:编译 64 位 ARM 代码(Linux 内核、OP-TEE OS)
  • arm-linux-gnueabihf:编译 32 位 ARM 代码(某些 TA 和裸机程序)

3.3.2 手动配置(备选方案)

如果自动下载失败,别慌。我曾经在断网环境下搞过离线部署,手动指定工具链路径就行:

# 设置环境变量
export CROSS_COMPILE=aarch64-linux-gnu-
export CROSS_COMPILE_TA=aarch64-linux-gnu-

# 或者直接修改 build/Makefile 中的变量
# CROSS_COMPILE ?= /opt/toolchains/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-
注意: 工具链版本要和 OP-TEE 版本匹配。我用 4.0.0 版本时,gcc 10.3 没问题。版本差太多会出现链接错误,比如 undefined reference to __aeabi_* 这类符号找不到的问题。

3.4 编译并运行 OP-TEE

这一步最让人期待——看到终端里刷出 OP-TEE 的启动日志,那种成就感,我到现在还记得。

3.4.1 一键编译

cd build
make -j$(nproc) all

$(nproc) 会自动获取你的 CPU 核心数。第一次编译大概需要 10-20 分钟,取决于机器性能。

编译成功后,你会看到:

  • out/bin/ 目录下生成了 QEMU 启动脚本
  • out/bios-qemu/ 包含引导固件
  • out/rootfs/ 包含根文件系统(内置 OP-TEE 客户端和测试程序)

3.4.2 启动 QEMU 模拟器

# 启动 QEMU(两个终端模式)
make run-only

# 或者使用脚本直接启动
./out/bin/run-qemu.sh

你会看到两个终端窗口:

  • 终端 1(UART0):Linux 内核启动日志,最终进入 shell 提示符 #
  • 终端 2(UART1):OP-TEE 安全世界日志,显示 I/TC: 开头的调试信息

看到类似下面的输出,就说明 OP-TEE 跑起来了:

I/TC: OP-TEE version: 4.0.0 (gcc version 10.3.1 20210621) #1 Tue Jan 10 10:00:00 UTC 2024 aarch64
I/TC: Primary CPU initializing...
I/TC: SMC handler ready
I/TC: Core initialized

3.5 调试环境搭建

跑起来只是第一步。真正开发 TA 的时候,调试才是重头戏。我习惯用 GDB + QEMU 的调试 stub 组合。

3.5.1 启用 QEMU 调试模式

# 在 build 目录下,使用调试模式启动
make run-only DEBUG=1

# 或者手动添加 -s -S 参数
qemu-system-aarch64 \
  -machine virt,secure=on \
  -cpu cortex-a53 \
  -smp 4 \
  -s -S \          # -s 开启 GDB stub(端口 1234),-S 启动时暂停 CPU
  -bios out/bios-qemu/bios.bin \
  ...

3.5.2 连接 GDB 调试器

另开一个终端:

# 启动 GDB,连接 QEMU
aarch64-linux-gnu-gdb \
  -ex "target remote :1234" \
  -ex "symbol-file out/optee_os/core/tee.elf" \
  -ex "break tee_entry_std" \
  -ex "continue"

这里解释一下:

  • target remote :1234:连接到 QEMU 的 GDB stub
  • symbol-file:加载 OP-TEE 内核的符号表,这样才能看到函数名和源码行号
  • break tee_entry_std:在标准调用入口处下断点
调试小技巧: 我经常在 tee_entry_std 和 tee_entry_fast 两个入口下断点。前者对应 CA 调用 TA 的普通请求,后者对应安全监控调用(比如切换世界)。这样能清晰看到 REE 和 TEE 之间的切换过程。

3.5.3 调试 TA 的常用命令

进入 GDB 后,这些命令我几乎每次都用:

命令 作用
info registers 查看所有寄存器状态(特别是 scr_el3 和 spsr_el3)
bt 查看调用栈回溯
list 显示当前断点附近的源码
p/x *(struct tee_ta_session *)0x... 打印 TA 会话结构体内容
monitor system_reset 从 GDB 重启 QEMU(不用退出再启动)
避坑指南: 我曾经在调试时发现断点不生效,折腾了半天才发现是编译时没加 CFG_TEE_CORE_DEBUG=y。这个配置会保留调试符号和优化级别(-O0),否则编译器优化后,源码行号和实际指令对不上。

3.6 验证环境是否正常

环境搭好了,跑个测试验证一下:

# 在 QEMU 的 Linux shell 中执行
# 列出已加载的 TA
tee-supplicant -d

# 运行 OP-TEE 自带的测试套件
xtest

# 运行示例 TA(比如 hello world)
optee_example_hello_world

如果 xtest 全部通过(或者大部分通过),恭喜你——环境搭建成功了!

注意: 有些测试用例需要特定的硬件特性(比如真随机数生成器),在 QEMU 模拟器上可能会跳过或失败。这不影响后续的国密算法开发,放心。

3.7 常见问题与解决方案

我把这些年遇到的高频问题整理了一下:

问题 原因 解决方法
repo sync 卡住或报 443 网络问题,GitHub 被墙 使用代理或国内镜像源
编译报错 arm-linux-gnueabihf-gcc: not found 工具链未下载或路径不对 重新执行 make toolchains
QEMU 启动后黑屏 缺少 secure=on 参数 检查 QEMU 命令行是否包含 -machine virt,secure=on
GDB 连接不上 QEMU 端口被占用或 QEMU 未加 -s 参数 检查端口 1234 是否被占用,或改用 -gdb tcp::1234
xtest 报 TEEC_ERROR_NOT_SUPPORTED 某些 TA 特性在 QEMU 上不支持 忽略该测试,或检查 CFG_* 配置是否开启