3. ARM Cortex-A 启动流程(上电到 Reset Vector)

本章深入分析 ARM Cortex-A 系列处理器从上电复位到执行第一条指令的完整启动流程。理解 ARMv7-A 与 ARMv8-A 架构的上电行为、异常向量表结构、Reset 处理流程以及 CPU 模式切换机制,是进行 Bootloader 开发和设备树移植的基础。

3.1 ARMv7-A/v8-A 上电行为

ARM Cortex-A 处理器在上电或复位后,硬件会自动执行一系列预定义操作,确保 CPU 进入一个已知的、可预测的状态。不同架构版本在上电行为上存在关键差异。

3.1.1 上电复位后的硬件状态

硬件组件 ARMv7-A 复位状态 ARMv8-A 复位状态
程序计数器 (PC) 0x00000000 (低地址) 或 0xFFFF0000 (高向量) 由 RVBAR 寄存器指定 (可配置)
处理器模式 SVC (超级用户模式) EL3 (最高异常等级)
中断 IRQ/FIQ 均被屏蔽 所有异常被屏蔽
MMU 关闭 (禁用地址转换) 关闭 (禁用地址转换)
Cache 禁用 (需软件使能) 禁用 (需软件使能)
栈指针 (SP) 未定义 (需软件初始化) 未定义 (需软件初始化)
关键概念: ARMv8-A 的 RVBAR (Reset Vector Base Address Register) 允许 SoC 设计者将复位向量映射到任意物理地址,这为多核启动和灵活的内存布局提供了支持。通常 RVBAR 的值由硬件配置引脚或 eFUSE 决定。

3.1.2 ARMv7-A 与 ARMv8-A 上电流程对比

ARMv7-A vs ARMv8-A 上电流程对比 ARMv7-A 上电/复位 PC = 0x00000000 模式 = SVC 中断屏蔽 取指执行 ARMv8-A 上电/复位 PC = RVBAR 异常等级 = EL3 所有异常屏蔽 取指执行 说明:ARMv8-A 的 RVBAR 机制允许 SoC 设计者灵活指定复位向量地址, 通常指向片内 ROM 中的 BootROM 代码,而非固定的 0x00000000。

3.2 异常向量表

异常向量表是处理器在发生异常时跳转的目标地址列表。ARM Cortex-A 支持两种向量表基址配置:低地址模式 (0x00000000) 和高地址模式 (0xFFFF0000)。在 ARMv8-A 中,向量表基址由 VBAR_ELx 寄存器控制。

3.2.1 ARMv7-A 异常向量表结构

向量偏移 异常类型 进入模式 优先级
0x00 Reset SVC 1 (最高)
0x04 Undefined Instruction Undef 6
0x08 Supervisor Call (SVC) SVC 6
0x0C Prefetch Abort Abort 5
0x10 Data Abort Abort 2
0x14 Reserved - -
0x18 IRQ (Interrupt Request) IRQ 4
0x1C FIQ (Fast Interrupt Request) FIQ 3
ARMv7-A 异常向量表布局 向量表基址 (0x00000000 或 0xFFFF0000) 0x00 Reset SVC 模式 0x04 Undefined Instruction Undef 模式 0x08 Supervisor Call (SVC) SVC 模式 0x0C Prefetch Abort Abort 模式 0x10 Data Abort Abort 模式 0x14 Reserved - 0x18 IRQ IRQ 模式 0x1C FIQ FIQ 模式 每个向量条目通常存放一条跳转指令 (B 或 LDR PC),指向对应的异常处理函数

3.2.2 ARMv8-A 异常向量表

ARMv8-A 的异常向量表更为复杂,每个异常等级 (EL) 拥有独立的向量表,由 VBAR_ELx 寄存器指定基址。每个向量表包含 16 个条目,每个条目占用 128 字节。

ARMv8-A 向量表条目布局: 每个异常等级有 4 个向量组 (Synchronous, IRQ, FIQ, SError),每组对应 4 种执行状态 (Current EL with SP0, Current EL with SPx, Lower EL using AArch64, Lower EL using AArch32),共 16 个条目。

3.3 Reset 处理流程

Reset 是优先级最高的异常,也是 Bootloader 的入口点。Reset 处理流程通常包括硬件初始化、软件环境准备和跳转到主程序三个阶段。

3.3.1 Reset 处理步骤

  1. 硬件自动操作: CPU 自动跳转到 Reset 向量地址,设置处理器模式为 SVC (ARMv7) 或 EL3 (ARMv8),屏蔽所有中断。
  2. 基本硬件初始化: 关闭看门狗、初始化 PLL 和时钟、配置内存控制器 (如 DDR 初始化)。
  3. CPU 模式切换: 根据需要切换到其他特权模式,初始化各模式下的栈指针 (SP)。
  4. 异常向量表重定位: 将异常向量表复制到 RAM 中,并设置 VBAR 寄存器指向新位置。
  5. BSS 段清零: 清除未初始化全局变量的内存区域。
  6. 数据段重定位: 将已初始化数据从 Flash 复制到 RAM。
  7. 跳转到主程序: 调用 main() 或启动内核。
