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) | 未定义 (需软件初始化) | 未定义 (需软件初始化) |
3.1.2 ARMv7-A 与 ARMv8-A 上电流程对比
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 |
3.2.2 ARMv8-A 异常向量表
ARMv8-A 的异常向量表更为复杂,每个异常等级 (EL) 拥有独立的向量表,由 VBAR_ELx 寄存器指定基址。每个向量表包含 16 个条目,每个条目占用 128 字节。
3.3 Reset 处理流程
Reset 是优先级最高的异常,也是 Bootloader 的入口点。Reset 处理流程通常包括硬件初始化、软件环境准备和跳转到主程序三个阶段。
3.3.1 Reset 处理步骤
- 硬件自动操作: CPU 自动跳转到 Reset 向量地址,设置处理器模式为 SVC (ARMv7) 或 EL3 (ARMv8),屏蔽所有中断。
- 基本硬件初始化: 关闭看门狗、初始化 PLL 和时钟、配置内存控制器 (如 DDR 初始化)。
- CPU 模式切换: 根据需要切换到其他特权模式,初始化各模式下的栈指针 (SP)。
- 异常向量表重定位: 将异常向量表复制到 RAM 中,并设置 VBAR 寄存器指向新位置。
- BSS 段清零: 清除未初始化全局变量的内存区域。
- 数据段重定位: 将已初始化数据从 Flash 复制到 RAM。
- 跳转到主程序: 调用 main() 或启动内核。
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
3.5 本章小结
ARM Cortex-A 的上电启动流程是 Bootloader 开发的基石。理解 ARMv7-A 与 ARMv8-A 在上电行为、异常向量表结构、Reset 处理流程和 CPU 模式切换方面的差异,对于编写正确的启动代码至关重要。在实际的 Bootloader 开发中,需要根据具体的 SoC 平台和 ARM 架构版本,灵活调整初始化流程。