3. TEE开发环境搭建:QEMU模拟器搭建、OP-TEE源码编译、Linux内核与TEE驱动配置

说实话,做TEE开发最头疼的就是硬件板子还没回来,代码已经写好了。这时候怎么办?靠模拟器。

我个人习惯在开发初期先用QEMU把整个环境跑通。你想想看,等硬件回来再调驱动,那得多耽误事。这一章我就带你搭一套完整的OP-TEE + QEMU开发环境。包括模拟器搭建、源码编译、内核和驱动配置。每一步我都会把踩过的坑指出来。

本章目标:在x86主机上通过QEMU模拟ARM64平台,运行完整的OP-TEE + Linux系统。最终能启动到Linux shell,并验证TEE驱动加载成功。

3.1 环境概览与依赖安装

先看看整体架构。QEMU模拟一个ARM64开发板,上面跑两个世界:

OP-TEE + QEMU 开发环境架构 主机(x86_64 Linux) QEMU + 交叉编译工具链 + OP-TEE Build System QEMU 模拟 ARM64 平台(Cortex-A57) 内存:2GB | 4核 | GICv3 | UART 安全世界(Secure World) OP-TEE OS 安全存储 | 密码学服务 | TA S-EL1 / S-EL0 非安全世界(Normal World) Linux Kernel + OP-TEE 驱动 CA(Client Application) EL1 / EL0

嗯,这张图你得记住。后面所有配置都是围绕这个结构展开的。

先装依赖。我用的是Ubuntu 22.04,其他发行版也差不多。

# 基础工具
sudo apt update
sudo apt install -y \
    git wget curl \
    build-essential \
    python3 python3-pip \
    device-tree-compiler \
    flex bison \
    libssl-dev \
    libncurses-dev \
    xterm

# QEMU(要支持ARM64)
sudo apt install -y qemu-system-arm

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

# 验证
aarch64-linux-gnu-gcc --version
qemu-system-aarch64 --version

我的经验:千万别用系统自带的旧版QEMU。我踩过坑,旧版QEMU对GICv3支持有问题,OP-TEE启动会卡死。建议从源码编译QEMU 7.2+,或者用OP-TEE官方推荐的版本。

3.2 获取OP-TEE源码与构建系统

OP-TEE官方提供了一个repo清单,能把所有组件一次性拉下来。我个人习惯用这个方式,省得一个个找版本匹配。

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

# 创建工作目录
mkdir -p ~/optee
cd ~/optee

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

# 同步源码(这一步比较久,建议挂代理)
repo sync -j$(nproc)

同步完成后,目录结构是这样的:

目录/文件 说明
optee_os/ OP-TEE 内核(安全世界OS)
linux/ Linux内核源码(含OP-TEE驱动)
build/ 构建脚本和Makefile
out/ 编译输出目录
toolchains/ 交叉编译工具链(自动下载)
qemu_v8.mk QEMU v8平台的顶层Makefile

注意:repo sync可能会因为网络问题失败。我建议用repo sync --fail-fast,这样失败后能快速定位是哪个仓库的问题。如果某个仓库反复失败,手动git clone也行。

3.3 编译OP-TEE与Linux内核

编译过程其实很简单。OP-TEE的构建系统已经帮你配好了所有依赖。你只需要执行一条命令。

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

这条命令会依次做以下几件事:

  1. 编译OP-TEE OS(生成tee-pager_v2.bin)
  2. 编译Linux内核(生成Image)
  3. 编译设备树(生成qemu_arm64.dtb)
  4. 编译U-Boot(引导加载程序)
  5. 生成根文件系统(基于Buildroot)

我第一次编译时等了大概40分钟。如果你机器性能好,20分钟也能搞定。

关键输出文件:

  • out/bin/tee-pager_v2.bin — OP-TEE OS镜像
  • out/bin/Image — Linux内核镜像
  • out/bin/qemu_arm64.dtb — 设备树
  • out-br/images/rootfs.cpio.gz — 根文件系统

3.4 Linux内核与TEE驱动配置

这里我要重点说一下。OP-TEE驱动默认是编译进内核的,但有时候你改了内核配置,驱动可能没打开。我曾经遇到过这个问题,折腾了半天才发现是驱动没编译进去。

检查内核配置:

cd ~/optee/linux
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

确保以下选项开启:

配置项 路径 值
CONFIG_OPTEE Device Drivers → TEE → OP-TEE y(编译进内核)
CONFIG_OPTEE_SHM_NUM_PRIV_PAGES 同上 1(默认即可)
CONFIG_TEE Device Drivers → TEE y
CONFIG_ARM_SMCCC Kernel Features → ARM SMC Calling Convention y

保存配置后,重新编译内核:

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

避坑指南:我曾经把OP-TEE驱动编译成模块(m),结果启动后忘了加载模块,CA调用TEE接口直接返回-ENODEV。建议你直接编译进内核,省心。

3.5 启动QEMU并验证

编译完成后,启动QEMU:

cd ~/optee/build
make run QEMU_V8

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

  • 一个窗口是安全世界的控制台(OP-TEE的日志)
  • 另一个窗口是非安全世界的控制台(Linux shell)

在Linux shell中,验证TEE驱动:

# 检查TEE设备节点
ls -l /dev/tee*
# 应该看到 /dev/tee0 和 /dev/teepriv0

# 检查内核日志
dmesg | grep optee
# 应该看到 "optee: OP-TEE: revision 4.0.0" 之类的信息

# 运行OP-TEE自带的测试
xtest
# 如果所有测试通过,说明环境搭建成功

常见问题:

  • 如果QEMU启动后黑屏,检查终端模拟器是否安装(sudo apt install xterm)
  • 如果/dev/tee0不存在,检查内核配置中OP-TEE驱动是否编译进内核
  • 如果xtest报错,检查OP-TEE OS版本和Linux内核版本是否匹配

3.6 我的调试小技巧

最后分享几个我常用的调试方法:

  • 加日志:在OP-TEE OS源码的core/arch/arm/kernel/下加DMSG()打印,重新编译就能看到安全世界的调试信息。
  • GDB调试:QEMU支持GDB连接。启动时加-s -S参数,然后在另一个终端用aarch64-linux-gnu-gdb vmlinux连接。
  • 抓包SMC调用:在OP-TEE OS的core/arch/arm/sm/下加日志,能看到每次安全调用的参数。

嗯,环境搭建这部分就到这里。你跟着步骤走,应该能顺利跑起来。如果卡住了,回头检查一下依赖版本和内核配置。这些东西我当初也调了好几天,别着急。