1. TrustZone 技术概述
ARM TrustZone 是 ARM 架构中提供系统级硬件隔离的安全扩展技术,最早在 ARMv6K 架构中引入,并在 ARMv7-A 及后续 ARMv8-A 中持续演进。其核心目标是在单一物理处理器上创建两个独立的执行环境,从而保护敏感数据和关键代码免受通用操作系统中潜在恶意软件的侵害。
1.1 ARM TrustZone 架构原理
TrustZone 将处理器硬件资源划分为两个虚拟世界:安全世界(Secure World)和非安全世界(Normal World)。这种划分不仅限于处理器核心,还延伸至系统总线、内存控制器、中断控制器和外围设备,形成端到端的硬件隔离屏障。
下表总结了 TrustZone 架构中两个世界的关键差异:
| 特性 | 安全世界(Secure World) | 非安全世界(Normal World) |
|---|---|---|
| 运行软件 | 可信操作系统(如 OP-TEE)、安全应用 | 通用操作系统(如 Linux、Android) |
| 内存访问 | 可访问安全内存和非安全内存 | 仅可访问非安全内存 |
| 外设访问 | 可配置访问安全外设 | 无法访问安全外设 |
| 中断处理 | 安全中断(FIQ)优先处理 | 非安全中断(IRQ) |
| 安全等级 | 高(硬件隔离 + 软件验证) | 低(依赖操作系统安全策略) |
TrustZone 的隔离机制通过系统总线的 NS(Non-Secure)位实现。每个总线事务都携带一个 NS 位,指示该事务来自安全世界还是非安全世界。内存控制器、外设总线等硬件组件根据 NS 位决定是否允许访问。这种设计使得隔离在硬件层面强制执行,无需软件参与。
1.2 安全世界与非安全世界隔离机制
两个世界的隔离体现在多个硬件层次上,形成纵深防御体系:
- 处理器核心隔离: 每个物理核心在逻辑上虚拟化为安全核心和非安全核心,通过安全配置寄存器(SCR)控制当前世界状态。
- 内存隔离: 系统内存管理单元(SMMU)或 TrustZone 地址空间控制器(TZASC)将物理内存划分为安全区域和非安全区域。非安全世界的 DMA 操作也无法访问安全内存。
- 缓存隔离: 缓存行标记有 NS 位,安全世界和非安全世界的缓存数据不会相互污染,防止缓存侧信道攻击。
- 中断隔离: 中断控制器(GIC)支持安全中断配置,安全中断(FIQ)直接路由到安全世界,非安全世界无法拦截或伪造。
- 外设隔离: 通过 TrustZone 保护控制器(TZPC)或外设自身的 NS 位控制逻辑,将外设寄存器空间标记为安全或非安全。
secure DDR)在系统启动时就被 TZASC 正确配置为安全属性。
下图展示了 TrustZone 系统中安全世界与非安全世界的隔离架构:
1.3 Monitor 模式与 SMC 指令
Monitor 模式是 TrustZone 架构中一个特殊的处理器模式,位于安全世界和非安全世界之间,充当两个世界切换的网关。Monitor 模式拥有最高的特权级别(EL3 在 ARMv8-A 中),负责保存和恢复世界上下文、验证切换请求的合法性。
SMC(Secure Monitor Call)指令是触发世界切换的唯一软件途径。当非安全世界需要调用安全服务时,执行 SMC 指令,处理器陷入 Monitor 模式,由 Monitor 软件(通常是 ARM Trusted Firmware)处理切换逻辑。
下表对比了 Monitor 模式与普通处理器模式的关键差异:
| 特性 | Monitor 模式(EL3) | 安全世界内核模式(S-EL1) | 非安全世界内核模式(EL1) |
|---|---|---|---|
| 特权级别 | 最高(EL3) | 高(S-EL1) | 中(EL1) |
| 主要职责 | 世界切换、安全监控 | 运行安全操作系统 | 运行通用操作系统 |
| 内存访问 | 全部内存 | 安全 + 非安全内存 | 仅非安全内存 |
| 触发方式 | SMC 指令、异常 | 安全中断、SMC 返回 | 非安全中断、系统调用 |
| 典型软件 | ARM Trusted Firmware | OP-TEE 内核 | Linux 内核 |
下图展示了 SMC 指令触发世界切换的完整流程:
在 ARMv8-A 架构中,Monitor 模式对应 EL3(Exception Level 3),安全世界内核运行在 S-EL1,非安全世界内核运行在 EL1。SMC 指令在 ARMv8-A 中被定义为 SMC #0 或 SMC #1,分别用于标准安全调用和快速安全调用。
// Linux 内核中发起 SMC 调用
#include <linux/arm-smccc.h>
struct arm_smccc_res res;
// 调用标准 SMC 服务
arm_smccc_smc(0x82000001, /* 功能 ID */
0x12345678, /* 参数 1 */
0, /* 参数 2 */
0, /* 参数 3 */
0, /* 参数 4 */
0, /* 参数 5 */
0, /* 参数 6 */
&res);
// 检查返回值
if (res.a0 != 0) {
pr_err("SMC 调用失败: %ld\n", res.a0);
} else {
pr_info("SMC 调用成功,返回值: %ld\n", res.a1);
}