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),必须确保向量表被正确映射到该地址。
ARM异常向量表布局(低向量模式) 基地址 0x00000000 0x00: 复位 (Reset) ldr pc, =reset_handler 0x04: 未定义指令 (Undef) ldr pc, =undefined_handler 0x08: 软件中断 (SVC) ldr pc, =svc_handler 0x0C: 预取中止 (Prefetch Abort) ldr pc, =prefetch_handler 0x10: 数据中止 (Data Abort) ldr pc, =data_abort_handler 0x18: IRQ (中断请求) ldr pc, =irq_handler 每个表项占用4字节,共8个表项(32字节)

4.3 异常优先级

当多个异常同时发生时,ARM硬件按照固定的优先级顺序响应。优先级从高到低排列如下:

  1. 复位 (Reset) — 最高优先级,任何异常都无法抢占复位。
  2. 数据中止 (Data Abort) — 优先级高于FIQ和IRQ。
  3. FIQ — 快速中断,优先级高于IRQ。
  4. IRQ — 普通中断。
  5. 预取中止 (Prefetch Abort) — 优先级低于IRQ。
  6. 未定义指令 (Undefined Instruction) — 与SVC同级,但SVC由指令主动触发。
  7. 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)
ARM异常处理流程(以IRQ为例) 当前程序执行 硬件:保存PC→LR_irq 保存CPSR→SPSR_irq 硬件:切换至IRQ模式,屏蔽IRQ 硬件:PC跳转到0x18向量表 软件:保存上下文 识别中断源 → 执行ISR 恢复上下文,异常返回

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模式下完成,以保证对系统资源的完全控制。
SVC模式切换流程 用户模式 (USR) 执行 svc #imm 指令 SVC异常入口 硬件自动切换模式 SVC模式 (特权) 执行系统调用服务 返回用户模式 MOVS PC, LR 恢复 SVC模式拥有独立的堆栈(SP_svc)和SPSR,确保用户模式无法破坏特权上下文 Bootloader中所有硬件初始化均在SVC模式下完成
总结: ARM异常处理机制通过硬件与软件的紧密配合,实现了高效、安全的系统响应。在Bootloader移植中,正确设置异常向量表、合理分配异常优先级、以及熟练运用SVC模式切换,是确保系统稳定启动和可靠运行的关键。