2. 基础知识:ARM体系结构基础
ARMv9架构作为当前Arm技术路线中的旗舰级设计,其体系结构基础决定了上层软件系统的运行方式与安全边界。理解指令集、异常模型、内存模型、寄存器组及特权级别这五大核心要素,是后续深入学习MMU、GIC、TrustZone与RME(Realm Management Extension)的必备前提。本章将从底层机制出发,结合AArch64执行状态,系统梳理这些基础概念,并建立它们之间的内在关联。
2.1 指令集:A64与执行状态切换
ARMv9架构的核心执行状态为AArch64,其对应的A64指令集采用固定32位编码,提供31个64位通用寄存器(X0-X30)以及专用的栈指针(SP)和程序计数器(PC)。A64指令集的设计强调低延迟异常处理与高效的加载/存储架构,所有数据处理操作均在寄存器中完成,内存访问仅通过显式的LDR/STR系列指令进行。
在兼容性方面,ARMv9保留了AArch32执行状态以支持存量32位软件。系统通过异常返回或异常进入时的SPSR_ELx.M字段实现两种执行状态的切换。例如,当EL0的32位应用触发系统调用(SVC #0)时,处理器切换到AArch64的EL1,异常返回时通过ERET指令恢复32位状态。这种设计使得SoC可以同时运行64位操作系统与32位遗留应用。
2.1.1 指令集对比与选择
| 特性 | A64 (ARMv8/9) | A32 (ARMv7) | T32 (Thumb-2) |
|---|---|---|---|
| 指令长度 | 固定32位 | 固定32位 | 16/32位混合 |
| 通用寄存器 | 31×64位 | 15×32位 | 15×32位 |
| 条件执行 | 仅少数指令 | 几乎全部指令 | 部分指令 |
| PC访问 | 不可直接读 | 可读 | 可读 |
| 适用场景 | 现代OS、应用处理器 | 传统应用、MCU | 代码密度敏感场景 |
2.2 异常模型:同步与异步的统一处理
ARMv9的异常模型将中断、陷阱、系统调用统一抽象为“异常”(Exception)。异常分为同步异常(如未定义指令、数据中止、SVC指令)和异步异常(如IRQ、FIQ、SError)。所有异常都通过异常向量表(Vector Table)分发,向量表基地址由VBAR_ELx寄存器指定,每个异常级别拥有独立的向量表。
异常进入时,处理器自动保存当前状态到SPSR_ELx,将返回地址存入ELR_ELx,并根据异常类型跳转到对应向量偏移。异常返回使用ERET指令,该指令同时完成PC恢复与PSTATE恢复。值得注意的是,ARMv9引入了异常路由机制:EL3(Secure Monitor)可以配置中断路由策略,例如将FIQ强制路由到EL3,用于实现安全世界与普通世界之间的快速切换。
SCR_EL3寄存器中的IRQ/FIQ路由位,决定中断是直接进入EL3还是被屏蔽到EL1。例如,当启用Secure-EL1的定时器中断时,需要将FIQ路由到EL3,再由EL3转发到S-EL1,确保安全世界的中断不被普通世界抢占。
2.2.1 异常向量表布局
// 每个异常级别(EL0-EL3)的向量表共16个条目,每个条目占128字节
// 偏移布局如下:
// 0x000: SP_EL0 同步异常
// 0x080: SP_EL0 IRQ
// 0x100: SP_EL0 FIQ
// 0x180: SP_EL0 SError
// 0x200: SP_ELx 同步异常
// 0x280: SP_ELx IRQ
// 0x300: SP_ELx FIQ
// 0x380: SP_ELx SError
// 0x400: 低EL AArch64 同步异常
// 0x480: 低EL AArch64 IRQ
// 0x500: 低EL AArch64 FIQ
// 0x580: 低EL AArch64 SError
// 0x600: 低EL AArch32 同步异常
// 0x680: 低EL AArch32 IRQ
// 0x700: 低EL AArch32 FIQ
// 0x780: 低EL AArch32 SError
2.3 内存模型:从单核到多核一致性
ARMv9内存模型定义了处理器对内存访问的观测顺序与一致性规则。其核心是弱内存模型(Weakly Ordered),即在不违反数据依赖关系的前提下,允许处理器和编译器重排内存访问指令。为了在弱模型下保证正确性,ARM提供了内存屏障指令(DMB、DSB、ISB)以及获取/释放语义的原子指令(LDXR/STXR、CAS)。
内存属性通过页表项中的属性字段配置,包括缓存策略(Write-Back/Write-Through)、共享属性(Non-shareable/Inner-shareable/Outer-shareable)以及执行权限(XN位)。多核系统中,处理器通过缓存一致性协议(如MESI)维护共享数据的一致性,而内存模型则定义了不同共享域之间的同步语义。
LDAR/STLR或显式屏障来保证顺序。
2.3.1 内存属性配置示例
| MAIR索引 | 属性 | 典型用途 |
|---|---|---|
| 0x00 | Device-nGnRnE | 外设寄存器(UART、GIC) |
| 0x04 | Normal Non-cacheable | DMA描述符 |
| 0x44 | Normal Write-Back | 常规RAM |
| 0xff | Normal Write-Through | 帧缓冲(部分场景) |
2.4 寄存器组:通用、系统与状态寄存器
AArch64架构提供31个64位通用寄存器(X0-X30),其中X30作为链接寄存器(LR)保存函数返回地址。此外,系统寄存器(System Registers)通过MRS/MSR指令访问,用于配置MMU、异常、调试等核心功能。每个异常级别拥有独立的系统寄存器视图,例如TCR_EL1与TCR_EL2分别控制EL1/EL0和EL2/EL1的地址翻译配置。
状态寄存器PSTATE并非一个物理寄存器,而是由多个字段组成的抽象视图,包括条件标志位(NZCV)、当前异常级别(EL)、执行状态(AArch64/AArch32)以及中断屏蔽位(DAIF)。异常进入时,PSTATE被保存到SPSR_ELx;异常返回时,ERET从SPSR_ELx恢复PSTATE。
ERET返回用户态。整个过程涉及通用寄存器、系统寄存器(TTBR0_EL1用于用户地址空间)和PSTATE的协同操作。
2.5 特权级别:安全世界的分层与隔离
ARMv9定义了四个异常级别(EL0-EL3),其中EL0为用户态,EL1为操作系统内核,EL2为虚拟化层(Hypervisor),EL3为安全监控器(Secure Monitor)。EL0-EL2在普通世界(Normal World)运行,而EL3负责在普通世界与安全世界(Secure World)之间切换。安全世界拥有独立的EL0/EL1,运行可信固件与安全服务。
特权级别的核心价值在于隔离:低特权级别无法直接访问高特权级别的资源,所有跨级别操作必须通过异常进入。例如,EL0应用无法直接操作MMU配置,必须通过SVC指令陷入EL1内核。ARMv9的RME扩展进一步引入了Realm Management Extension,在EL2之下新增了R-EL2级别,用于保护机密计算场景中的Realm世界。
CurrentEL系统寄存器判断当前异常级别。例如,在U-Boot或ATF中打印CurrentEL的值,若为0b01表示EL1,0b10表示EL2,0b11表示EL3。这有助于确认固件是否运行在预期的特权级别。
2.5.1 特权级别与典型软件栈
| 异常级别 | 典型软件 | 主要职责 |
|---|---|---|
| EL0 | 应用程序 | 用户逻辑、不直接访问硬件 |
| EL1 | Linux/RTOS内核 | 进程调度、内存管理、驱动 |
| EL2 | Hypervisor (KVM/Xen) | 虚拟CPU调度、内存虚拟化 |
| EL3 | ATF (BL31) | 安全世界切换、PSCI电源管理 |
2.6 综合案例:系统启动时的特权级别迁移
以ARMv9应用处理器启动流程为例,系统上电后首先在EL3执行ROM代码,随后加载ATF BL31到EL3。BL31初始化安全世界环境后,通过ERET降级到EL2执行Hypervisor或直接降级到EL1执行内核。内核启动过程中,通过配置SCR_EL3允许EL1访问必要的系统寄存器,并设置VBAR_EL1指向内核异常向量表。
当用户态应用需要读取硬件信息时,执行SVC #0指令,处理器陷入EL1,内核根据SVC编号分发处理。若需要与安全世界通信,内核通过SMC指令陷入EL3,由BL31切换到安全世界执行可信服务。整个过程体现了异常模型、特权级别与寄存器组的紧密协作。
SCR_EL3的NS位,可能导致安全世界与普通世界的内存映射混淆,引发严重的安全漏洞。务必在切换世界之前,确保MMU页表与缓存状态完全隔离。
2.7 总结与常见误区复盘
本章系统梳理了ARMv9体系结构的五大基础模块。在实际开发中,常见误区包括:混淆AArch64与AArch32的寄存器视图、忽略内存屏障导致的数据竞争、错误配置异常向量表基地址、以及在EL3代码中直接访问EL1专用寄存器。建议开发者始终从特权级别视角审视代码路径,明确当前执行上下文,并利用ARM架构参考手册中的伪代码验证关键操作。