4. TrustZone硬件架构
TrustZone并不是一颗独立的安全芯片,而是SoC内部贯穿处理器核、总线矩阵、内存控制器与外设的一整套硬件安全扩展。理解它在Cortex-A与Cortex-M上的不同实现方式,是移植适配工作的第一道门槛。很多工程师在A系列上积累了经验后直接套用到M系列,结果在安全中断配置、内存分区粒度和启动流程上反复踩坑,根本原因就在于两者的TrustZone模型并不相同。
一、核心原理:两种TrustZone模型
Cortex-A系列的TrustZone采用“双世界”模型:同一颗物理核通过时间分片在Secure World与Normal World之间切换,两个世界各自拥有独立的异常等级(EL0~EL3)、独立的页表和独立的系统寄存器视图。世界切换由SMC指令或安全中断触发,经EL3的Secure Monitor完成上下文保存与恢复。它的安全边界是“核内虚拟化”式的,粒度细、灵活度高,但切换开销和软件栈复杂度也更大。
Cortex-M系列(ARMv8-M)的TrustZone则采用“状态机”模型:处理器在Secure与Non-secure两种状态间切换,由SAU(Security Attribution Unit)和IDAU(Implementation Defined Attribution Unit)共同决定每个地址的安全属性。M系列没有EL等级概念,切换通过BLXNS、SG等指令以及安全异常完成,状态切换更轻量,但安全属性是静态配置的,灵活性低于A系列。
二、总线与内存保护机制
在A系列SoC中,安全属性通过总线上的NS位(Non-secure bit)传播。AXI总线事务携带AWPROT/ARPROT信号,其中bit[1]即NS位,由处理器或主设备控制器置位。TZASC(TrustZone Address Space Controller)挂在总线上,把DRAM划分为多个区域并分别标记为安全或非安全;TZPC(TrustZone Protection Controller)则控制外设的安全属性。任何非安全主设备访问安全区域都会被TZASC拦截并返回错误响应。
M系列没有TZASC这类独立控制器,安全属性由SAU在核内直接判定。SAU最多支持8个区域,每个区域可配置起始地址、结束地址和属性(安全/非安全/非安全可调用)。IDAU由芯片厂商实现,通常把Flash、SRAM、外设按物理地址预先划分。SAU与IDAU的判定结果取“更安全”的一方,这一规则在移植时极易被忽略。
关键规则:SAU与IDAU冲突时,安全属性取两者中更严格的结果。若IDAU把某段SRAM标记为Secure,即使SAU配置为Non-secure,最终仍为Secure。移植前必须向芯片厂商索取IDAU地址映射表。
三、中断与异常处理差异
A系列使用GIC(Generic Interrupt Controller),GICv3/v4支持中断分组:Group 0用于安全中断,Group 1 Secure和Group 1 Non-secure分别对应两个世界。中断路由由GICD_IGROUPR寄存器配置,安全中断只能由Secure World处理,非安全中断可被路由到任一世界。FIQ通常用于安全中断,IRQ用于非安全中断,但这不是强制的。
M系列使用NVIC,ARMv8-M的NVIC为每个中断增加了目标状态位(Target State)。中断可被配置为Secure、Non-secure或Both。安全中断只能由Secure状态处理,非安全中断由Non-secure状态处理。当Non-secure代码触发安全中断时,硬件自动完成状态切换并压栈,返回时通过BXNS恢复。安全异常优先级高于所有非安全异常。
| 对比维度 | Cortex-A 系列 | Cortex-M 系列 |
|---|---|---|
| 安全模型 | 双世界 + EL 等级 | 双状态 + SAU/IDAU |
| 切换指令 | SMC / HVC | BLXNS / SG |
| 内存保护单元 | TZASC + MMU 页表 | SAU + MPU |
| 中断控制器 | GIC(分组路由) | NVIC(目标状态位) |
| 安全中断载体 | FIQ / Group 0 | Secure 异常 |
| 配置粒度 | 页级(4KB) | 区域级(最小32B) |
| 典型场景 | 应用处理器、网关 | MCU、传感器节点 |
四、移植适配中的典型误区与复盘
第一个误区是把A系列的“世界切换”思维直接搬到M系列。M系列没有Secure Monitor,状态切换由硬件在异常入口自动完成,不需要也不应该手写上下文保存代码。若在安全异常处理函数中手动保存全部寄存器,反而会破坏硬件压栈的栈帧布局。
第二个误区是忽略SAU与IDAU的叠加判定。某项目在STM32L5上把一段SRAM配置为Non-secure,但该区域被IDAU默认标记为Secure,导致非安全代码访问时触发SecureFault。排查时只检查了SAU配置,浪费了大量时间。正确做法是同时导出SAU和IDAU的地址映射进行比对。
第三个误区是中断优先级配置错误。M系列中安全中断的优先级数值必须小于非安全中断,否则安全中断可能被非安全中断抢占,破坏安全隔离。移植时应统一规划优先级分组,安全中断使用0~3,非安全中断使用4~15。
/* Cortex-M TrustZone SAU 配置示例 */
SAU->CTRL = 0; /* 关闭 SAU 后再配置 */
SAU->RNR = 0; /* 选择区域 0 */
SAU->RBAR = 0x0C000000 | SAU_RBAR_ENABLE;
SAU->RLAR = 0x0C00FFFF | SAU_RLAR_ENABLE | SAU_RLAR_NSC;
SAU->RNR = 1; /* 区域 1:非安全 SRAM */
SAU->RBAR = 0x20000000;
SAU->RLAR = 0x2000FFFF | SAU_RLAR_ENABLE;
SAU->CTRL = SAU_CTRL_ENABLE | SAU_CTRL_ALLNS;
__DSB();
__ISB();
移植建议:先在芯片参考手册中确认IDAU的固定地址划分,再设计SAU区域,最后配置NVIC中断目标状态。三步顺序不可颠倒,否则会出现“配置看似正确但行为异常”的问题。
总结来看,A系列TrustZone是“核内虚拟化”路线,强调灵活与细粒度;M系列是“状态机 + 静态分区”路线,强调轻量与确定性。移植适配的核心不是照搬代码,而是先建立正确的硬件模型认知,再针对总线保护、内存分区和中断路由逐项对齐。