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系列。

Cortex-A 与 Cortex-M TrustZone 架构对比 Cortex-A:双世界 + EL 等级 Normal World EL0 应用 / EL1 内核 / EL2 虚拟化 Secure World S-EL0 可信应用 / S-EL1 TEE 内核 EL3 Secure Monitor SMC 指令触发世界切换 TTBR0/TTBR1 独立页表 · 两级地址转换 TZASC 内存分区 · GIC 安全中断分组 切换开销大 · 软件栈复杂 · 粒度细 Cortex-M:双状态 + SAU/IDAU Non-secure State 普通任务 · NS 向量表 · NS 栈 Secure State 安全任务 · S 向量表 · S 栈 SAU + IDAU 地址属性判定 BLXNS / SG 指令切换状态 MPU 安全分区 · 安全/非安全外设 NVIC 安全中断 · 安全异常优先级 切换轻量 · 静态配置 · 粒度较粗

二、总线与内存保护机制

在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 / HVCBLXNS / SG
内存保护单元TZASC + MMU 页表SAU + MPU
中断控制器GIC(分组路由)NVIC(目标状态位)
安全中断载体FIQ / Group 0Secure 异常
配置粒度页级(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系列是“状态机 + 静态分区”路线,强调轻量与确定性。移植适配的核心不是照搬代码,而是先建立正确的硬件模型认知,再针对总线保护、内存分区和中断路由逐项对齐。