ARM处理器模式与寄存器

深入解读 ARM 处理器模式与寄存器 的底层原理与最佳实践。

1. 处理器模式与特权级

ARM 是一个模态架构(Modal Architecture)。处理器不在 User 下干活,就在 IRQ/FIQ 里处理中断,或者在 SVC 里跑系统调用—每种场景对应一种模式。引入 TrustZone 安全扩展和虚拟化扩展后,模式列表进一步扩大。

1.1 基础七模式

模式 全称 缩写 触发条件 特权级
User User mode USR 应用程序默认运行 非特权(唯一!)
FIQ Fast Interrupt reQuest FIQ FIQ 中断异常 特权
IRQ Interrupt ReQuest IRQ IRQ 中断异常 特权
Supervisor Supervisor mode SVC Reset 或执行 SVC 指令 特权
Abort Abort mode ABT 内存访问异常(缺页/权限错误) 特权
Undefined Undefined mode UND 执行未定义指令 特权
System System mode SYS —(仅有特权软件显式切换) 特权

两个值得强调的点:

  • User mode 是唯一的非特权模式。在 User mode 下,不能直接修改 CP15 系统控制寄存器、不能操作 MMU 配置、不能操作缓存。这是操作系统实现进程隔离的硬件基础。
  • System mode 很特别:它是特权模式,但却与 User mode 共享完全相同的寄存器视图(不 bank R13/R14/SPSR)。它通常被操作系统内核用于需要特权访问但不需要独立栈帧的执行上下文。

1.2 TrustZone 引入的新维度:安全状态

TrustZone 安全扩展在”模式”之上叠加了第二个维度:安全状态。对于实现了 TrustZone 的处理器,系统安全性通过将所有硬件和软件资源一分为二来实现:一部分划归 Secure world(安全子系统),其余划归 Normal / Non-secure world(普通世界)。处理器处于 Non-secure 状态时,无法访问分配给 Secure 状态的内存——这不是软件检查,而是总线上的 NS(Non-Secure)位在物理层面阻断。

TrustZone 新增了一个独立的 Monitor 模式,作为两个世界之间的唯一网关。当软件需要从 Normal world 切换到 Secure world(例如访问安全密钥),必须通过 SMC(Secure Monitor Call)指令进入 Monitor 模式,由 Monitor 模式的软件验证请求合法性后切换世界并跳转到 Secure world 的入口代码。从 Monitor 返回则使用 ERET(或等价寄存器写回 CPSR)指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
              ┌─────────────────────────┐
│ Monitor Mode (MON) │ ← gateway between worlds
│ Secure PL1 │
└──────────┬──────────────┘

┌────────────────────────┼─────────────────────────┐
│ Normal World │ Secure World │
│ ┌──────────────────┐ │ ┌──────────────────┐ │
│ │ User / FIQ / IRQ │ │ │ User / FIQ / IRQ │ │
│ │ SVC / ABT / UND │ │ │ SVC / ABT / UND │ │
│ │ System / Hyp │ │ │ System │ │
│ └──────────────────┘ │ └──────────────────┘ │
└────────────────────────┴─────────────────────────┘

关键点:

  • Normal World 和 Secure World 各自拥有一套完整的处理器模式。TrustZone 不是在”模式之上叠加”,而是将模式复制到了两个安全维度中。
  • Monitor 模式是唯一的跨世界桥梁,运行在 Secure PL1,处理 SMC 调用和 world switch。
  • 普通世界代码无法访问安全世界的内存——这是硬件隔离,不由操作系统控制。
  • Linux 等通用操作系统及其应用运行在 Normal World;厂商固件、安全密钥和 DRM 等运行在 Secure World。在某些情况下,Secure 状态下运行的软件比 Non-secure 状态下的软件拥有更高的特权

1.3 虚拟化扩展的第三层:PL0/PL1/PL2

ARMv7-A 虚拟化扩展引入了新的特权层级 PL2Hyp 模式,形成三层特权体系。与 TrustZone 不同的是:TrustZone 是水平隔离(两个世界彼此分离),虚拟化是垂直分层(上层管控下层)。

特权级 运行什么? 对应模式 关键限制
PL0 应用程序 User mode 只能非特权内存访问,不能改系统配置
PL1 操作系统内核(Guest OS) SVC, IRQ, FIQ, ABT, UND, System, Monitor 可观上操作系统在此执行,横跨多种异常模式
PL2 Hypervisor(虚拟机管理器) Hyp mode 仅存在于 Non-secure 世界

原书明确指出 PL0–PL2 是与 TrustZone 安全状态正交的维度——特权级定义的是”在当前安全状态内能访问哪些资源”,与另一安全状态无关。例如 Non-secure PL1 不能访问 Secure PL0 的内存,即便它的特权级更高。

