3. OP-TEE 启动与运行流程
OP-TEE 并不是一个孤立运行的程序,它依赖从芯片上电到富操作系统(REE)启动的完整信任链。理解它的启动与运行流程,是后续分析共享内存与性能优化的前提。本章围绕安全启动、BL32 加载、TA 与 CA 通信模型、会话建立与命令调用流程展开,帮助读者建立从"上电"到"一次 TA 命令执行完成"的全局视图。
一、安全启动与信任链
安全启动的核心思想是:每一级固件在加载下一级之前,先验证其签名或哈希,验证通过才移交执行权。这样,任何一级被篡改都会导致启动中断,从而保证最终运行在安全世界中的 OP-TEE 内核是可信的。
典型 ARMv8-A 平台的启动链如下:
- BL1(Boot ROM):芯片内固化代码,验证 BL2 的签名,是信任根(Root of Trust)。
- BL2(Trusted Boot Firmware):初始化 DDR 等基础硬件,加载并验证 BL31、BL32、BL33。
- BL31(EL3 Runtime):常驻安全监控(Secure Monitor),负责 SMC 调用转发与安全世界/非安全世界切换。
- BL32(OP-TEE OS):运行在 Secure EL1,即 TEE 内核本体。
- BL33(U-Boot / UEFI):非安全世界引导程序,最终拉起 Linux 内核。
二、BL32 加载与 OP-TEE 初始化
BL32 通常以 tee.bin 或 tee-raw.bin 形式存在,由 BL2 加载到安全内存区域。加载后,OP-TEE 内核依次完成:
- 设置异常向量表与 MMU,建立安全世界地址映射;
- 初始化 GIC、串口、定时器等平台驱动;
- 初始化线程与栈,准备处理来自非安全世界的 SMC;
- 加载并验证内置 TA(Early TA / Pseudo TA);
- 进入等待循环,通过 SMC 与 BL31 交互。
在 Linux 侧,OP-TEE 驱动通过 optee 节点与 BL32 通信,设备树中常见配置如下:
firmware {
optee {
compatible = "linaro,optee-tz";
method = "smc";
};
};
当 Linux 启动 optee 驱动时,会通过 SMC 向 BL32 发起握手,获取版本、共享内存配置等信息,随后注册字符设备 /dev/tee0 与 /dev/teepriv0,供用户态 CA 使用。
三、TA 与 CA 通信模型
OP-TEE 的通信模型由两个角色构成:
- CA(Client Application):运行在 Linux 用户态,通过
libteec调用 TEE 接口。 - TA(Trusted Application):运行在 OP-TEE 安全世界,处理具体安全逻辑。
两者之间不能直接访问对方内存,所有交互都通过共享内存与 SMC 完成。CA 调用 TEEC_InvokeCommand 后,请求经 libteec → 内核 optee 驱动 → SMC → BL31 → BL32,最终由 OP-TEE 调度到目标 TA。TA 执行完成后,结果沿原路径返回。
四、会话建立与命令调用流程
一次完整的 TA 调用通常包含"打开会话—调用命令—关闭会话"三个阶段。以 CA 侧代码为例:
TEEC_Context ctx;
TEEC_Session sess;
TEEC_Operation op;
uint32_t err;
TEEC_InitializeContext(NULL, &ctx);
TEEC_OpenSession(&ctx, &sess, &uuid,
TEEC_LOGIN_PUBLIC, NULL, NULL, &err);
memset(&op, 0, sizeof(op));
op.paramTypes = TEEC_PARAM_TYPES(
TEEC_MEMREF_TEMP_INPUT, TEEC_NONE,
TEEC_NONE, TEEC_NONE);
op.params[0].tmpref.buffer = input;
op.params[0].tmpref.size = len;
TEEC_InvokeCommand(&sess, CMD_PROCESS, &op, &err);
TEEC_CloseSession(&sess);
TEEC_FinalizeContext(&ctx);
对应的 TA 侧入口为:
TEE_Result TA_InvokeCommandEntryPoint(
void *sess_ctx, uint32_t cmd_id,
uint32_t param_types, TEE_Param params[4])
{
switch (cmd_id) {
case CMD_PROCESS:
return process_data(params);
default:
return TEE_ERROR_BAD_PARAMETERS;
}
}
整个流程可归纳为下表:
| 阶段 | CA 侧动作 | TEE 侧动作 | 关键接口 |
|---|---|---|---|
| 初始化 | 初始化上下文 | 驱动握手,注册设备 | TEEC_InitializeContext |
| 打开会话 | 指定 TA UUID 发起连接 | 加载/查找 TA,创建会话 | TEEC_OpenSession |
| 调用命令 | 填充参数并触发调用 | 分发到 TA 命令入口 | TEEC_InvokeCommand |
| 关闭会话 | 释放会话资源 | 销毁会话上下文 | TEEC_CloseSession |
| 清理 | 释放上下文 | 驱动资源回收 | TEEC_FinalizeContext |
五、典型场景与常见误区
场景:一个安全支付 CA 需要向 TA 发送交易数据并获取签名结果。CA 通过 TEEC_MEMREF_TEMP_INPUT 传入明文,TA 在安全世界内完成密钥运算,返回签名。整个过程中,密钥始终不出安全世界,REE 侧只能看到密文与签名结果。