从复位到控制:在 ARM 裸机上禁用中断

发布: (2026年1月2日 GMT+8 14:59)
5 min read
原文: Dev.to

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] – 模式位

常用模式编码:

模式
User0x10
FIQ0x11
IRQ0x12
Supervisor0x13
Abort0x17
Undefined0x1B
System0x1F

显式禁用中断

cpsid 指令(Change Processor State, Interrupt Disable)提供对中断屏蔽的直接控制:

  • cpsid i – 禁用 IRQ
  • cpsid f – 禁用 FIQ
  • cpsid 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 运行时。

Back to Blog

相关文章

阅读更多 »

解码 ARM Cortex-Mx 异常入口与退出

引言 – 为什么要写这篇文章 在 ARM Cortex‑M 系列上进行中断处理在理论上看起来很简单,但一打开调试器就会变得令人困惑。 - PC v...