pl_and_mode

完整虚拟化栈示意:

1
2
3
4
5
6
7
8
9
┌──────────────┐  PL0  ← 应用层(无特权,仅非特权内存访问)
│ Application │
├──────────────┤
│ Guest OS │ PL1 ← 客操作系统,横跨 SVC/IRQ/FIQ/ABT/UND/System
│ (Linux) │ 处理来自 PL0 的 SVC 系统调用
├──────────────┤
│ Hypervisor │ PL2 ← 管控多个 PL1 Guest OS,处理来自各 OS 的敏感操作
│ (KVM/Xen) │
└──────────────┘

Hyp 模式特有资源:

  • R13_hyp:独立栈指针,不与其他任何模式共享
  • SPSR_hyp:异常发生时保存 CPSR 快照
  • ELR_hyp(Exception Link Register):专门存储 Hyp 模式下的异常返回地址(与常规 LR 分离)
  • Hyp 模式用 User 模式的 LR(R14_usr)存储函数调用返回地址

2. 寄存器组与 Banking:同名异实

出处:原书 §4.1,第 50-52 页

ARM 架构提供 16 个 32 位通用寄存器(R0–R15),但这只是”逻辑视图”。物理上,某些寄存器在不同模式下指向不同的硬件存储单元——这就是寄存器 Banking。

2.1 寄存器的角色分工

寄存器 角色 说明
R0–R7 通用数据(低寄存器) 从不 Bank,所有模式共用同一物理存储
R8–R12 通用数据(高寄存器) R8–R12 在 FIQ 模式下 Bank;其他模式共用
R13 Stack Pointer (SP) 每个异常模式独立 Bank:SP_usr ≠ SP_svc ≠ SP_irq …
R14 Link Register (LR) 每个异常模式独立 Bank:LR_usr ≠ LR_svc ≠ LR_irq …
R15 Program Counter (PC) 从不 Bank
CPSR 当前程序状态寄存器 从不 Bank
SPSR 备份状态寄存器 每个异常模式独立 Bank:SPSR_fiq, SPSR_irq, SPSR_abt…

一个 FIQ 中断处理函数用 R8 时,它实际上访问的是 R8_fiq 这个物理寄存器——而不是 User 模式下看到的 R8_usr。这种透明的硬件切换避免了中断处理程序中保存/恢复上下文的开销,也是 FIQ(Fast Interrupt)之所以”快”的关键设计之一。

2.2 寄存器全视图

原书 Figure 4-5 完整展示了 ARM 寄存器的 Banking 机制——浅色寄存器为所有模式共享,着色寄存器在不同模式下映射到独立的物理存储。

The_ARM_register_set

几个重要观察:

  1. R0–R7 + R15 + CPSR 从不 Bank,所有模式和上下文看到的都是同一份。
  2. FIQ 是唯一的 R8–R12 Bank 模式——FIQ 中断处理程序无需 push/pop 这 5 个寄存器,直接拿到独立副本。
  3. R14(Link Register)在 Hyp 和 SYS 模式下退回使用 LR_usr——因为它们不需要独立的子程序返回路径。
  4. R15(PC)有一个历史包袱:在 ARM 状态读取 PC 时,返回 当前地址 + 8;在 Thumb 状态返回 当前地址 + 4。这是 ARM1 三级流水线的遗产,在 ARMv7 中依然保留。

实例:SVC 模式下执行 BL sub_routine,LR_svc 自动存入返回地址。执行 BX LR 就能回到调用点。但如果是 IRQ 中断打断了 User 模式的代码,LR_irq 会自动保存中断发生时的返回地址。不同模式的 LR 互不干扰。

2.3 复位后寄存器状态与初始化要求

  • R0–R14 复位值不可预测(架构未定义)
  • SP 必须由 boot 代码显式初始化:需要为每个模式分别设置栈指针
  • AAPCS(ARM Architecture Procedure Call Standard)规定了寄存器的调用约定角色

3. 程序状态寄存器:CPSR 与 SPSR

CPSR(Current Program Status Register)是一个 32 位寄存器,编码了处理器的当前状态。User 模式下只能访问其受限版本 APSR(只暴露 NZCVQ 和 GE 位)。

3.1 CPSR 位字段全解

cpsr_bits

