:::info
学习笔记记录,非教程。
:::
Cortex-A中断向量[1]表有8个中断,其中重点关注IRQ。Cortex-A的中断向量表需要用户自己去定义。
各中断的简单介绍:
其中IRQ中断为非向量中断,所有中断共享同一入口,再软件判断来源。
大概是这样:
通过设置中断向量表偏移,指定中断向量表的地址。
类似于STM32的NVIC,CortexA7使用 GIC v2 作为中断控制器,比NVIC更强大因为GIC能处理多核的中断。
ARM GIC 主要由两部分组成:
GIC 的核心流程基本就是三步:
中断的 ID Card。
向量表的“表项”是指令,不是纯地址。
每个向量入口的指令都指向某个具体的处理函数(Reset_Handler、IRQ_Handler 等)。
当发生异常,CPU 硬件会取指执行入口指令 → ldr pc, =xxx
→ 跳到真正的处理函数。
这样,只要依次写好这些跳转指令,后续再告诉cpu这些指令在哪个位置,就等于告诉 CPU“各种异常该去哪”。
:::danger
中断向量表必须按固定顺序来定义,顺序是由 ARM 硬件架构规定的,不是随便排列的。这样CPU才能正确处理不同的异常
:::
1 |
|
关闭I、D Cache 和MMU
CP15 是 Cortex-A 系列处理器的 系统控制寄存器集,其中 SCTLR(System Control Register, c1) 控制了处理器的一些核心行为,例如:
位 | 功能 |
---|---|
M | MMU 使能位(Memory Management Unit) |
C | 数据缓存使能位 |
I | 指令缓存使能位 |
A | 对齐检查(Alignment)使能 |
Z | 缓存清零 / 压缩乘法指令 |
V | 高速异常向量表 |
… | 其他一些调试、异常行为控制 |
在复位后,SCTLR 寄存器的初始值不一定是你想要的运行状态。不同的 SoC 或板级支持包可能默认值不同,有些位可能 默认启用某些功能但不适合裸机启动阶段。
在裸机启动阶段,你通常需要:
禁用 MMU 和缓存:
关闭对齐检查:
保证指令执行顺序一致:
统一系统行为:
如果不重置这些位可能的风险:
访问未定义:
数据不一致:
异常频发:
调试困难:
代码如下:
1 |
|
访问CP15 VBAR(Vector Base Address Register)寄存器,该寄存器是专门指定中断向量表偏移首地址的。
dsb
(Data Synchronization Barrier)保证所有数据访问指令执行完再继续。isb
(Instruction Synchronization Barrier)保证新的 VBAR 设置马上生效,不会被 CPU 指令流水线里的旧指令影响。1 |
|
内核工作在不同模式下,User模式和是Sys模式共用sp寄存器,而其他模式是独享一个sp寄存器。
在编译链接后,程序的内存布局通常分为几个主要段:
.text:存放代码(只读)。
.data:存放已初始化的全局/静态变量(初始值不为 0)。
.bss:存放未初始化的或者初始化为 0 的全局/静态变量。
.bss
只在运行时需要分配内存,编译产物中不占用存储空间(只是记录了大小),这样可以减少可执行文件体积。
根据 C 语言标准:
所有未显式初始化的全局变量、静态变量在程序开始执行前必须被初始化为 0。
这意味着:
如果 bss
段中的内容不是全 0,程序可能会读到随机的旧内存内容。
硬件上,RAM 启动后可能是杂乱的值(上电状态、上次运行残留、调试器写入等)。
因此,启动代码(crt0 或汇编 startup.s)通常会在 main()
之前清零 bss 段,保证所有这些变量是干净的 0。
1 |
|
一旦 CPU 进入 IRQ 模式,中断处理代码首先:
把 lr
(中断返回地址)、r0
~r3
、r12
等易被破坏的寄存器压栈保存。
保存 SPSR
(中断进入时的 CPSR 状态),以便中断结束时恢复原任务的运行状态。
目的:防止中断服务过程破坏被中断的程序的寄存器内容和运行状态。
读取 GICC_IAR(Interrupt Acknowledge Register)寄存器。
这个寄存器会返回当前触发的中断 ID(是哪一个外设触发的 IRQ)。
目的:确定是哪个具体中断源发生了 IRQ。
ARMv7-A 的 IRQ 模式不适合直接运行通用 C 代码(栈、寄存器不统一),所以这里切到 SVC 模式。
在 SVC 模式下调用 system_irqhandler
(C 写的总中断处理函数)。
system_irqhandler
会根据中断号去调用具体外设的中断处理例程。
目的:统一用 SVC 模式的栈和环境执行中断逻辑,方便用 C 语言写 ISR 分发器。
切回 IRQ 模式。
向 GIC 写 EOIR(End of Interrupt Register),通知 GIC 这个中断处理完成,可以接收新的中断。
从栈中弹出寄存器和 SPSR
,恢复进入中断前的状态。
用 subs pc, lr, #4
返回到中断发生前的指令位置继续运行。
目的:
告诉中断控制器“我处理完了”。
让 CPU 完整回到被打断的程序,像中断没发生一样继续执行。
省流版:
当一个程序在 SVC 模式 下运行时,如果来了 IRQ:
IRQ_Handler
)。1 |
|
中断向量,英文名为Interrupt Vector,在早期计算机体系结构里,“vector”常被用作“指针/地址索引”的意思,所以”向量“实际上就是地址指针的意思。 ↩︎
创建时间:8月 11, 2025
最后更新:8月 25, 2025
字数统计:4.1k字
预计阅读:16min