ARM架构基础:处理器模式、异常模型、内存管理单元(MMU)、缓存与一致性基础

TrustZone 技术的本质是系统级隔离,它并非一个独立的硬件模块,而是深度嵌入 ARM 处理器的架构特性。要真正理解 TrustZone 如何实现安全世界与普通世界的隔离,必须先掌握 ARM 处理器的底层运行机制。本章将围绕四个核心支柱展开:处理器模式与异常模型(决定代码如何被调度和响应)、内存管理单元(决定地址如何被翻译和权限如何被检查)、缓存与一致性(决定数据在多核与内存间如何保持同步)。这四个部分共同构成了 TrustZone 安全扩展的硬件基础,也是后续编写 TEE 代码、配置安全世界内存时必须面对的底层约束。

ARM 架构基础与 TrustZone 关联模型 TrustZone 扩展 安全/普通世界隔离 处理器模式 USR/SVC/IRQ/FIQ EL0-EL3 异常级别 CPSR/SPSR 状态保存 异常模型 同步/异步异常 向量表跳转 异常返回 ERET MMU 页表翻译/权限检查 NS位地址空间 TCR/MAIR 控制 缓存与一致性 L1/L2 Cache 层级 Cache Line 状态 SCU/CCI 互联 TrustZone 如何依赖这些基础 • 处理器模式:安全世界使用独立的 Banked 寄存器,上下文切换依赖模式切换 • 异常模型:SMC 指令触发 EL3 异常,是安全世界与普通世界通信的唯一入口 • MMU:页表描述符中的 NS 位决定物理地址空间归属,实现内存级隔离 • 缓存一致性:安全世界与普通世界共享缓存,需通过 Clean/Invalidate 防止数据泄漏

2.1 处理器模式:特权级与状态保存

核心原理

ARM 处理器(Cortex-A 系列)采用模式(Mode)与异常级别(Exception Level)双重维度来管理特权。在 ARMv7 及更早架构中,处理器模式包括 USR(用户)、SVC(管理模式)、IRQ(中断)、FIQ(快速中断)、ABT(中止)、UND(未定义)、SYS(系统)等。进入 ARMv8 后,AArch64 架构引入了更清晰的异常级别模型:EL0(用户态)、EL1(内核态)、EL2(虚拟化)、EL3(安全固件)。TrustZone 正是利用 EL3 作为安全世界与普通世界的切换枢纽。

每个模式拥有独立的堆栈指针(SP)和保存程序状态寄存器(SPSR)。当异常发生时,处理器自动将当前 CPSR 保存到对应模式的 SPSR,并将返回地址保存到 LR(链接寄存器),然后切换到目标模式。这种机制保证了异常处理现场不会破坏用户态的状态。

判断方法

  • 查看当前模式:读取 CPSR 的 M[4:0] 字段,例如 0b10000 表示 USR 模式,0b10011 表示 SVC 模式。
  • 确认异常级别:在 AArch64 中,读取 CurrentEL 寄存器,返回 0/1/2/3 对应 EL0-EL3。
  • 检查特权指令可用性:尝试执行 MSR/MRS 操作系统寄存器,若触发 UND 异常,则当前处于 EL0。

案例拆解:TEE 上下文切换

在 OP-TEE 中,当普通世界调用 SMC 指令时,CPU 从 EL1(普通世界内核)陷入 EL3(ATF 固件),ATF 保存普通世界上下文,然后切换到安全世界的 EL1。整个过程涉及两次模式切换:EL1→EL3→EL1(安全)。每次切换都需要保存通用寄存器、系统寄存器(如 TTBR0_EL1、SCTLR_EL1)以及栈指针。如果遗漏某个寄存器的保存,安全世界可能读取到普通世界的残留数据,造成信息泄漏。

经验提醒:在编写底层切换代码时,务必使用 stp 指令批量保存寄存器对,并确保 SPSR 中保存了完整的 PSTATE。调试时可通过 JTAG 读取 CurrentEL 和 SPSR_EL3 验证切换是否完整。

2.2 异常模型:向量表与同步/异步处理

核心原理

ARM 异常模型定义了处理器响应外部事件(中断、复位)或内部事件(未定义指令、SVC、SMC)的机制。异常向量表(Vector Table)位于内存固定地址(或由 VBAR 寄存器指定),每个异常类型对应一个入口。TrustZone 引入了一个新的异常类型——SMC(Secure Monitor Call),它只能在 EL3 被处理,是普通世界请求安全服务的唯一合法途径。

异常分为同步异常(与当前指令直接相关,如数据中止、未定义指令)和异步异常(外部中断 IRQ/FIQ)。在 TrustZone 中,FIQ 通常被配置为安全中断,用于安全世界内部的外设响应,而 IRQ 则用于普通世界。这种分配方式确保安全世界的中断不会被普通世界屏蔽。

操作流程:配置向量表

  1. 在启动代码中定义异常向量表,每个入口 16 字节对齐。
  2. 设置 VBAR_EL3 指向安全世界向量表,VBAR_EL1 指向普通世界向量表。
  3. 为 SMC 异常编写处理函数,解析参数并分发到对应 TEE 服务。
  4. 使用 eret 指令从异常返回,恢复处理器状态。

常见误区

风险说明:初学者常将 IRQ 和 FIQ 都配置为普通中断,导致安全世界的外设中断无法及时响应。在安全关键系统中,必须将安全外设中断配置为 FIQ,并在 EL3 中注册独立的中断控制器(GIC)配置。