位段 名称 含义
N (31) Negative ALU 运算结果为负
Z (30) Zero ALU 运算结果为零
C (29) Carry ALU 运算产生进位/借位,无符号数
V (28) Overflow ALU 运算有符号溢出,有符号数
Q (27) Saturation 粘滞饱和标志(DSP 指令设置后保持)
J (24) Jazelle 处理器是否在 Jazelle 状态
GE[3:0] (19:16) Greater-than-or-Equal SIMD 指令的大于等于标志
IT[7:2] (15:10) If-Then Thumb-2 IT 块的执行条件
E (9) Endianness 0=小端, 1=大端
A (8) Async Abort mask 1=屏蔽异步异常
I (7) IRQ mask 1=屏蔽 IRQ 中断
F (6) FIQ mask 1=屏蔽 FIQ 中断
T (5) Thumb 0=ARM 状态, 1=Thumb 状态
M[4:0] (4:0) Mode 当前处理器模式编码

N/Z/C/V 四条件码是 ARM 条件执行的基础:

1
2
CMP R0, R1      ; R0 - R1 → 更新 NZCV 标志(不改变 R0 或 R1)
BEQ target ; 如果 Z=1(相等)则跳转

实例:User 模式代码执行 CMP R0, #5 后 Z 标志变化,APSR 随之更新;IRQ 中断突然到来,当前 CPSR 被自动保存到 SPSR_irq,中断处理完毕后通过 SUBS PC, LR, #4 恢复 CPSR(包含被中断代码的 NZCV 状态)。

3.2 SPSR:异常发生时的”状态快照”

每个异常模式拥有一个独立的 SPSR(Saved Program Status Register)。当异常发生时:

  1. 硬件自动将当时的 CPSR 拷贝到目标异常模式的 SPSR
  2. CPSR[4:0] 被改写为异常模式编码
  3. 异常返回时,SPSR → CPSR 恢复原状

这就是为什么每个模式只需要一个 SPSR——它只在从该模式返回时才被读取。

3.3 模式切换的两种方式

  1. 显式切换:特权软件通过 MSR CPSR_c, #mode 直接写 CPSR 的 M 字段
  2. 隐式切换:异常事件自动触发切换(更常见)

User 模式不能修改 CPSR[4:0](M 位)和 CPSR[7:6](I/F 中断屏蔽位)——这是硬件强制执行的保护。


4. CP15 系统控制协处理器

CP15(System Control Coprocessor)是 ARM 核心特性的总控面板。所有系统级操作——MMU 配置、缓存维护、TLB 管理、异常向量表基址——都通过 CP15 完成。16 个主寄存器(c0–c15)各自承担不同的角色。

4.1 CP15 关键寄存器速查

寄存器 全称 作用
MIDR (c0) Main ID Register 处理器身份识别(实现者、架构版本、型号)
MPIDR (c0) Multiprocessor Affinity Register 多核集群中唯一标识每个核心
SCTLR (c1) System Control Register 主系统控制寄存器(MMU/缓存/分支预测开关)
ACTLR (c1) Auxiliary Control Register 实现特定的附加控制
CPACR (c1) Coprocessor Access Control 控制对 CP10/CP11(NEON/VFP)的访问权限
SCR (c1) Secure Configuration Register TrustZone 控制
TTBR0 (c2) Translation Table Base Register 0 一级页表物理基址
TTBR1 (c2) Translation Table Base Register 1 一级页表物理基址(内核空间)
TTBCR (c2) Translation Table Base Control TTBR0/TTBR1 的地址划分控制
DFSR (c5) Data Fault Status Register 最近数据异常的详细信息
IFSR (c5) Instruction Fault Status Register 最近指令异常的详细信息
DFAR (c6) Data Fault Address Register 引起数据异常的目标虚拟地址
IFAR (c6) Instruction Fault Address Register 引起指令异常的虚拟地址
VBAR (c12) Vector Base Address Register 异常向量表基址
MVBAR (c12) Monitor Vector Base Address Register Monitor 模式异常向量表基址
CONTEXTIDR (c13) Context ID Register ASID 进程标识
CBAR (c15) Configuration Base Address Register GIC 和 Local Timer 外设的基地址

所有 CP15 访问都通过两条指令完成:

1
2
MRC  p15, <Op1>, <Rt>, <CRn>, <CRm>, <Op2>   ; CP15 → ARM 寄存器
MCR p15, <Op1>, <Rt>, <CRn>, <CRm>, <Op2> ; ARM 寄存器 → CP15

各参数含义:

参数 位宽 含义
p15 协处理器编号,固定为 15(系统控制协处理器)
Op1 3-bit 一级操作码,选择 CRn 内部的寄存器分组(通常为 0)
Rt ARM 通用寄存器(R0–R14),MRC 写入目标 / MCR 读取源
CRn 4-bit 主寄存器号(c0–c15),选择功能大类
CRm 4-bit 二级寄存器号,在 CRn 内部进一步子选择
Op2 3-bit 二级操作码,在 CRn + CRm 范围内最终选出一个物理寄存器

