2. TrustZone基础
ARM TrustZone 并不是一颗独立的安全芯片,而是集成在 Cortex-A 与部分 Cortex-M 处理器内部的一套硬件安全扩展。它通过在处理器、总线、内存控制器和外设之间引入一条“安全维度”,把整个 SoC 的运行环境在逻辑上切分为两个世界:安全世界(Secure World)与非安全世界(Normal World)。理解这两个世界的划分方式以及地址空间如何被隔离,是后续在 IoT 设备上做 TrustZone 移植适配的第一块基石。
一、核心原理:一条额外的地址位
TrustZone 的核心思想非常简洁:为系统中每一次内存访问附加一个安全状态标记。在 AMBA AXI/AHB 总线上,这个标记体现为 AWPROT[1] 与 ARPROT[1] 位,业界常称为 NS 位(Non-Secure bit)。当 NS=0 时表示安全访问,NS=1 时表示非安全访问。处理器、DMA 控制器、外设主设备发出的每一笔事务都携带该位,总线互联与内存保护单元据此判断是否放行。
与之配合的是处理器内部的 SCR(Secure Configuration Register) 寄存器中的 NS 位。当 CPU 处于安全世界时 SCR.NS=0,处于非安全世界时 SCR.NS=1。CPU 发出的所有取指、数据访问都会自动带上当前世界的 NS 标记。因此,“世界切换”本质上就是修改 SCR.NS 并跳转到对应入口地址的过程。
二、安全世界与非安全世界的划分
两个世界各自拥有独立的运行环境和资源视图,典型划分如下:
- 非安全世界:运行 Rich OS(Linux、RTOS)与普通应用,负责业务逻辑、网络协议栈、UI 等。它可以看到绝大部分 DRAM、通用外设,但无法访问被标记为安全的区域。
- 安全世界:运行可信执行环境(TEE,如 OP-TEE、Trusted Firmware-A 的 BL32),承载密钥管理、安全启动校验、加解密、身份认证等敏感操作。它拥有独立的栈、堆、中断向量和特权级。
- 监控层(Secure Monitor):运行在 EL3,是两世界之间唯一的合法通道,通过
SMC指令触发,负责上下文保存与切换。
需要强调的是,两个世界共享同一颗 CPU 核心和同一套寄存器物理资源,切换时由监控层保存/恢复上下文。因此安全世界并不是“另一个 CPU”,而是同一 CPU 在另一种安全状态下的执行视图。
三、地址空间隔离机制
地址空间隔离由多个硬件组件协同完成,形成从 CPU 到外设的完整链路:
- TZASC(TrustZone Address Space Controller):连接在 DRAM 控制器前,把物理内存划分为多个区域,每个区域可配置为安全、非安全或两者皆可,并可为非安全访问设置读/写权限。
- TZPC(TrustZone Protection Controller):通过一组可编程信号线控制外设的安全属性,决定某个外设只能被安全世界访问,还是两世界共享。
- MMU 与页表:安全世界与非安全世界使用各自的页表基址(如 TTBR0/TTBR1 配合 SCR.NS),实现虚拟地址到物理地址的独立映射。
- GIC 中断隔离:GIC 支持
Group 0(安全中断,路由到 EL3)与Group 1(非安全中断),并通过FIQ/IRQ分流,防止非安全世界窃听安全中断。
下面这张图展示了从 CPU 到内存与外设的隔离链路,以及 NS 位在其中的传递路径:
四、典型场景:一次安全服务调用
以 IoT 设备向安全世界请求解密一段固件为例,流程如下:
1. 非安全世界应用调用 TEE Client API,触发 SMC 指令
2. CPU 陷入 EL3,Secure Monitor 保存非安全上下文
3. 切换 SCR.NS=0,跳转到安全世界入口
4. 安全世界校验参数、执行解密,结果写入共享内存
5. 再次 SMC 返回 EL3,恢复非安全上下文,SCR.NS=1
6. 非安全世界从共享内存读取结果
整个过程对非安全世界而言是一次“函数调用”,但它无法读取安全世界的代码、密钥或中间状态。共享内存区域必须由 TZASC 显式配置为两世界可访问,否则数据无法传递。
五、常见误区与复盘
| 隔离组件 | 作用对象 | 关键配置 | 失效后果 |
|---|---|---|---|
| TZASC | DRAM 物理区域 | 区域基址、大小、安全属性、读写权限 | 安全内存被非安全世界读写 |
| TZPC | 外设 | 安全/共享/非安全信号线 | 密钥外设被普通应用访问 |
| GIC | 中断 | Group 0 / Group 1 分组 | 安全中断被非安全世界截获 |
| MMU + SCR.NS | 虚拟地址映射 | 页表基址、NS 位 | 地址空间越界或映射混乱 |