第2章:OP-TEE源码结构——源码目录分析、核心组件介绍、构建系统解析、编译流程
好,咱们直接进入正题。上一章我们把OP-TEE的宏观概念聊清楚了,这一章我带你钻进它的肚子里,看看源码到底是怎么组织的。说实话,我第一次接触OP-TEE源码时,也被那一堆文件夹搞得有点懵。但摸清楚规律后,你会发现它的结构其实非常清晰。
2.1 源码目录分析
OP-TEE的源码托管在GitHub上,项目名叫optee_os。你把它clone下来后,顶层目录大概长这样:
optee_os/
├── core/ # 核心代码,TEE内核
├── lib/ # 库文件,密码学、内存管理等
├── mk/ # 构建系统的Makefile片段
├── out/ # 编译输出目录
├── scripts/ # 辅助脚本
├── ta/ # Trusted Application示例
├── documentation/ # 文档
└── keys/ # 签名密钥
嗯,这里我要重点说说core/目录。它才是OP-TEE的心脏。我当年调试一个内存隔离的bug,就是在core/arch/arm/下面翻了好几天。
core/的子目录结构:
- arch/:架构相关代码,ARMv7、ARMv8都在这里。你想想看,不同CPU的页表、异常处理都不一样,这部分就是做硬件适配的。
- kernel/:TEE内核的核心逻辑,包括线程管理、IPC、系统调用。说白了,这就是TEE里的“操作系统”。
- mm/:内存管理。我遇到过最头疼的问题就是这里——页表配置错了,导致安全世界和非安全世界的内存互相泄露。
- tee/:TEE核心服务,比如TEE_OpenSession、TEE_InvokeCommand这些API的实现。
- drivers/:外设驱动,比如UART、SPI、RNG(随机数生成器)。
个人经验:如果你要移植OP-TEE到新平台,core/arch/arm/plat-xxxx/这个目录是你最先要看的。每个平台都有自己的板级初始化代码,我习惯先从这里入手,把串口调通,后面调试就方便多了。
2.2 核心组件介绍
OP-TEE不是一个大泥球,它由几个关键组件拼起来的。我画了一张图,帮你理清它们的关系:
这张图里,我标出了几个关键组件:
- CA(Client Application):跑在Linux里的普通应用,比如你的手机支付App。它通过TEE Client API发起请求。
- libteec:TEE Client API的实现库。CA调用它,它再通过Linux驱动和TEE通信。
- OP-TEE Linux驱动:负责在REE和TEE之间传递消息。我调试时经常在这里加打印,看SMC调用是否成功。
- TA(Trusted Application):跑在TEE里的安全应用,比如指纹比对、密钥管理。TA通过TEE Internal API使用TEE内核的服务。
- OP-TEE内核:就是前面说的
core/目录,提供内存隔离、密码学、安全存储等基础能力。
避坑指南:我曾经以为TA和CA是直接通信的,后来才发现它们之间隔了好几层。每次调用都要经过:CA → libteec → 驱动 → SMC → TEE内核 → TA。这个路径上的任何一环出问题,调用就会失败。所以调试时,建议从驱动层开始排查。
2.3 构建系统解析
OP-TEE用的是自己那套基于Makefile的构建系统。说实话,我第一次看mk/目录下的文件时,头都大了。但用久了你会发现,它其实很灵活。
构建系统的核心文件:
| 文件/目录 | 作用 |
|---|---|
Makefile |
顶层Makefile,入口文件 |
mk/ |
构建规则片段,按功能拆分 |
mk/config.mk |
全局配置选项,比如是否开启调试 |
core/core.mk |
核心模块的构建规则 |
ta/ta.mk |
TA的构建规则 |
你想想看,为什么OP-TEE不用CMake或者Kbuild?我个人觉得,Makefile的好处是依赖关系清晰,而且嵌入式环境里Makefile的兼容性最好。你总不能在裸机上跑Python吧?
构建系统的关键变量:
# 平台配置
PLATFORM ?= vexpress-qemu_v8a
PLATFORM_FLAVOR ?= qemu_virt
# 调试选项
CFG_TEE_CORE_DEBUG ?= y
CFG_TEE_TA_LOG_LEVEL ?= 3
# 内存配置
CFG_TZDRAM_START ?= 0x0e000000
CFG_TZDRAM_SIZE ?= 0x02000000
嗯,这里要注意CFG_开头的变量。它们是OP-TEE的配置开关,几乎每个功能都可以通过它来控制。我习惯在mk/config.mk里先搜一遍,看看有哪些选项可用。
2.4 编译流程
编译OP-TEE,说白了就是三步走:配置、编译、打包。但每一步里都有不少门道。
第一步:配置
运行make menuconfig或者直接设置环境变量。我个人更喜欢直接写变量,因为可以脚本化:
make PLATFORM=vexpress-qemu_v8a \
CFG_TEE_CORE_DEBUG=y \
CFG_TEE_TA_LOG_LEVEL=4 \
O=out
第二步:编译
直接make就行。编译过程大致是:
- 先编译工具链相关的头文件检查
- 然后编译
lib/目录下的库文件 - 接着编译
core/目录下的内核代码 - 最后编译
ta/目录下的示例TA - 链接生成最终的
tee.bin或tee.elf
注意:我第一次编译时,卡在了链接阶段。后来发现是内存布局文件core/arch/arm/plat-xxxx/platform_config.h里的地址配置错了。TEE的基地址必须和硬件设计一致,否则跑不起来。
第三步:打包
编译完成后,out/目录下会生成:
tee.bin:纯二进制镜像,可以直接烧录tee.elf:带符号表的镜像,用于调试tee.dump:反汇编文件,我经常用它来查问题ta/:编译好的TA文件,后缀是.ta
如果你用的是QEMU模拟器,还需要把tee.bin和Linux内核、设备树打包到一起。这个流程在OP-TEE的build/仓库里有脚本,我建议你直接用现成的。
我的习惯:每次编译前,我都会先make clean一下,避免旧文件干扰。然后加上CFG_TEE_CORE_DEBUG=y,这样出错了能直接看到堆栈。等调试完了,再关掉调试选项,编译release版本。
好了,这一章我们把OP-TEE的源码结构、核心组件、构建系统和编译流程都过了一遍。说白了,源码结构就是告诉你“东西在哪”,核心组件告诉你“谁负责什么”,构建系统告诉你“怎么配”,编译流程告诉你“怎么跑”。把这四块搞明白,你就能在OP-TEE的代码里自由穿梭了。
可可精品资料库