3. TEE开发环境搭建:基于QEMU的ARM TrustZone模拟器搭建、OP-TEE源码编译与部署

说实话,很多初学者一上来就买开发板,结果发现调试起来特别麻烦。我个人习惯先用模拟器把环境跑通,再上真板子。这样效率高,而且能省不少钱。

这一章,我们就来搞定基于QEMU的ARM TrustZone模拟器,再把OP-TEE的源码编译部署上去。你跟着我走一遍,大概两个小时就能看到一个跑起来的TEE环境。

3.1 为什么选QEMU?

QEMU能模拟完整的ARMv8-A平台,包括GIC、UART、定时器这些外设。最关键的是,它支持TrustZone扩展。这意味着你可以在普通Linux里跑一个完整的TEE系统,而不需要买硬件。

我在项目里遇到过一种情况:客户要求快速验证一个安全存储方案,但开发板还在采购流程里。当时就是用QEMU搭的环境,提前两周完成了原型验证。嗯,这个选择后来被证明非常正确。

核心优势:

  • 零硬件成本,一台笔记本就够了
  • 调试方便,GDB直接连上去
  • 快照功能,出错了随时回滚
  • 支持多核模拟,接近真实硬件行为

3.2 环境准备

先看看你的机器。我建议用Ubuntu 20.04或22.04 LTS,64位系统。其他发行版也行,但依赖包的名字可能不一样,你得自己查一下。

需要安装的依赖包不少,我列个清单:

sudo apt-get update
sudo apt-get install -y \
    git \
    wget \
    make \
    gcc \
    g++ \
    python3 \
    python3-pip \
    device-tree-compiler \
    flex \
    bison \
    libssl-dev \
    libncurses-dev \
    libglib2.0-dev \
    libfdt-dev \
    libpixman-1-dev \
    zlib1g-dev \
    libgmp-dev \
    libmpc-dev \
    libmpfr-dev \
    texinfo \
    cpio \
    rsync \
    unzip \
    bc \
    u-boot-tools \
    android-tools-mkbootimg

小技巧: 如果你用的是Ubuntu 22.04,记得把python改成python3。我一开始没注意,结果编译脚本报错,查了半天才发现是python软链接的问题。

3.3 下载OP-TEE源码

OP-TEE官方提供了一个repo清单文件,能一次性拉取所有组件。包括:

  • optee_os — TEE内核,运行在安全世界
  • optee_client — 普通世界的客户端API库
  • optee_test — 测试用例,验证功能是否正常
  • build — 编译脚本和配置文件
  • linux — 打了补丁的Linux内核
  • qemu — 支持TrustZone的QEMU

拉取命令如下:

mkdir ~/optee
cd ~/optee
repo init -u https://github.com/OP-TEE/manifest.git -m qemu_v8.xml
repo sync -j4

这个过程比较慢,取决于你的网速。我建议用-j4参数,同时拉取4个任务。我曾经试过-j8,结果把公司的出口带宽占满了,被IT部门打电话警告……

注意: repo工具需要先安装。如果提示找不到repo,执行:

sudo apt-get install repo

或者从Google官方源下载:

mkdir ~/bin
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
export PATH=~/bin:$PATH

3.4 编译OP-TEE

源码拉下来之后,进入build目录,直接make就行。但别急,先看看编译选项。

OP-TEE的编译系统基于Makefile,支持多种目标平台。我们用的是qemu_v8,对应ARMv8-A架构的QEMU模拟器。

cd ~/optee/build
make -j$(nproc) QEMU_V8=y

这里有几个关键点:

  • -j$(nproc):用所有CPU核心并行编译,速度最快
  • QEMU_V8=y:指定目标平台为QEMU v8
  • 第一次编译会下载交叉编译工具链,大概几百MB

编译完成后,你会看到类似这样的输出:

Built optee_os
Built optee_client
Built optee_test
Built linux
Built qemu
Built rootfs
Built all targets successfully

我记得第一次编译时,卡在了rootfs生成那一步。后来发现是磁盘空间不够,OP-TEE的根文件系统需要至少2GB空闲空间。所以编译前先检查一下:

df -h ~/optee

3.5 启动QEMU模拟器

编译成功后,启动模拟器只需要一条命令:

cd ~/optee/build
make run-only QEMU_V8=y

你会看到两个终端窗口弹出来:

  • 一个运行普通世界(Normal World)的Linux
  • 一个运行安全世界(Secure World)的OP-TEE

登录普通世界的Linux,用户名root,密码空。然后运行测试用例:

xtest

这个命令会执行所有TEE功能测试。如果一切正常,你会看到一堆绿色的PASS。我建议先跑一个简单的测试:

xtest 1001

这个测试只验证基本的TA加载和调用,跑得很快。

常见问题:

  • QEMU窗口不显示? 检查是否安装了SDL库:sudo apt-get install libsdl2-dev
  • 启动卡在"Waiting for root device"? 重新编译rootfs:make -j$(nproc) rootfs QEMU_V8=y
  • xtest报错"TEEC_ERROR_NOT_SUPPORTED"? 检查OP-TEE内核是否正常启动,看安全世界终端的日志

3.6 整体架构图

下面这张图展示了整个环境的组件关系和启动流程。我画的时候特意把安全世界和普通世界的边界标清楚了。

OP-TEE QEMU 模拟器架构图 普通世界 (Normal World) 安全世界 (Secure World) Linux 内核 (带OP-TEE补丁) optee_client (libteec.so) optee_test (xtest) CA (Client Application) OP-TEE OS (optee_os) TEE Core Framework TA (Trusted Application) Secure Storage QEMU (ARMv8-A + TrustZone 模拟) CA通过libteec.so调用OP-TEE驱动,触发SMC异常进入安全世界,由TEE Core Framework分发给对应的TA处理

3.7 验证环境是否正常

环境跑起来之后,我习惯做几个快速验证:

  1. 检查OP-TEE版本:在安全世界终端输入version,应该显示当前编译的版本号
  2. 查看安全内存:cat /proc/iomem | grep optee,确认安全内存区域已注册
  3. 运行基础测试:xtest 1001,看是否返回TEEC_SUCCESS
  4. 检查日志:dmesg | grep optee,看驱动加载是否正常

调试技巧: 如果想看更详细的日志,可以在编译时开启调试选项:

make -j$(nproc) QEMU_V8=y CFG_TEE_CORE_LOG_LEVEL=4

日志级别从0(无日志)到4(最详细)。我调试时一般用3,信息量适中。

3.8 常见问题与避坑

我整理了几个容易踩的坑,都是我在项目中实际遇到过的:

问题 原因 解决方法
编译报错"undefined reference to ..." 交叉编译工具链版本不匹配 删除toolchain目录,重新make,让脚本自动下载
QEMU启动后黑屏 缺少图形库或显示配置错误 安装libsdl2-dev,或改用-nographic模式
xtest全部FAIL OP-TEE内核未正确加载 检查安全世界终端是否有"OP-TEE"启动信息
repo sync失败 网络问题或GitHub被墙 使用代理,或换用国内镜像源

我曾经在给客户做POC时,现场网络特别差,repo sync反复中断。后来我提前把整个optee目录打包成tar.gz,带到现场直接解压编译,省了不少时间。所以建议你也备份一份完整的源码包。

3.9 下一步做什么?

环境搭好之后,你可以试试自己写一个简单的TA。比如实现一个加法函数,从普通世界传入两个数,在安全世界里计算,再返回结果。这个例子虽然简单,但能帮你理解CA和TA之间的通信流程。

嗯,这一章的内容就到这里。环境搭好了,后面的事情就好办了。