整体流程说明我们实现一个最简单的安全世界加法运算示例Linux应用层传入两个整数安全世界TA完成加法后返回结果验证从CA正常世界应用到TA安全世界可信应用的完整链路打通。整体分为5大步骤宿主机准备OP-TEE开发环境编译依赖库与工具编写并编译安全世界TA编写并编译正常世界CA应用将所有文件部署到QEMU根文件系统目标系统运行测试验证链路步骤1宿主机准备开发环境你需要先准备好aarch64交叉编译工具链以及OP-TEE的客户端库和TA开发套件。1.1 确认交叉编译器确保本地有aarch64-linux-gnu交叉工具链执行aarch64-linux-gnu-gcc -v能输出版本信息即可没有的话先安装sudo apt install gcc-aarch64-linux-gnu1.2 编译optee_clientoptee_client提供正常世界CA依赖的libteec.so库、头文件以及负责加载TA的tee-supplicant守护进程。如果还没有源码先克隆并切换到和你OP-TEE匹配的版本git clone https://github.com/OP-TEE/optee_client.git cd optee_client git checkout 4.10.0交叉编译export CROSS_COMPILEaarch64-linux-gnu- export ARCHarm64 make修改 Makefile WITH_TEEACL ? 0 或者 make CROSS_COMPILEaarch64-linux-gnu- ARCHarm64 WITH_TEEACL0编译完成后关键产物out/arm64/export/usr/lib/libteec.soCA依赖的动态库out/arm64/export/usr/include/CA需要的TEEC头文件out/arm64/export/usr/sbin/tee-supplicantTA文件加载守护进程1.3 导出TA开发套件TA的编译依赖optee_os提供的开发工具链从你之前编译的optee_os源码中导出# 进入你的optee_os源码目录 cd optee_os # 导出ARM64架构的TA开发套件 make CROSS_COMPILEaarch64-linux-gnu- PLATFORMvexpress-qemu_armv8a ta_dev_kit make PLATFORMvexpress-qemu_armv8a ARCHarm CFG_ARM64_corey CROSS_COMPILE64aarch64-linux-gnu- ta_dev_kit -j32原因是ARM64 32的交叉编译工具不一样make PLATFORMvexpress-qemu_armv8a \ CROSS_COMPILEarm-linux-gnueabihf- \ CROSS_COMPILE64aarch64-linux-gnu- \ ARCHarm \ CFG_ARM64_corey \ -j32包含TA编译需要的头文件、链接脚本、签名工具等。步骤2编写并编译安全世界TA创建独立的TA工程目录ta_example包含3个核心文件。2.1 定义TA唯一UUID每个TA有专属UUIDCA通过这个UUID匹配并打开对应TA。生成一个随机UUIDuuidgen # 示例输出12345678-1234-1234-1234-123456789abc下文以该UUID为例实际使用请替换为你生成的值。2.2 TA核心源码文件1ta_entry.cTA业务逻辑实现TA生命周期入口和命令处理这里实现加法运算命令#include tee_internal_api.h #include tee_internal_api_extensions.h /* TA UUID必须和CA完全一致 */ #define TA_EXAMPLE_UUID \ { 0x12345678, 0x1234, 0x1234, \ { 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc } } /* 命令ID加法操作 */ #define CMD_ADD 0 /* TA被创建时调用 */ TEE_Result TA_CreateEntryPoint(void) { return TEE_SUCCESS; } /* TA被销毁时调用 */ void TA_DestroyEntryPoint(void) { } /* CA打开会话时调用 */ TEE_Result TA_OpenSessionEntryPoint(uint32_t param_types, TEE_Param params[4], void **session_context) { (void)param_types; (void)params; (void)session_context; return TEE_SUCCESS; } /* CA关闭会话时调用 */ void TA_CloseSessionEntryPoint(void *session_context) { (void)session_context; } /* 处理CA发来的命令 */ TEE_Result TA_InvokeCommandEntryPoint(void *session_context, uint32_t cmd_id, uint32_t param_types, TEE_Param params[4]) { (void)session_context; /* 校验参数格式2个输入值 1个输出值 */ if (param_types ! TEE_PARAM_TYPES( TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_VALUE_OUTPUT, TEE_PARAM_TYPE_NONE)) { return TEE_ERROR_BAD_PARAMETERS; } switch (cmd_id) { case CMD_ADD: /* 安全世界执行加法结果写入输出参数 */ params[2].value.a params[0].value.a params[1].value.a; return TEE_SUCCESS; default: return TEE_ERROR_NOT_SUPPORTED; } }文件2新建配置头文件user_ta_header_defines.h在ta_demo目录下新建这个文件填入 TA 的所有配置宏#ifndef USER_TA_HEADER_DEFINES_H #define USER_TA_HEADER_DEFINES_H /* TA UUID必须和CA端完全一致 */ #define TA_UUID { 0x12345678, 0x1234, 0x1234, \ { 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc } } /* TA运行属性用户态、DDR中执行 */ #define TA_FLAGS (TA_FLAG_USER_MODE | TA_FLAG_EXEC_DDR) /* TA栈大小默认2KB足够基础功能 */ #define TA_STACK_SIZE (2 * 1024) /* TA数据段大小 */ #define TA_DATA_SIZE (32 * 1024) #endif /* USER_TA_HEADER_DEFINES_H */文件3MakefileTA编译脚本注意修改TA_DEV_KIT_DIR为你实际的TA开发套件路径。# 替换为你的optee_os导出TA套件的实际路径 TA_DEV_KIT_DIR : ../optee_os/out/arm-plat-vexpress/export-ta_arm64 CROSS_COMPILE : aarch64-linux-gnu- BINARY : example_ta # 引入OP-TEE标准TA编译规则 include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk新建sub.mkta_demo/sub.mksrcs-y ta_entry.c2.3编译并手动签名make python3 ../optee_os/scripts/sign_encrypt.py sign-enc \ --uuid 12345678-1234-1234-1234-123456789abc \ --in example_ta.stripped.elf \ --out example_ta.ta \ --key /home/wythe/qemu/sec/optee_os/keys/default_ta.pem编译完成后 目录下会生成example_ta.ta这是签名后的最终TA镜像可直接放到目标系统加载。步骤3编写并编译正常世界CA应用创建CA工程目录ca_example实现Linux用户态调用逻辑。3.1 CA源码main.c通过libteec库完成「初始化上下文→打开会话→调用命令→关闭会话」全流程#include stdio.h #include stdlib.h #include string.h #include tee_client_api.h /* 与TA完全一致的UUID */ #define TA_EXAMPLE_UUID \ { 0x12345678, 0x1234, 0x1234, \ { 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc } } #define CMD_ADD 0 int main(void) { TEEC_Result res; TEEC_Context ctx; TEEC_Session sess; TEEC_Operation op; TEEC_UUID uuid TA_EXAMPLE_UUID; uint32_t err_origin; /* 1. 初始化TEE上下文打开/dev/tee0设备 */ res TEEC_InitializeContext(NULL, ctx); if (res ! TEEC_SUCCESS) { printf(初始化TEE失败错误码: 0x%x\n, res); return 1; } /* 2. 打开与目标TA的会话 */ memset(op, 0, sizeof(op)); op.paramTypes TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE); res TEEC_OpenSession(ctx, sess, uuid, TEEC_LOGIN_PUBLIC, NULL, op, err_origin); if (res ! TEEC_SUCCESS) { printf(打开TA会话失败错误码: 0x%x, 错误来源: %d\n, res, err_origin); TEEC_FinalizeContext(ctx); return 1; } printf(成功与安全世界TA建立会话\n); /* 3. 调用加法命令计算 123 456 */ memset(op, 0, sizeof(op)); op.paramTypes TEEC_PARAM_TYPES( TEEC_VALUE_INPUT, /* 参数0输入整数a */ TEEC_VALUE_INPUT, /* 参数1输入整数b */ TEEC_VALUE_OUTPUT, /* 参数2输出计算结果 */ TEEC_NONE); op.params[0].value.a 123; op.params[1].value.a 456; res TEEC_InvokeCommand(sess, CMD_ADD, op, err_origin); if (res ! TEEC_SUCCESS) { printf(调用TA命令失败错误码: 0x%x, 错误来源: %d\n, res, err_origin); goto exit; } printf(安全世界计算结果: %d %d %d\n, op.params[0].value.a, op.params[1].value.a, op.params[2].value.a); exit: /* 4. 关闭会话、释放上下文 */ TEEC_CloseSession(sess); TEEC_FinalizeContext(ctx); return 0; }3.2 交叉编译CA执行以下命令注意替换头文件和库路径为你optee_client的实际导出路径aarch64-linux-gnu-gcc main.c -o ca_example \ -I../optee_client/out/arm64/export/usr/include \ -L../optee_client/out/arm64/export/usr/lib \ -lteec -Wall编译完成后生成ca_example可执行文件。步骤4部署到QEMU根文件系统你的根文件系统在bootdisk.img中直接在宿主机挂载后写入文件即可。4.1 挂载磁盘镜像mount bootdisk.img rootfs_mnt4.2 复制所有文件到对应目录#切换到root用户 mkdir -p rootfs_mnt/lib # 1. 复制动态库libteec.so cp ../optee_client/out/arm64/export/usr//lib/libteec.so rootfs_mnt/lib/ ln -s libteec.so rootfs_mnt/lib/libteec.so.0 # 2. 复制tee-supplicant守护进程 cp ../optee_client/out/arm64/export/usr/sbin/tee-supplicant rootfs_mnt/sbin/ chmod x rootfs_mnt/sbin/tee-supplicant # 3. 创建TA存储目录放入TA文件OP-TEE默认搜索路径 mkdir -p rootfs_mnt/lib/optee_armtz/ cp ../ta_demo/example_ta.ta rootfs_mnt/lib/optee_armtz/ # 4. 复制CA可执行文件 cp ../ca_example/ca_example rootfs_mnt/root/ chmod x rootfs_mnt/root/ca_example4.3 卸载磁盘镜像umount rootfs_mnt步骤5目标系统运行测试检查所有的运行程序以及so都打包进去5.1 启动tee-supplicantTA文件的加载依赖这个守护进程先后台运行无法启动安装各种libc库mount bootdisk.img rootfs_mnt/ cp -a /usr/aarch64-linux-gnu/lib/ld-linux-aarch64.so.1 rootfs_mnt/lib/ cp -a /usr/aarch64-linux-gnu/lib/libc.so.6 rootfs_mnt/lib/ cp -a /usr/aarch64-linux-gnu/lib/libpthread.so.0 rootfs_mnt/lib/ cp -a /usr/aarch64-linux-gnu/lib/libm.so.6 rootfs_mnt/lib/ cp -a /usr/aarch64-linux-gnu/lib/libdl.so.2 rootfs_mnt/lib/ cp -a /usr/aarch64-linux-gnu/lib/librt.so.1 rootfs_mnt/lib/ cp -a /usr/aarch64-linux-gnu/lib/libresolv.so.2 rootfs_mnt/lib/启动成功5.2 运行CA程序#监听端口 54320 nc localhost 54320需要修改cd /lib/optee_armtz将自定义文件名改为UUID命名的标准格式mv example_ta.ta 12345678-1234-1234-1234-123456789abc.ta cd /root ./ca_example执行成功预期输出成功与安全世界TA建立会话 安全世界计算结果: 123 456 579出现该输出代表Linux应用层 → 内核OP-TEE驱动 → SMC安全调用 → OP-TEE安全世界 → TA的完整链路完全打通。常见问题排查打开会话返回 0xffff0008TA文件未找到检查/lib/optee_armtz/目录下是否存在.ta文件文件名是否正确。初始化上下文失败检查/dev/tee0设备节点是否存在内核OP-TEE驱动是否正常加载。打开会话返回 0xffff3024TA签名校验失败确认编译TA的签名密钥和OP-TEE内核配置的密钥一致。