2. ARM Cortex-A 异常模型:异常类型、向量表与处理模式
ARM Cortex-A 处理器的异常模型是中断控制器 GIC 驱动开发的底层硬件基础。理解异常类型、向量表基地址以及处理模式与寄存器组的关系,是编写可靠中断处理程序的前提。本章将系统梳理 ARMv7-A 和 ARMv8-A 架构下的异常模型核心概念。
2.1 异常类型与优先级
ARM Cortex-A 处理器支持多种异常源,每种异常对应一个固定的优先级和入口地址。下表列出了 ARMv7-A 架构下的主要异常类型及其属性:
| 异常类型 | 异常模式 | 优先级(0最高) | 触发条件 |
|---|---|---|---|
| Reset | SVC | 0 | 上电或复位信号 |
| Data Abort | Abort | 1 | 数据访问失效(MMU 缺页/权限错误) |
| FIQ | FIQ | 2 | 快速中断请求(GIC 可配置为 FIQ) |
| IRQ | IRQ | 3 | 普通中断请求(GIC 默认输出) |
| Prefetch Abort | Abort | 4 | 指令预取失效 |
| Undefined Instruction | Undefined | 5 | 执行未定义指令 |
| Supervisor Call (SVC) | SVC | 6 | 执行 SVC 指令(系统调用) |
关键理解:FIQ 的优先级高于 IRQ,且拥有独立的寄存器组(R8~R14_fiq),因此 FIQ 处理程序无需保存/恢复这些寄存器,响应速度更快。在 GIC 驱动中,可以将高优先级中断映射为 FIQ 信号。
2.2 异常向量表基地址
异常向量表是处理器在发生异常时跳转的目标地址集合。ARM Cortex-A 支持两种向量表基地址配置方式:
- 低向量(Low Vectors):基地址固定为
0x00000000,用于传统裸机或简单系统。 - 高向量(High Vectors):基地址固定为
0xFFFF0000,通常由 Linux 内核使用。
在 ARMv7-A 中,通过协处理器 CP15 的 c1 寄存器(SCTLR)的 V 位选择:
MRC p15, 0, r0, c1, c0, 0 ; 读取 SCTLR
ORR r0, r0, #(1 << 13) ; 设置 V 位,选择高向量
MCR p15, 0, r0, c1, c0, 0 ; 写入 SCTLR
向量表在内存中的布局如下(每个向量占用 4 字节,存放一条跳转指令):
2.3 异常处理模式与寄存器组
ARM Cortex-A 处理器在进入异常时,会自动切换到对应的处理器模式。每种模式拥有独立的寄存器组(Banked Registers),用于保存上下文。下表展示了各模式下的寄存器映射关系:
| 寄存器 | User/System | FIQ | IRQ | SVC | Abort | Undefined |
|---|---|---|---|---|---|---|
| R0~R7 | R0~R7 | R0~R7 | R0~R7 | R0~R7 | R0~R7 | R0~R7 |
| R8~R12 | R8~R12 | R8_fiq~R12_fiq | R8~R12 | R8~R12 | R8~R12 | R8~R12 |
| R13 (SP) | R13_usr | R13_fiq | R13_irq | R13_svc | R13_abt | R13_und |
| R14 (LR) | R14_usr | R14_fiq | R14_irq | R14_svc | R14_abt | R14_und |
| SPSR | — | SPSR_fiq | SPSR_irq | SPSR_svc | SPSR_abt | SPSR_und |
驱动开发要点:在 GIC 中断处理程序中,IRQ 模式使用独立的 R13_irq(栈指针)和 R14_irq(链接寄存器)。这意味着中断处理程序必须使用 IRQ 模式下的栈,并在退出前恢复被中断任务的上下文。FIQ 模式拥有更多的私有寄存器(R8~R12),因此 FIQ 处理程序可以避免保存这些寄存器,从而获得更快的响应速度。
2.4 异常处理流程
当 ARM Cortex-A 处理器检测到异常时,硬件自动执行以下操作:
- 保存返回地址:将当前 PC 值存入对应模式的 R14(LR)寄存器。
- 保存 CPSR:将当前 CPSR 值存入对应模式的 SPSR 寄存器。
- 切换模式:修改 CPSR 的模式位,切换到对应的异常模式。
- 禁用中断:设置 CPSR 的 I 位(IRQ 禁用)和 F 位(FIQ 禁用),防止嵌套中断。
- 跳转向量表:根据异常类型,从向量表基地址 + 偏移处读取指令并执行。
以下是一个典型的 IRQ 中断处理程序入口代码示例:
.section .vectors, "ax"
.global _start
_start:
ldr pc, reset_handler @ 0x00: Reset
ldr pc, undef_handler @ 0x04: Undefined Instruction
ldr pc, svc_handler @ 0x08: Supervisor Call
ldr pc, pabt_handler @ 0x0C: Prefetch Abort
ldr pc, dabt_handler @ 0x10: Data Abort
nop @ 0x14: Reserved
ldr pc, irq_handler @ 0x18: IRQ
ldr pc, fiq_handler @ 0x1C: FIQ
irq_handler:
sub lr, lr, #4 @ 修正返回地址
srsdb sp!, #0x12 @ 保存 LR_irq 和 SPSR_irq 到 IRQ 栈
cpsid i, #0x13 @ 切换到 SVC 模式,仍禁用 IRQ
push {r0-r3, r12, lr} @ 保存被调用者寄存器
@ 调用 GIC 中断处理函数
bl gic_handle_irq
pop {r0-r3, r12, lr} @ 恢复寄存器
rfeia sp! @ 从栈恢复 PC 和 CPSR
常见错误:在 IRQ 处理程序中直接使用
MOVS PC, LR 返回是错误的,因为 IRQ 模式下 LR 的值需要先减去 4(由于 ARM 流水线特性)。正确的做法是使用 SUBS PC, LR, #4 或通过栈恢复。
2.5 ARMv8-A 异常模型差异
ARMv8-A(AArch64)引入了全新的异常模型,与 ARMv7-A 有显著不同:
- 异常级别(Exception Levels):EL0(用户态)、EL1(内核态)、EL2(虚拟化)、EL3(安全监控)。
- 向量表基地址:通过
VBAR_EL1、VBAR_EL2、VBAR_EL3分别配置。 - 向量表大小:每个向量条目占用 128 字节(32 条指令),支持同步异常、IRQ、FIQ 和 SError。
- 寄存器组:每个异常级别拥有独立的 SP_ELx、SPSR_ELx、ELR_ELx 寄存器。
下表对比了 ARMv7-A 和 ARMv8-A 在中断处理方面的关键差异:
| 特性 | ARMv7-A (AArch32) | ARMv8-A (AArch64) |
|---|---|---|
| 异常模式 | 7 种处理器模式(FIQ/IRQ/SVC 等) | 4 个异常级别(EL0~EL3) |
| 向量表基地址 | VBAR(CP15 寄存器) | VBAR_EL1/EL2/EL3 |
| 向量条目大小 | 4 字节(1 条指令) | 128 字节(32 条指令) |
| 中断信号 | IRQ / FIQ | IRQ / FIQ / SError |
| 返回指令 | MOVS PC, LR / SUBS PC, LR, #4 | ERET |
| 栈指针 | 各模式独立 SP | 各异常级别独立 SP_ELx |
GIC 驱动适配:在 ARMv8-A 系统中,GIC 驱动需要根据当前异常级别配置中断路由。例如,在 EL1 下运行的 Linux 内核,GIC 中断被配置为 IRQ 信号,通过
VBAR_EL1 中的 IRQ 向量入口处理。在 EL3 下的安全监控程序(如 ARM Trusted Firmware)则使用 VBAR_EL3 处理 FIQ。
2.6 异常模型与 GIC 的交互
GIC 作为中断控制器,其输出信号(IRQ/FIQ)直接连接到处理器的异常输入引脚。下图展示了从外设中断到处理器异常处理的完整链路:
在 GIC 驱动开发中,需要重点关注以下与异常模型相关的配置点:
- 中断信号类型:GIC 可以配置为输出 IRQ 或 FIQ,驱动需根据处理器模式选择对应的向量表条目。
- 中断优先级分组:GIC 支持优先级分组(Group 0/1),Group 0 中断通常路由到 FIQ,Group 1 路由到 IRQ。
- 中断确认与完成:处理器在中断处理程序中必须通过 GIC CPU 接口寄存器(ICC_EOIR)发送中断完成信号,否则 GIC 不会发送后续中断。
- 嵌套中断:在 IRQ 处理程序中,如果需要支持高优先级中断抢占,必须手动重新使能 IRQ(清除 CPSR 的 I 位),并保存/恢复嵌套上下文。
实战经验:在编写 GIC 中断处理程序时,建议在 IRQ 入口处立即读取
ICC_IAR 寄存器获取中断 ID,然后切换到 SVC 模式执行实际处理逻辑。这样可以避免在 IRQ 模式下长时间运行,减少对栈指针(R13_irq)的压力,并允许在 SVC 模式下安全地使能嵌套中断。