ARM TrustZone 技术基础

好,咱们正式开始啃 TrustZone 这块硬骨头。说实话,我第一次接触 TrustZone 的时候,也被它那套「两个世界」的概念绕得有点晕。但后来我意识到,搞懂它其实就三件事:硬件怎么切、隔离怎么保、Monitor 怎么管。今天咱们就把这三件事彻底说透。

TrustZone 硬件架构:一颗芯,两个世界

TrustZone 不是软件补丁,它是 ARM 在芯片层面做的一套硬件扩展。说白了,就是让同一个物理 CPU 核心,能跑出「两个虚拟处理器」的效果。

我习惯把 TrustZone 想象成一栋楼里的两套公寓。共用同一个大门(物理 CPU),但进了门之后,左边是安全世界,右边是普通世界。两个世界各有各的「房间」——也就是各自独立的内存、缓存、外设和中断控制器。

核心要点:TrustZone 的隔离是物理级别的,不是软件模拟的。普通世界的程序,无论如何都访问不到安全世界的内存区域。这不是靠操作系统权限控制的,而是硬件总线层面直接拦截。

为什么会这样?因为 ARM 在系统总线上加了一个额外的控制信号——NS位(Non-Secure bit)。每个总线传输事务都会带上这个标记。安全世界的传输带的是「Secure」标记,普通世界的传输带的是「Non-Secure」标记。总线上的内存控制器、外设控制器看到这个标记,就知道该不该放行。

物理隔离:不是说说而已

我在项目中遇到过最典型的误解,就是有人觉得 TrustZone 的隔离「跟 Linux 的用户态内核态差不多」。差远了。用户态内核态是同一个世界里的权限分级,而 TrustZone 是两个世界之间的物理隔离。

具体来说,隔离体现在三个层面:

  • 内存隔离:安全世界和普通世界有各自的内存区域。普通世界的 DMA(直接内存访问)设备,即使绕过 CPU,也无法读写安全内存。
  • 缓存隔离:L1/L2 缓存里也会标记 NS 位。普通世界的数据不会污染安全世界的缓存行。
  • 外设隔离:每个外设都可以配置为「安全」或「非安全」模式。比如指纹传感器只能被安全世界访问,普通世界的驱动连它的寄存器地址都映射不到。
隔离维度 普通世界 安全世界
内存访问 只能访问 Non-Secure 内存 可访问 Secure + Non-Secure 内存
缓存标记 NS=1 NS=0
外设权限 仅 Non-Secure 外设 所有外设(可配置)
中断处理 只能接收 Non-Secure 中断 可配置接收 Secure 或 Non-Secure 中断

我曾经踩过的坑:有一次调试安全支付模块,发现安全世界写入的一块密钥数据,在普通世界竟然能读到。查了两天才发现,是内存控制器里的 TrustZone 地址空间过滤器(TZASC)配置漏了一段区域。硬件隔离是到位了,但配置错了等于白搭。所以,TrustZone 的安全强度,最终取决于你的配置正确性。

Monitor Mode:两个世界的「旋转门」

两个世界之间怎么切换?这就轮到 Monitor Mode 登场了。它既不属于安全世界,也不属于普通世界,而是独立于两者之外的第三种模式。

我把它比作机场的「国际转机通道」。你从国内出发(普通世界),想飞国际(安全世界),必须经过这个中转区。在中转区里,系统会做安全检查、上下文保存、寄存器切换——然后才放你过去。

Monitor Mode 的触发方式有两种:

  1. 软件主动调用:通过执行 SMC(Secure Monitor Call)指令,主动请求切换到 Monitor Mode。
  2. 硬件异常触发:某些安全相关的中断或异常,会强制 CPU 进入 Monitor Mode 处理。

进入 Monitor Mode 后,CPU 会执行一段特殊的代码——Monitor 向量表。这段代码负责:

  • 保存当前世界的上下文(寄存器、状态等)
  • 切换内存视图(MMU 配置、页表)
  • 修改 NS 位,切换到目标世界
  • 恢复目标世界的上下文
  • 执行 ERET 指令,跳转到目标世界

小技巧:Monitor 代码通常放在一个独立的安全内存区域,并且只由安全世界固件(比如 ARM Trusted Firmware)管理。普通世界永远无法修改或读取这段代码。你想想看,如果攻击者能篡改 Monitor 代码,那整个 TrustZone 体系就形同虚设了。

核心寄存器 SCR:一切切换的「开关」

说了这么多,到底是谁在控制这一切?答案是 SCR(Secure Configuration Register)。这个寄存器是 Monitor Mode 的「控制面板」,它决定了当前世界的安全状态、中断路由方式、以及异常处理行为。

SCR 寄存器里几个关键的位域:

位域 名称 作用
NS Non-Secure bit 0=安全世界,1=普通世界。切换世界时,Monitor 代码会修改这个位。
IRQ/FIQ 中断路由控制 配置 IRQ 和 FIQ 中断是路由到当前世界,还是强制路由到 Monitor Mode。
EA External Abort 控制外部中止异常(比如总线错误)是否被视为安全异常。
SCE SMC Calling Enable 是否允许普通世界执行 SMC 指令。关闭后,普通世界无法主动请求切换到安全世界。

嗯,这里要注意:SCR 寄存器只能在 Monitor Mode 下读写。普通世界和安全世界的代码,如果试图直接访问 SCR,会触发异常。这是硬件层面的保护,确保只有最底层的 Monitor 代码才能控制世界切换。

我个人习惯在调试 TrustZone 时,第一步就是检查 SCR 寄存器的值。如果发现 NS 位不对,或者中断路由配置错了,那后面所有的问题排查都是白费功夫。

知识体系总览

下面这张图,把 TrustZone 的核心逻辑串起来了。你仔细看一遍,应该就能理解「一颗芯、两个世界、一个 Monitor」是怎么协同工作的。

ARM TrustZone 核心架构 普通世界 (Normal World) Rich OS (Linux / Android) 普通应用 NS=1 内存/外设 通过 SMC 请求安全服务 安全世界 (Secure World) Trusted OS (OP-TEE / Trusty) 安全应用 (TA) NS=0 内存/外设 密钥管理 / 指纹处理 Monitor Mode 上下文保存 / NS 位切换 / 中断路由 SCR 寄存器控制 SMC 指令 SMC 指令 ERET 返回 ERET 返回 硬件隔离:总线 NS 位标记 + TZASC 地址空间过滤器 + 独立缓存标记 软件隔离:Monitor 代码不可篡改 + SCR 寄存器只读于 Monitor Mode

从这张图可以看得很清楚:普通世界和安全世界之间没有直接通道,所有切换都必须经过 Monitor Mode。Monitor Mode 就像那个「把关人」,它检查 SCR 寄存器、保存上下文、切换 NS 位——然后才放行。