2.3 内存管理单元(MMU):地址翻译与权限控制

核心原理

MMU 负责将虚拟地址(VA)翻译为物理地址(PA),并执行内存访问权限检查。ARMv8 使用页表描述符中的多个字段控制访问:AP[2:1] 控制读写权限,UXN/PXN 控制执行权限,而最关键的是 NS(Non-Secure)位。NS 位决定了该物理地址属于安全世界还是普通世界。当 CPU 处于安全状态时,可以访问 NS=0 和 NS=1 的内存;当处于普通世界时,只能访问 NS=1 的内存。这是 TrustZone 内存隔离的基石。

MMU 还通过 TCR(Translation Control Register)配置页表基地址、粒度大小(4K/16K/64K)以及地址空间划分。MAIR(Memory Attribute Indirection Register)定义内存属性(如 Device-nGnRnE、Normal Write-Back),用于控制缓存策略。

判断方法:检查页表配置

寄存器字段作用TrustZone 相关
TTBR0_EL1BADDR用户空间页表基址普通世界 EL0/EL1
TTBR1_EL1BADDR内核空间页表基址普通世界内核
TTBR0_EL3BADDR安全固件页表EL3 代码
MAIR_EL1Attr内存属性编码配置 Normal/Device 区域

案例拆解:安全内存隔离配置

假设我们需要在安全世界中保留 4MB 的 SRAM(地址 0x2E000000),并在普通世界中不可见。操作步骤如下:

  1. 在安全世界页表中,将该区域映射为 NS=0,AP=0b00(EL1 读写),MAIR 属性为 Normal Write-Back。
  2. 在普通世界页表中,不建立该区域的映射,或将其映射为 Fault 条目。
  3. 配置 TZASC(TrustZone Address Space Controller)将该物理地址段标记为安全,即使普通世界通过 MMU 访问也会被总线拒绝。
经验提醒:MMU 的 NS 位只是软件层面的隔离,真正的硬件强制隔离需要 TZASC 配合。在调试时,如果普通世界访问安全内存返回全 0 或触发 Data Abort,首先检查 TZASC 的配置。

2.4 缓存与一致性:多核环境下的数据同步

核心原理

现代 ARM 处理器采用多级缓存架构:L1 是私有缓存(每个核心独有),L2 是共享缓存(通常一组核心共享),L3 可选。缓存以 Cache Line(通常 64 字节)为粒度工作。TrustZone 的引入带来了新的挑战:安全世界和普通世界共享同一套缓存物理资源,但逻辑上需要隔离。如果安全世界的数据残留在缓存中,普通世界通过缓存探测攻击可能获取敏感信息。

ARM 通过缓存维护操作(Clean/Invalidate)和一致性协议(MESI/MOESI)来管理数据同步。在 TrustZone 切换时,软件必须执行缓存清理操作,确保安全世界的数据不会泄漏到普通世界。此外,多核系统中,SCU(Snoop Control Unit)或 CCI(Cache Coherent Interconnect)负责维护各核心缓存的一致性。

操作流程:安全上下文切换时的缓存维护

// 伪代码:切换到安全世界前
DSB SY;              // 确保所有内存访问完成
DC CIVAC, x0;        // Clean and Invalidate by VA to PoC
DSB SY;
// 切换到普通世界前
DC CISW, x0;         // Clean and Invalidate by Set/Way
DSB SY;
ISB;                 // 指令同步屏障

常见误区与复盘

风险说明:很多开发者只清理了当前核心的缓存,忽略了其他核心的共享缓存。在多核 TEE 中,必须使用 DC CIVAC 操作所有相关地址,或者通过 CCI 的广播清理功能。否则,普通世界核心可能从 L2 缓存中读取到安全世界的残留数据。

另一个常见问题是缓存一致性协议与 TrustZone 的交互。当安全世界修改了某块内存,而普通世界的缓存中仍有旧副本时,如果普通世界直接读取,会得到过期数据。因此,在共享内存(通过 SMC 传递的缓冲区)场景中,双方都需要执行缓存清理操作。

2.5 综合案例:基于 TrustZone 的安全启动流程

将上述知识整合,我们来看一个典型的安全启动流程:

  1. ROM 代码(EL3):上电后 CPU 进入 EL3,配置 MMU 映射安全 ROM 和 SRAM,设置向量表。
  2. 加载 ATF(EL3):验证 BL31 镜像签名,加载到安全内存,跳转执行。
  3. 初始化 TZASC:配置内存区域安全属性,将 TEE 内存标记为安全。
  4. 切换到普通世界:ATF 设置 EL1 的页表和向量表,执行 eret 进入普通世界 U-Boot。
  5. 普通世界启动内核:内核运行在 EL1,通过 SMC 调用安全世界服务(如密钥管理)。

整个流程中,每一步都依赖处理器模式切换、异常处理、MMU 配置和缓存维护。任何一个环节的疏漏都可能导致安全启动失败或信息泄漏。

总结复盘:TrustZone 不是孤立的安全模块,而是建立在 ARM 处理器模式、异常、MMU 和缓存机制之上的系统级安全架构。理解这四个基础模块的交互,是后续编写 TEE 驱动、配置安全内存、调试安全启动的前提。建议读者在开发板上实际执行 info registers 观察模式切换,并通过 pagewalk 命令检查页表 NS 位,加深理解。