从复位到控制:在 ARM 裸机上禁用中断
Source: Dev.to
裸金属在 ARMv7 上的执行从复位向量开始,远早于任何 C 环境的出现。当 Cortex‑A9 在 QEMU 的 vexpress‑a9 模型下复位后,处理器进入 Supervisor 模式,且中断被屏蔽,MMU 被禁用。栈指针未定义,内存段未初始化,也没有安装任何处理程序。执行仅在已定义的程序计数器和 CPSR 值下开始。
本文检查了执行的最早阶段,并展示了最小的启动汇编块在复位后如何接管控制:显式屏蔽中断、验证处理器模式,并在已知状态下停机。这为在引入栈、内存初始化以及最终的 C 运行时之前,建立了可预测的基准。
从复位向量到 _start
在复位时,ARMv7 定义了以下初始条件:
- 模式: Supervisor (
0b10011) - IRQ 掩码 (CPSR.I): 1(禁用)
- FIQ 掩码 (CPSR.F): 1(禁用)
- 指令集: ARM 状态
- MMU: 已禁用
虽然在架构上复位时会屏蔽中断,但早期启动代码不应依赖这种隐式状态。显式地关闭中断可确保在安装向量表或异常处理程序之前拥有确定性的环境。
之前的文章 Bare Metal ARM Boot: Understanding the Reset Vector and First Instructions 建立了一个最小的向量表和复位向量:
- 向量表放置在 flash 的地址
0x0 - 复位向量从
_vectors跳转到_start _start包含一个无限循环
本文在该示例的基础上,为 _start 添加了其第一个真实职责:在停机前强制屏蔽中断。
CPSR概述
Current Program Status Register (CPSR) 控制执行的关键方面:
- 位 [31:28] – 条件标志 (N, Z, C, V)
- 位 7 – IRQ 禁用 (I)
- 位 6 – FIQ 禁用 (F)
- 位 [4:0] – 模式位
常用模式编码:
| 模式 | 值 |
|---|---|
| User | 0x10 |
| FIQ | 0x11 |
| IRQ | 0x12 |
| Supervisor | 0x13 |
| Abort | 0x17 |
| Undefined | 0x1B |
| System | 0x1F |
显式禁用中断
cpsid 指令(Change Processor State, Interrupt Disable)提供对中断屏蔽的直接控制:
cpsid i– 禁用 IRQcpsid f– 禁用 FIQcpsid if– 同时禁用两者
cpsid 是特权指令,只能在诸如 Supervisor 等特权模式下执行。在启动时发出 cpsid if 可以防止在有效的异常处理程序就绪之前意外进入异常。
最小启动汇编
.section .vectors, "ax"
.global _vectors
_vectors:
b _start @ Reset vector: branch to startup
.section .text
.global _start
_start:
@ Disable IRQ and FIQ interrupts
cpsid if
@ Infinite loop
halt:
b halt
使用 GDB 验证行为
A breakpoint confirms that execution flows from the reset vector into _start:
(gdb) break _start
Breakpoint 1 at 0x4: file startup.s, line 9.
(gdb) continue
Continuing.
Breakpoint 1, _start () at startup.s:9
9 cpsid if
Examining the CPSR before and after executing cpsid if:
(gdb) info registers cpsr
cpsr 0x400001d3 1073742291
(gdb) stepi
10 b .
(gdb) info registers cpsr
cpsr 0x400001d3 1073742291
The CPSR value remains unchanged because interrupts were already masked at reset.
Binary view:
(gdb) print/t $cpsr
$1 = 1000000000000000000000111010011
解释
- 位[4:0] =
10011→ 监督模式 - 位6 = 1 → FIQ 禁用
- 位7 = 1 → IRQ 禁用
这确认了启动代码在特权模式下运行,且两种中断源均已被屏蔽。
Conclusion
处理器现在能够从复位平稳过渡到启动汇编代码,建立受控的执行状态。中断屏蔽被明确强制,处理器模式得到验证。有了这个基础,后续步骤——堆栈设置、.data 和 .bss 初始化,以及进入 main()——可以安全地引入。
下一篇文章将基于这个最小的引导程序,构建适用于裸机 ARM 系统的可用 C 运行时。