4. 内存隔离与TZASC:TrustZone地址空间控制器的工作原理
在ARM TrustZone架构中,内存隔离是安全世界与普通世界之间最核心的硬件屏障。虽然处理器内核通过安全位(NS位)区分当前执行状态,但如果没有总线级别的地址空间过滤,普通世界仍然可以通过DMA、GPU或其他总线主控设备访问安全内存区域。TrustZone地址空间控制器(TZASC)正是为了解决这一总线级隔离问题而设计的硬件模块。
核心概念: TZASC位于系统总线(如AXI/AHB)与内存控制器之间,对每一个总线事务的地址、安全状态进行实时检查。只有当事务的安全属性与目标内存区域的安全配置匹配时,访问才被允许通过。
4.1 TZASC的工作原理
TZASC本质上是一个可编程的地址过滤器。它监控系统总线上的所有内存访问请求,并根据预先配置的区域描述符决定是否放行。其工作流程如下:
- 地址匹配: 总线主控发起一次内存访问,携带目标地址和事务的安全状态(Secure/Non-Secure)。
- 区域查找: TZASC将目标地址与内部维护的多个区域(Region)的基地址和大小进行比较,确定该地址属于哪个区域。
- 权限检查: 根据命中区域的安全属性配置(如:仅安全世界可读写、仅非安全世界可读、或完全开放),检查当前事务的安全状态是否具有相应权限。
- 裁决与转发: 如果权限检查通过,事务被转发到下游内存控制器;如果失败,TZASC返回错误响应(SLVERR或DECERR),阻止访问。
关键设计点: TZASC的配置寄存器(区域描述符)必须由安全世界软件(如安全监控器或安全OS)在安全状态下进行编程。普通世界软件无法修改这些配置,从而保证了隔离策略的不可绕过性。
4.2 内存区域划分与安全属性配置
TZASC将物理内存地址空间划分为多个可编程区域(Region)。每个区域由一组描述符定义,包含以下关键字段:
| 配置字段 | 位宽 | 描述 |
|---|---|---|
| 基地址(BASE) | 32/64位 | 区域的起始物理地址,通常要求对齐到区域大小 |
| 区域大小(SIZE) | 8位 | 以2的幂次表示区域大小,最小粒度通常为4KB或64KB |
| 安全权限(SEC) | 2位 | 定义安全世界和非安全世界的读写权限组合 |
| 子区域掩码(SUB) | 8位 | 将区域进一步细分为8个子区域,每个子区域可独立配置 |
| 使能位(EN) | 1位 | 控制该区域描述符是否生效 |
4.3 安全属性模型:四种典型配置
每个TZASC区域的安全权限(SEC)字段定义了四种标准访问模式,这是实现内存隔离的基础:
| SEC值 | 安全世界 | 非安全世界 | 典型用途 |
|---|---|---|---|
| 00 | 读/写 | 无访问 | 安全固件、密钥存储、安全监控器代码 |
| 01 | 读/写 | 只读 | 安全世界向非安全世界暴露的只读配置表 |
| 10 | 读/写 | 读/写 | 共享内存区域,用于安全与非安全世界的数据交换 |
| 11 | 无访问 | 读/写 | 非安全世界独占区域(较少使用,通常由MMU管理) |
安全风险提示: 将安全内存区域配置为“安全世界读/写 + 非安全世界只读”(SEC=01)时,必须确保非安全世界无法通过侧信道攻击(如缓存时序、推测执行)读取敏感数据。在ARMv8.4及后续架构中,建议配合推测存储屏障(SSB)和缓存隔离指令使用。
4.4 典型内存布局示例
在一个典型的嵌入式系统中,TZASC将物理内存划分为多个区域,形成清晰的隔离边界。以下是一个4GB DRAM系统的示例布局:
4.5 子区域(Sub-Region)与细粒度控制
为了在不增加区域描述符数量的前提下提供更细粒度的控制,TZASC支持子区域掩码机制。每个区域被均匀划分为8个子区域,每个子区域可以独立配置是否遵循主区域的安全权限:
- 子区域使能位 = 1: 该子区域遵循主区域的安全权限(SEC字段)。
- 子区域使能位 = 0: 该子区域被强制禁止所有访问(安全和非安全均不可访问),相当于在该地址范围内创建一个“空洞”。
应用场景: 子区域掩码常用于在共享内存区域中保留一小块安全世界专用的元数据区域。例如,区域2(共享内存)的大小为1MB,通过子区域掩码将第0个子区域(前128KB)设置为禁止访问,用于存放安全世界与共享缓冲区的控制结构。
4.6 配置示例:初始化TZASC区域
以下代码展示了在安全监控器初始化阶段,如何通过内存映射寄存器配置TZASC的区域描述符。假设TZASC的基地址为 0x2A000000:
/* TZASC寄存器偏移定义 */
#define TZASC_BASE 0x2A000000
#define TZASC_REGION_BASE(n) (TZASC_BASE + 0x100 + (n * 0x10))
#define TZASC_REGION_ATTR(n) (TZASC_BASE + 0x104 + (n * 0x10))
#define TZASC_REGION_SIZE(n) (TZASC_BASE + 0x108 + (n * 0x10))
#define TZASC_REGION_EN(n) (TZASC_BASE + 0x10C + (n * 0x10))
/* 安全属性宏定义 */
#define SEC_READ_WRITE_SECURE_ONLY 0x0 /* SEC=00 */
#define SEC_READ_WRITE_SECURE_RO_NS 0x1 /* SEC=01 */
#define SEC_READ_WRITE_BOTH 0x2 /* SEC=10 */
#define SEC_READ_WRITE_NONSEC_ONLY 0x3 /* SEC=11 */
/* 配置区域0:安全固件专用(0x0000_0000 - 0x000F_FFFF,1MB) */
void tzasc_configure_region0(void) {
/* 设置基地址:0x0000_0000,对齐到1MB边界 */
*(volatile uint32_t *)TZASC_REGION_BASE(0) = 0x00000000;
/* 设置属性:安全世界读写,非安全世界无访问 */
*(volatile uint32_t *)TZASC_REGION_ATTR(0) = SEC_READ_WRITE_SECURE_ONLY;
/* 设置大小:1MB(2^20),编码为20 */
*(volatile uint32_t *)TZASC_REGION_SIZE(0) = 20;
/* 使能区域0 */
*(volatile uint32_t *)TZASC_REGION_EN(0) = 0x1;
}
/* 配置区域2:共享内存(0x1000_0000 - 0x100F_FFFF,1MB) */
void tzasc_configure_region2(void) {
*(volatile uint32_t *)TZASC_REGION_BASE(2) = 0x10000000;
*(volatile uint32_t *)TZASC_REGION_ATTR(2) = SEC_READ_WRITE_BOTH;
*(volatile uint32_t *)TZASC_REGION_SIZE(2) = 20;
*(volatile uint32_t *)TZASC_REGION_EN(2) = 0x1;
}
编程注意事项:
- 在修改TZASC配置前,必须确保当前CPU处于安全监控器模式(Monitor Mode)或安全EL3/EL1。
- 区域大小必须使用2的幂次编码,且基地址必须对齐到区域大小。
- 修改已使能的区域时,建议先清除使能位,更新配置后再重新使能,避免中间状态导致总线错误。
- 不同SoC厂商的TZASC实现可能存在寄存器偏移差异,请参考具体芯片的技术参考手册(TRM)。
4.7 TZASC与系统安全的关系
TZASC是TrustZone内存隔离的最后一道防线。它与处理器内核的安全状态检查、MMU页表权限共同构成纵深防御体系:
| 防御层级 | 作用范围 | 绕过风险 |
|---|---|---|
| 处理器NS位 | CPU内核内部 | 仅保护CPU发起的访问,无法防御DMA/GPU |
| MMU页表权限 | 虚拟地址空间 | 页表可能被篡改(需SMMU保护) |
| TZASC | 物理地址空间(总线级) | 硬件强制,不可绕过(除非硬件漏洞) |
硬件攻击面: 虽然TZASC提供了硬件级隔离,但攻击者仍可能通过物理攻击(如探针、电压毛刺、激光注入)尝试绕过。在安全等级要求极高的场景(如支付终端、HSM),建议配合主动屏蔽层和电压/温度传感器使用。
通过合理配置TZASC的区域描述符,系统设计者可以在物理地址层面建立不可篡改的安全边界,确保安全固件、密钥材料、可信应用的数据不会被普通世界或恶意DMA设备窃取或篡改。这是构建可信执行环境(TEE)的基石之一。