通过 CRn + Op1 + CRm + Op2 四个维度的组合,CP15 可以在 16 个主寄存器的名义下容纳远超 16 个物理寄存器。

4.2 MIDR 解读:处理器身份证明

实例:读取一颗 Cortex-A8 CPU 的 MIDR:

1
MCR  p15, 0, R1, c0, c0, 0    ; R1 = MIDR

结果 R1 的各字段含义:

字段 位段 含义
Implementer [31:24] 0x41 ‘A’ = ARM 设计
Variant [23:20] 取决于版本 处理器修订号
Architecture [19:16] 0xF ARMv7 架构
Part Number [15:4] 0xC08 Cortex-A8
Revision [3:0] 取决于批次 补丁修订号

这个寄存器是 boot 代码和操作系统用来确定当前运行在哪个 CPU 上的基础信息来源。


5. SCTLR 系统控制寄存器

SCTLR 是 CP15 c1 寄存器中最关键的一个——它是整个 SoC 系统行为的主控开关。只能从 PL1 或更高特权级 访问。

5.1 关键控制位

符号 作用
M [0] MMU enable 1 = 启用 MMU(分页翻译)
A [1] Alignment check 1 = 启用对齐检查
C [2] Cache enable (data/unified) 1 = 启用数据/统一缓存
Z [11] Branch prediction 1 = 启用分支预测
I [12] Instruction cache 1 = 启用指令缓存
V [13] Vector table base 0 = 0x00000000, 1 = 0xFFFF0000
FI [21] FIQ config enable FIQ 行为配置
U [22] Alignment model 对齐模型选择
EE [25] Exception endianness 异常处理时的端序
NMFI [27] Non-Maskable FIQ FIQ 不可被屏蔽
TE [30] Thumb exception enable 异常在 ARM/Thumb 状态处理

5.2 Boot 代码中的经典初始化序列

以下汇编来自原书 Example 4.x,是典型的 boot 代码中启用系统关键功能的序列:

1
2
3
4
5
MRC     p15, 0, r0, c1, c0, 0    ; 读 SCTLR 当前值 → r0
ORR r0, r0, #(1 << 2) ; 置 C 位:启用数据缓存
ORR r0, r0, #(1 << 12) ; 置 I 位:启用指令缓存
ORR r0, r0, #(1 << 11) ; 置 Z 位:启用分支预测
MCR p15, 0, r0, c1, c0, 0 ; 写回 SCTLR

这段序列的意义:

  1. C 位(数据缓存):不置位的话,所有数据访问直接走总线,性能退化到裸内存。
  2. I 位(指令缓存):不置位指令缓存,每条指令都要从内存取。
  3. Z 位(分支预测):置位前分支预测器不工作,流水线效率大幅降低。

实例:如果一段代码在 A 位置为 1 时访问了一个非对齐地址(如 LDR R0, [R1] where R1 末 2 位非零),硬件会触发 Data Abort 异常进入 ABT 模式。这在调试内存访问 Bug 时是强有力的工具——只要读一下 DFAR 就知道是哪个地址引起的。


6. 学习要点总结

  1. ARM 有 9 种模式:7 种基础模式 + Monitor(TrustZone) + Hyp(虚拟化扩展)。User 是唯一的非特权模式,System 是唯一”特权但不 bank SP/LR”的模式。

  2. 寄存器 Banking 的物理机制:非 Bank 寄存器(R0–R7, R15, CPSR)所有模式共享;Bank 寄存器(R8–R12/FIQ + R13/R14/SPSR/每种异常模式)在不同模式下指向不同物理存储。FIQ 独有的 R8_fiq–R12_fiq 是实现快速中断响应的关键。

  3. 特权级 ≠ 安全状态:PL0/PL1/PL2 是垂直分层(应用→内核→Hypervisor);Secure/Non-secure 是水平隔离(TrustZone)。两者正交——Linux 运行在 Normal PL1,Trusted OS 运行在 Secure PL1。

  4. **CPSR 是处理器的”状态名片”**:32 位编码了 NZCV 条件码、中断屏蔽位、当前模式、端序、指令集状态。每个位段都有明确的控制语义。User 模式只能看到受限的 APSR。

  5. CP15 是系统编程的入口:从读取 CPU 型号(MIDR)到设置页表基址(TTBR0),从控制缓存(c7)到定位异常向量表(VBAR),全部通过 MRC/MCR 完成。

  6. SCTLR 是 Boot 代码的必配项:C 位(数据缓存)、I 位(指令缓存)、Z 位(分支预测)、M 位(MMU)必须在 boot 过程中依次置位,它们是系统从”裸跑”切换到”缓存 + 分页”的硬件开关。