Reset 处理完整流程 上电复位 关闭看门狗 初始化时钟/PLL 初始化 DDR 初始化栈指针 跳转到主程序 注意:DDR 初始化必须在栈初始化之前完成,因为 DDR 初始化代码本身可能需要栈支持

3.3.2 Reset 向量代码示例

@ ARMv7-A Reset 向量代码示例 (start.S)
.section .vectors, "ax"
.globl _start
_start:
    @ Reset 向量
    b   reset_handler
    @ Undefined Instruction 向量
    ldr pc, _undefined_instruction
    @ SVC 向量
    ldr pc, _software_interrupt
    @ Prefetch Abort 向量
    ldr pc, _prefetch_abort
    @ Data Abort 向量
    ldr pc, _data_abort
    @ Reserved
    nop
    @ IRQ 向量
    ldr pc, _irq
    @ FIQ 向量
    ldr pc, _fiq

reset_handler:
    @ 1. 切换到 SVC 模式并屏蔽中断
    mrs r0, cpsr
    bic r0, r0, #0x1F
    orr r0, r0, #0xD3    @ SVC 模式,IRQ/FIQ 屏蔽
    msr cpsr, r0

    @ 2. 关闭 MMU 和 Cache
    mrc p15, 0, r0, c1, c0, 0
    bic r0, r0, #0x0005  @ 关闭 MMU 和 DCache
    bic r0, r0, #0x1000  @ 关闭 ICache
    mcr p15, 0, r0, c1, c0, 0

    @ 3. 初始化栈指针
    ldr sp, =_stack_top

    @ 4. 清零 BSS 段
    ldr r0, =_bss_start
    ldr r1, =_bss_end
    mov r2, #0
bss_loop:
    cmp r0, r1
    strlo r2, [r0], #4
    blo bss_loop

    @ 5. 跳转到 main
    bl main
    b .

3.4 CPU 模式切换

ARM Cortex-A 处理器支持多种特权模式,每种模式拥有独立的寄存器组和栈空间。模式切换是 Bootloader 初始化过程中的关键步骤。

3.4.1 ARMv7-A 处理器模式

模式 CPSR M 位 可访问寄存器 用途
User (USR) 10000 R0-R14, PC, CPSR 普通应用程序执行
FIQ 10001 R0-R7, R8_fiq-R14_fiq, PC, CPSR, SPSR_fiq 快速中断处理
IRQ 10010 R0-R12, R13_irq-R14_irq, PC, CPSR, SPSR_irq 普通中断处理
Supervisor (SVC) 10011 R0-R12, R13_svc-R14_svc, PC, CPSR, SPSR_svc 操作系统内核、Bootloader
Abort 10111 R0-R12, R13_abt-R14_abt, PC, CPSR, SPSR_abt 内存访问异常处理
Undefined 11011 R0-R12, R13_und-R14_und, PC, CPSR, SPSR_und 未定义指令异常处理
System (SYS) 11111 R0-R14, PC, CPSR (共享 User 寄存器) 特权任务执行

3.4.2 ARMv8-A 异常等级

ARMv8-A 使用异常等级 (Exception Level, EL) 替代传统的处理器模式。EL0 最低,EL3 最高。

异常等级 名称 用途 对应 ARMv7 模式
EL0 User 应用程序 User
EL1 OS 操作系统内核 SVC
EL2 Hypervisor 虚拟化 Hyp (ARMv7.1)
EL3 Secure Monitor 安全监控 Monitor (ARMv7)

3.4.3 模式切换代码示例

@ ARMv7-A 模式切换示例:初始化各模式栈指针
.macro init_sp mode, stack_top
    mrs r0, cpsr
    bic r0, r0, #0x1F
    orr r0, r0, #\mode
    msr cpsr, r0
    ldr sp, =\stack_top
.endm

@ 在 Reset 处理中调用
init_sp 0xD3, _svc_stack_top    @ SVC 模式
init_sp 0xD2, _irq_stack_top    @ IRQ 模式
init_sp 0xD1, _fiq_stack_top    @ FIQ 模式
init_sp 0xD7, _abt_stack_top    @ Abort 模式
init_sp 0xDB, _und_stack_top    @ Undefined 模式

@ 切换回 SVC 模式继续执行
mrs r0, cpsr
bic r0, r0, #0x1F
orr r0, r0, #0xD3
msr cpsr, r0
重要提示: 在切换 CPU 模式时,必须确保目标模式的栈指针 (SP) 已经初始化。如果 SP 未初始化,任何使用栈的操作(如函数调用、压栈指令)都会导致不可预测的行为。Bootloader 中常见的死机问题往往源于栈指针未正确设置。

3.5 本章小结

ARM Cortex-A 的上电启动流程是 Bootloader 开发的基石。理解 ARMv7-A 与 ARMv8-A 在上电行为、异常向量表结构、Reset 处理流程和 CPU 模式切换方面的差异,对于编写正确的启动代码至关重要。在实际的 Bootloader 开发中,需要根据具体的 SoC 平台和 ARM 架构版本,灵活调整初始化流程。