4. ARM异常处理机制
ARM架构的异常处理机制是嵌入式系统稳定运行的核心保障。当CPU遇到中断、未定义指令、数据访问错误等事件时,会暂停当前程序流,跳转到预定义的异常处理程序。理解异常类型、向量表布局、优先级规则以及处理流程,是进行Bootloader开发和ARM平台移植的基础。
核心要点: ARM异常机制采用固定的向量表、硬件自动保存/恢复上下文、以及通过模式切换实现特权级隔离。Bootloader中常利用SVC模式切换来执行系统调用。
4.1 异常类型
ARM架构定义了7种异常类型(以ARMv7-A为例),每种异常对应一个固定的向量偏移地址和CPU模式。
| 异常类型 | 向量偏移 | CPU模式 | 触发条件 |
|---|---|---|---|
| 复位 (Reset) | 0x00 | SVC (特权) | 上电或复位信号 |
| 未定义指令 (Undefined Instruction) | 0x04 | UND (特权) | CPU无法识别的指令 |
| 软件中断 (SWI / SVC) | 0x08 | SVC (特权) | 执行SVC指令(系统调用) |
| 预取中止 (Prefetch Abort) | 0x0C | ABT (特权) | 指令预取时地址无效 |
| 数据中止 (Data Abort) | 0x10 | ABT (特权) | 数据访问时地址无效 |
| IRQ (中断请求) | 0x18 | IRQ (特权) | 外部硬件中断 |
| FIQ (快速中断请求) | 0x1C | FIQ (特权) | 高速外部硬件中断 |
Bootloader视角: 复位异常是Bootloader的入口点。SVC异常常用于Bootloader向用户程序提供底层服务接口(如串口打印、内存读写)。FIQ通常留给对实时性要求极高的外设(如DMA传输完成)。
4.2 异常向量表
异常向量表是一段位于内存低地址(或高地址,取决于配置)的连续存储区域,每个表项存放一条跳转指令(如B、LDR PC)或直接存放异常处理函数的地址。ARM默认将向量表放置在地址0x00000000处。
; 典型的ARM异常向量表(汇编代码)
.section .vectors, "ax"
.global _start
_start:
ldr pc, =reset_handler ; 0x00: 复位
ldr pc, =undefined_handler ; 0x04: 未定义指令
ldr pc, =svc_handler ; 0x08: 软件中断 (SVC)
ldr pc, =prefetch_handler ; 0x0C: 预取中止
ldr pc, =data_abort_handler ; 0x10: 数据中止
nop ; 0x14: 保留
ldr pc, =irq_handler ; 0x18: IRQ
ldr pc, =fiq_handler ; 0x1C: FIQ
移植注意: 在U-Boot中,向量表通常位于链接脚本指定的起始地址(如CONFIG_SYS_TEXT_BASE)。如果使用MMU并启用高向量(0xFFFF0000),必须确保向量表被正确映射到该地址。
4.3 异常优先级
当多个异常同时发生时,ARM硬件按照固定的优先级顺序响应。优先级从高到低排列如下:
- 复位 (Reset) — 最高优先级,任何异常都无法抢占复位。
- 数据中止 (Data Abort) — 优先级高于FIQ和IRQ。
- FIQ — 快速中断,优先级高于IRQ。
- IRQ — 普通中断。
- 预取中止 (Prefetch Abort) — 优先级低于IRQ。
- 未定义指令 (Undefined Instruction) — 与SVC同级,但SVC由指令主动触发。
- SVC (软件中断) — 最低优先级(由用户程序主动调用)。
设计启示: FIQ拥有独立的寄存器组(R8~R14_fiq),无需压栈即可快速响应,因此Bootloader中可将紧急的看门狗喂狗或电源管理任务放在FIQ中。IRQ则用于普通外设中断。
4.4 异常处理流程
ARM异常处理由硬件自动完成部分操作,然后跳转到软件处理程序。以IRQ为例,完整流程如下:
- 步骤1(硬件): 保存当前PC到LR_irq(LR = PC - 4),保存CPSR到SPSR_irq。
- 步骤2(硬件): 设置CPSR中的模式位为IRQ模式,并屏蔽IRQ(设置I位)。
- 步骤3(硬件): 强制PC跳转到向量表0x18处。
- 步骤4(软件): 从向量表跳转到实际的IRQ处理函数。
- 步骤5(软件): 保存被中断程序的上下文(R0~R12、LR等)。
- 步骤6(软件): 识别中断源并执行对应的服务程序。
- 步骤7(软件): 恢复上下文,执行异常返回指令(SUBS PC, LR, #4)。
; IRQ异常处理入口示例(简化)
irq_handler:
sub lr, lr, #4 ; 修正返回地址
stmfd sp!, {r0-r12, lr} ; 保存上下文
bl irq_dispatch ; 调用C语言中断分发函数
ldmfd sp!, {r0-r12, pc}^ ; 恢复上下文并返回(^表示同时恢复SPSR到CPSR)
4.5 SVC模式切换
SVC(Supervisor)模式是ARM的最高特权模式之一,复位后CPU默认进入SVC模式。在Bootloader中,SVC模式切换通常用于以下场景:
- 系统调用: 用户程序通过执行SVC指令陷入内核,请求Bootloader提供的服务(如读取Flash、设置时钟)。
- 模式初始化: Bootloader启动时,需要从其他模式(如IRQ、FIQ)切换回SVC模式以配置系统资源。
- 上下文隔离: 利用SVC模式独立的堆栈指针(SP_svc)和寄存器组,保护关键数据不被用户模式破坏。
; 从用户模式切换到SVC模式(汇编)
; 假设当前在用户模式,需要执行特权操作
svc #0x01 ; 触发SVC异常,CPU自动切换到SVC模式
; 异常处理程序根据立即数0x01执行对应服务
; 直接修改CPSR切换模式(仅在当前为特权模式时有效)
mrs r0, cpsr ; 读取当前CPSR
bic r0, r0, #0x1F ; 清除模式位
orr r0, r0, #0x13 ; 设置为SVC模式 (M[4:0] = 10011)
msr cpsr_c, r0 ; 写入CPSR,完成模式切换
U-Boot实践: U-Boot的启动代码(start.S)在复位后立即设置SP_svc,并确保CPU处于SVC模式。后续所有初始化操作(如关闭看门狗、初始化时钟、配置MMU)都在SVC模式下完成,以保证对系统资源的完全控制。
总结: ARM异常处理机制通过硬件与软件的紧密配合,实现了高效、安全的系统响应。在Bootloader移植中,正确设置异常向量表、合理分配异常优先级、以及熟练运用SVC模式切换,是确保系统稳定启动和可靠运行的关键。