3. OP-TEE系统架构
要真正理解 OP-TEE Trusted Application 的开发方式,必须先建立一张清晰的系统架构图。OP-TEE 并不是一个孤立的库,而是一套横跨两个执行世界、多个软件层次的完整可信执行环境。它的核心思想是:把敏感逻辑放进 Secure World,把普通业务留在 Normal World,两者通过受控的通信通道协作。只有理解了这条链路上每一层的职责,才能写出正确的 TA 与 CA。
一、双世界架构:Normal World 与 Secure World
ARM TrustZone 把 CPU 划分为两个安全状态:Normal World(非安全世界)和 Secure World(安全世界)。Normal World 运行 Linux 等通用操作系统,负责 UI、网络、存储等普通业务;Secure World 运行 OP-TEE OS,负责密钥管理、加解密、身份认证等敏感操作。两者物理上共享同一颗 CPU,但通过 TrustZone 硬件隔离,Normal World 无法直接读取 Secure World 的内存。
两个世界之间的切换由 SMC(Secure Monitor Call)指令触发,经过 EL3 的 Secure Monitor 完成上下文保存与状态切换。这意味着一次 TA 调用并不是普通函数调用,而是一次跨越安全边界的“世界切换”,其开销远高于普通系统调用,这也是 TA 设计要尽量减少跨世界往返次数的原因。
二、OP-TEE 的软件分层
从下到上,OP-TEE 的软件栈可以划分为几个关键层次,每一层都有明确的职责边界:
- OP-TEE OS(Secure World 内核):运行在 Secure EL1,负责 TA 的加载、调度、内存隔离、系统调用处理,以及密码学原语、安全存储等核心服务。
- TEE Supplicant(Normal World 用户态守护进程):运行在 Linux 用户态,代替 Secure World 完成它无法直接做的文件系统操作,例如加载 TA 二进制、读写安全存储文件。
- Linux 内核驱动(optee.ko):提供
/dev/tee0与/dev/teepriv0设备节点,负责 SMC 调用、共享内存管理以及和 TEE Supplicant 的 RPC 交互。 - 用户态库(libteec / optee_client):为 CA 提供
TEEC_InitializeContext、TEEC_OpenSession、TEEC_InvokeCommand等标准 API。 - CA 与 TA:CA 是 Normal World 的客户端应用,TA 是 Secure World 中真正执行敏感逻辑的可信应用。
三、通信机制与调用流程
一次完整的 TA 调用,数据流大致如下:CA 调用 libteec 的 TEEC_InvokeCommand,libteec 通过 ioctl 进入 Linux 内核驱动;驱动准备共享内存并执行 SMC 陷入 Secure World;OP-TEE OS 根据 session 找到目标 TA,把参数映射进 TA 地址空间并调用对应 command;TA 执行完毕后原路返回结果。若 TA 中途需要文件操作,则触发 RPC,由驱动通知 TEE Supplicant 处理,处理完再回到 Secure World 继续执行。
图中可以清楚看到:Normal World 与 Secure World 之间只有两条主要通道——向下的 SMC 调用和向上的 RPC 请求。CA 与 TA 之间并不存在直接内存共享,所有参数都通过共享内存加描述符的方式传递。
四、典型场景:一次安全存储写入
假设 TA 需要把用户密钥写入安全存储,流程如下:
- CA 调用
TEEC_InvokeCommand,请求写入密钥。 - libteec 通过 ioctl 进入 optee.ko,驱动执行 SMC 切换到 Secure World。
- OP-TEE OS 调度目标 TA,TA 调用 TEE Core API 加密密钥。
- TA 需要落盘,触发 RPC;OP-TEE OS 通过驱动通知 TEE Supplicant。
- TEE Supplicant 在 Linux 文件系统中写入加密后的数据文件。
- 结果回传 TA,TA 返回成功,CA 收到返回值。
CA: TEEC_InvokeCommand(session, CMD_STORE_KEY, &op, &err)
-> libteec: ioctl(/dev/tee0, IOCTL_INVOKE)
-> optee.ko: smc(OPTEE_SMC_CALL_WITH_ARG)
-> OP-TEE OS: TA_InvokeCommandEntryPoint(CMD_STORE_KEY)
-> TA: TEE_WriteObjectData() -> RPC -> Supplicant -> 文件系统
-> 返回 TEEC_SUCCESS
五、常见误区与复盘
open()、read() 等 Linux 系统调用。实际上 TA 运行在 Secure World,没有 Linux 系统调用接口,必须通过 RPC 委托 TEE Supplicant 完成文件操作。
复盘来看,理解 OP-TEE 架构的关键在于抓住三条线:世界边界(Normal 与 Secure 的隔离)、调用路径(CA → libteec → 驱动 → SMC → OP-TEE OS → TA)、RPC 回环(TA → OP-TEE OS → 驱动 → Supplicant → 文件系统)。开发 TA 时,凡是涉及资源访问的设计,都要先问一句:这件事应该由 Secure World 做,还是必须委托 Normal World 做?想清楚这一点,TA 的接口划分和命令设计就会自然清晰。
| 层次 | 运行世界 | 核心职责 | 典型接口/文件 |
|---|---|---|---|
| CA 客户端 | Normal World 用户态 | 发起会话与命令调用 | TEEC_* API |
| libteec | Normal World 用户态 | 封装 ioctl 与共享内存 | libteec.so |
| Linux 驱动 | Normal World 内核态 | SMC 调用、RPC 转发 | optee.ko、/dev/tee0 |
| TEE Supplicant | Normal World 用户态 | 加载 TA、安全存储落盘 | tee-supplicant |
| OP-TEE OS | Secure World | TA 调度、隔离、系统服务 | tee_core、TEE Core API |
| TA | Secure World | 执行敏感业务逻辑 | TA_InvokeCommandEntryPoint |
掌握这张分层表,就等于掌握了 OP-TEE 的“地图”。后续开发 TA 时,无论是配置交叉编译、定义命令 ID,还是排查调用失败,都可以回到这张地图上定位问题发生在哪一层、属于哪个世界。