ARM架构-异常与中断
2024年9月 · 预计阅读时间: 11 分钟
#
1.ARM 对异常或中断的处理过程#
1.1 通用处理过程对于 arm 系统,异常与中断的硬件框图如下:
所有的中断源(按键、定时器等),它们发出的中断汇聚到中断控制器, 再由中断控制器发信号给 CPU,告诉它发生了那些紧急情况。
除了这些中断,还有什么可以打断 CPU 的运行?
- 指令不对
- 数据访问有问题
- reset 信号
- 等等,这些都可以打断断 CPU,这些被称为异常
- 中断属于一种异常
ARM 系统中如何处理异常与中断?重点在于保存现场以及恢复现场, 处理过程如下:
- 保存现场(各种寄存器)
- 处理异常(中断属于一种异常)
- 恢复现场
细化一下,在 ARM 系统中如何使用异常(中断)?
初始化
- 设置中断源,让它可以产生中断
- 设置中断控制器(可以屏蔽某个中断,优先级)
- 设置 CPU 总开关,使能中断
执行其他程序:正常程序
产生中断,举例:按下按键--->中断控制器--->CPU
cpu 每执行完一条指令都会检查有无中断/异常产生
发现有中断/异常产生,开始处理:
- 保存现场
- 分辨异常/中断,调用对于异常/中断的处理函数
- 恢复现场
不同的芯片,不同的架构,在这方面的处理稍有差别:
- 保存/恢复现场:cortex M3/M4 是硬件实现的,cortex A7 是软件实现的
- CPU 中止当前执行,跳转去执行处理异常的代码:也有差异
- cortex M3/M4 在向量表上放置的是函数地址
- cortex A7 在向量表上放置的是跳转指令
通用处理流程:不同处理器、操作系统会有细微差别。
- 中断请求
- 中断响应
关中断
- 保存断点
- 识别中断源
- 保存现场
开中断
- 中断服务程序
关中断
- 恢复现场
开中断
- 中断返回
#
1.2 Cortex M3/M4#
1)M3/M4 的异常/中断处理流程发生异常/中断时,硬件上实现了这些事情:
保存现场:把被中断瞬间的寄存器的值保存进栈里
根据异常/中断号,从向量表中得到函数地址,跳转过去执行
函数执行完后,从栈中恢复现场
保存现场、分辨异常/中断、跳转执行,都是硬件实现的。 我们只需要在向量表中,把处理函数的地址填进去就可以了。
硬件承包了大部分的工作。
M3/M4 的向量表中,存放的是函数地址。
#
2)M3/M4 的向量表M3/M4 的向量表中,放置的是具体异常/中断的处理函数的地址。
比如发生Reset
异常时,CPU 就会从向量表里找到第 1 项,得到 Reset_Handler 函数的地址,跳转去执行。
比如发生EXTI Line 0
中断时,CPU 就会从向量表里找到第 22 项,得到 EXTI0_IRQHandler 函数的地址,跳转去执行。
- 跳转之前,硬件会保存现场
- 函数执行完毕,返回之后,硬件会恢复现场
#
1.3 Cortex A7#
1)A7 的异常/中断处理流程发生异常/中断时,硬件上实现了这些事情:
CPU 切换到对应的异常模式,比如 IRQ 模式、未定义模式、SVC 模式
保存被中断时的 CPSR 到 SPSR
- CPSR:current program status register,当前程序状态寄存器
- SRSR:saved program status register,保存的程序状态寄存器
跳到这个异常的入口地址去,执行指令,这通常是一条跳转指令,
ldr PC, _irq
存放在向量表中。
软件要做的事情就比较多了:
- 保存现场
- 分辨异常/中断
- 调用对应的处理函数
- 恢复现场
#
2)A7 的向量表A7 的向量表中,放置的是某类异常的跳转指令。
比如发生Reset
异常时,CPU 就会从向量表里找到第 0 项,得到b reset
指令,执行后就跳转到 reset 函数。
比如发生任何的中断时,CPU 就会从向量表里找到第 6 项,得到ldr pc, _irq
指令,执行后就跳转到_irq 函数。(在 irq 函数里面进行分辨中断源的工作)
- 跳转之前,硬件只会保存 CPSR 寄存器
- 跳转之后,软件要保存现场
- 函数执行完毕,返回之前,软件恢复现场
#
2.异常处理深入分析_保存现场#
2.1 处理流程总述CPU 每执行完一条指令都会检查有无中断/异常产生,发现有中断/异常产生,开始处理:
- 保存现场
- 分辨异常/中断,调用对应的异常/中断处理函数
- 恢复现场
具体对于不同处理器:
- 保存现场:cortex M3/M4 里是硬件完成,cortex A7 等是软件实现
- 分辨异常/中断:cortex M3/M4 里是硬件完成,cortex A7 等是软件实现
- 调用处理函数:cortex M3/M4 里是硬件来调用,cortex A7 等是软件自己去调用
- 恢复现场:cortex M3/M4 里是软件触发、硬件实现,cortex A7 等是软件实现
不管是硬件还是软件实现,第一步都是保存现场。
- 在处理异常前,把这些寄存器保存在栈中,这称为保存现场
- 在处理完异常后,从栈中恢复这些寄存器,这称为恢复现场
#
2.2 保存现场#
1)需要保存哪些寄存器?ARM 处理器中有这些寄存器:
在 arm 中有个ATPCS
规则(ARM-THUMB procedure call standard(ARM-Thumb 过程调用标准)。
约定 R0-R15 寄存器的用途:
R0-R3
调用者和被调用者之间传参数
R4-R11
函数可能被使用,所以在函数的入口保存它们,在函数的出口恢复它们。
还有一个程序状态寄存器,对于 M3/M4 它被称为XPSR,对于 A7 它被称为CPSR,我们简称为 PSR。 R0-R15、PSR,就是所谓的现场。 发生异常/中断后,在处理异常/中断前,需要保存现场,难道需要保存所有这些寄存器吗? 不需要! 在 C 函数中,可以修改 R0-R3、R12、R14(LR)以及 PSR。如果 C 函数要用到这些寄存器,就要把它们保存到栈里,在函数结束前在从栈中恢复它们。 这些寄存器被拆分成 2 部分:调用者保存的寄存器(R0-R3,R12,LR,PSR)、被调用者保存的寄存器(R4-R11)。
比如函数 A 调用函数 B,函数 A 应该知道:
- R0-R3 是用来传参数给函数 B 的
- 函数 B 可以肆意修改 R0-R3
- 函数 A 不要指望函数 B 帮你保存 R0-R3
- 保存 R0-R3,是函数 A 的事情
- 对于 LR、PSR 也是同样的道理,保存它们是函数 A 的责任
对于函数 B:
- 我用到 R4-R11 中的某一个,我都会在函数入口保存、在函数返回前恢复
- 保证在 B 函数调用前后,函数 A 看到的 R4-R11 保存不变
进一步,假设函数 B 就是异常/中断处理函数,函数 B 本身能保证 R4-R11 不变,那么保存现场时,只需要保存这些:
- 调用者保存的寄存器(R0-R3,R12,LR,PSR)
- PC(执行完之后的返回地址)
#
2)Cortex M3/M4保存现场(硬件进行)
调用 C 函数
- C 函数执行完后,它返回 LR 所指示的位置。 难道把 LR 设置为被中断的程序的地址就行了吗? 如果只是返回 LR 所指示的地方,硬件帮我们保存在栈里的寄存器,怎么恢复?
- M3/M4 在调用异常处理函数前,把 LR 设置为一个特殊的值,转给特殊的值被称为EXC_RETURN。 当 PC 寄存器的值等于EXC_RETURN时,会触发异常返回机制,简单地说:会从栈里恢复 R0-R3,R12,LR,PC,PSR 等寄存器。
- EXC_RETURN的值,请参考
ARM Cortex-M3与Cortex-M4权威指南.pdf
,截图如下:
补充 2 个知识点:
操作模式:M3/M4 有两个操作模式
- 处理模式:执行中断服务程序等异常处理时,处于处理模式
- 线程模式:执行普通应用程序代码时,处于线程模式
M3/M4 有连个 SP 寄存器:SP_process、SP_main
- 有些 RTOS 在运行用户程序时会使用 SP_process,默认使用 SP_main。
#
3)Cortex A7处理器有 9 种模式:User、Sys、FIQ、IRQ、ABT、SVC、UND、MON、HYP。
下图中深色的寄存器,表示该模式下的"Banked"寄存器,比如 SPSR 寄存器,在很多模式中都有自己的寄存器。比如 IRQ 模式下访问 SPSR 时,访问到的是 IRQ 模式下自己的 SPSR_irq,别的模式下无法访问 SPSR_irq。
比较值得关注的是
FIQ
模式,名为"快中断"
,它有很多"Banked"寄存器:R8-R12,SP,LR
。 在 FIQ 模式下,它既然能使用自己的 R8-R12,SP,LR,自然不需要去保存被中断的程序的"R8-R12,SP,LR"了。 省去保存这几个寄存器的时间,处理中断时自然就快很多,所以被称为"FIQ"。
从上图也看到,几乎每个模式下都有自己是 SP 寄存器,意味着这些模式下有自己的栈。
当发生异常时,以 IRQ 为例:
硬件:
- CPU 会自动切换进入对应的模式,比如进入 IRQ 模式
- 并且会把被中断的 CPSR 保存到 SPSR_irq 里
- 跳转到 IRQ 入口:
ldr PC, _irq
软件:
- 保存现场:调用者保存的寄存器(R0-R3,R12,LR)以及 PC(返回地址)
- 分辨中断源、处理中断
- 恢复现场
#
3.CPU 模式(Mode)_状态(State)与寄存器#
3.1 ARMv7 有 9 种模式- USR:用户模式
- SYS:系统模式
- 异常模式:
- UND:未定义模式(出现未定义的指令)
- SVC:管理模式,软中断
- ABT:中止模式(1,指令预取中止 2,数据访问中止)
- IRQ:中断模式
- FIQ:快中断模式
除了用户模式(USR),其他 6 种可以称为特权模式(privileged mode)。特权模式可以编程操作CPSR
直接进入其他模式,而在用户模式下,不能随意切换。
跟 ARM9 相比,多了 2 中 Mode:Monitor、Hyp。
#
3.2 ARMv7 有 2 种状态- ARM state
- ARM 指令集,在 ARMv7 32 位指令下,每个指令占 4 字节(机器码)
- Thumb state
- Thumb 指令集,每个指令占 2 字节(机器码)
例如,同样是mov R0, R1
,使用 ARM 指令编译成机器码占据 4Byte,而使用 Thumb 占据 2Byte。
#
3.3 寄存器分析#
1)A7 R0-R15 寄存器在2.2
小节的3)Cortex A7
中也已经说明过下图中的寄存器了。
每个模式下都有自己的 SP 寄存器(R13),即 SP_xxx;也有自己的 LR 寄存器(R14),保存发生异常时的指令地址。 另外,在 FIQ 快中断模式下,有自己的 R8-R12 寄存器,那么就不需要保存系统/用户模式下的 R8 ~ R12 这几个寄存器,这样可以省略保存寄存器的时间,加快处理速度。
#
2)CPSR / SPSR 寄存器我们从低位到高位看:
M4-M0
:表示当前 CPU 处于哪一种模式。T, bit[5] :表示工作在 ARM 还是 Thumb 指令集下;
F, bit[6] :如果是 1,表示禁止 FIQ 中断
I, bit[7] :如果是 1,表示禁止 IRQ 中断
A, bit[8] :如果是 1,表示禁止异步中止
E, bit[9] :大小端,0 Little Endian,1 Big Endian
IT[7:0], bits[15:10, 26:25] :
GE[3:0], bits[19:16] :大于或等于标志位
Bits[23:20]:保留位
J, bit[24] :加速执行环境的 ARM Jazelle ® 技术,结合 T 位
Q, bit[27] :累积饱和位。
Condition flags, bits[31:28] :
N, bit[31] Negative condition flag
Z, bit[30] Zero condition flag
C, bit[29] Carry condition flag
V, bit[28] Overflow condition flag
例如:
cmp R0, R1
- 影响 z 位,if R0 == R1, Z = 1beq xxx
- 使用 z 位,如果 z == 1, 则跳转。
#
3.4 发生异常时的处理流程#
1)异常向量表在 ARM9 里,异常向量表基地址只有两个取值:0、0xFFFF0000。 对于 cortex A7,它的异常向量表基地址是可以修改的。
#
2)进入异常的处理流程(硬件)- 硬件确定要进入哪种异常模式
- LR 寄存器被更新,它表示处理完异常后要返回到哪里,这个值可能需要修改。
- SPSR = 被中断时的 CPSR
- 对于"Security Exceptions",……,本课程不涉及
- 更新异常模式下的 CPSR:设置模式位、设置 mask bit(屏蔽其他异常)、设置指令集状态位
- PC = 异常入口地址
- 从 PC 所指示地方执行程序
#
3)退出异常在ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf
中,对异常的退出,描述得很复杂。但是很多情况,我们并不涉及。
所以我们参考S3C2440A_UserManual_Rev13.pdf
,它描述得更清晰、简单。
让 LR 减去某个值,然后赋值给 PC(PC = 某个异常 LR 寄存器减去 offset) 减去什么值呢? 也就是我们怎么返回去继续执行原来的程序,根据下面这个表来取值:
如果发生的是 SWI 可以把 R14_svc 复制给 PC 如果发生的是 IRQ 可以把 R14_irq 的值减去 4 赋值给 PC
把 CPSR 的值恢复(CPSR 值等于 某一个一场模式下的 SPSR)
清中断(如果是中断的话,对于其他异常不用设置)
#
4)确定异常返回地址发生异常时,LR 寄存器里保存的值是什么?
"Preferred return address"是什么?请看下图:对于IRQ
模式,就是下一条执行指令的地址。
offset 是什么?
从异常中返回时,LR 可能需要调整,再赋给 PC。 ARM9 的手册讲得比较清楚,返回指令如下:
#
4.ARM_Thumb 指令集程序示例#
4.1 汇编里指定指令集对于 IMX6ULL、STM32MP157,默认使用 ARM 指令集。 在汇编文件里,可以使用这样的语法告诉编译器:
#
4.2 编译 C 文件时指定指令集使用 GCC 编译时:
#
4.3 汇编里切换状态要切换 CPU 的 State,比如从 ARM 切换到 Thumb,或者从 Thumb 切换到 ARM,可以使用 BX、BLX 指令:
汇编里调用 C 函数时,可以直接如此调用:
#
5.SVC 异常在 ARM 指令中,有一条指令:
它会触发一个异常。
在操作系统中,比如各类 RTOS 或者 Linux,都会使用SVC
指令故意触发异常,从而导致内核的异常处理函数被调用,进而去使用内核的服务。
比如 Linux 中,各类文件操作的函数open
、read
、write
,它的实质都是SVC
指令。
本节课程不讲解SVC
在内核中的使用,我们只是看看如何处理SVC
触发的异常。
#
6.中断的硬件结构与配置寄存器#
6.1 中断路径上的 3 个部件- 中断源 中断源多种多样,比如 GPIO、定时器、UART、DMA 等等。 它们都有自己的寄存器,可以进行相关设置:使能中断、中断状态、中断类型等等。
- 中断控制器
各种中断源发出的中断信号,汇聚到中断控制器。
可以在中断控制器中设置各个中断的优先级。
中断控制器会向 CPU 发出中断信号,CPU 可以读取中断控制器的寄存器,判断当前处理的是哪个中断。
中断控制器有多种实现,比如:
- STM32F103 中被称为 NVIC:Nested vectored interrupt controller(嵌套向量中断控制器)
- ARM9 中一般是芯片厂家自己实现的,没有统一标准
- Cortex A7 中使用 GIC(Generic Interrupt Controller)
- CPU CPU 每执行完一条指令,都会判断一下是否有中断发生了。 CPU 也有自己的寄存器,可以设置它来使能/禁止中断,这是中断处理的总开关。
接下来,进行对比学习三款芯片:STM32F103\STM32MP157\IMX6ULL
#
6.2 STM32F103 的 GPIO 中断对于 GPIO 中断,F103 引入了一个外部中断控制器,External interrupt/event controller (EXTI)
。
EXTI 可以给 NVIC 提供 16 个中断信号:EXTI0~EXTI15。 那么某个 EXTIx,它来自哪些 GPIO 呢?这需要设置 GPIO 控制器。
#
1)GPIO 控制器AFIO_EXTICR1~AFIO_EXTICR4
一共 4 个寄存器
名为:External interrupt configuration register
,外部中断配置寄存器。
用来选择某个外部中断 EXTIx 的中断源。
因此,在 GPIO 控制器中,可以设置某个 GPIO 引脚作为中断源,给 EXTI 提供中断信号。
#
2)EXTI设置高电平触发、低电平触发、上升沿触发、下降沿触发等等,具体包括:
- Falling trigger selection register:是否选择下降沿触发
- Rising trigger selection register:是否选择上升沿触发
- Interrupt mask register:是否屏蔽中断
当发生中断时,可以读取下列寄存器判断是否发生了中断、发生了哪个中断:
- Pending reqeust register
要使用 EXTI,流程如下:
- 配置
EXTI_IMR
:允许 EXTI 发出中断 - 配置
EXTI_RTSR、EXTI_FTSR
,选择中断触发方式 - 配置 NVIC 中的寄存器,允许 NVIC 把中断发给 CPU
#
3)NVICNVIC 的职责就是从多个中断源中取出优先级最高的中断,向 CPU 发出中断信号,处理中断时,程序可以写 NVIC 的寄存器,清除中断。
#
4)CPUcortex M3/M4 处理器内部有这几个寄存器:
PRIMASK
把 PRIMASK 的 bit0 设置为 1,就可以屏蔽所有优先级可配置的中断。 可以使用这些指令来设置它:
FAULTMASK
FAULTMASK 和 PRIMASK 很像,它更进一步,出来一般的中断外,把 HardFault 都禁止了。 只有 NMI 可以发生。 可以使用这些指令来设置它:
BASEPRI
可以屏蔽优先级大于或等于 BASEPRI 的中断。
#
6.3 STM32MP157 的 GPIO 中断#
1)GPIO 控制器对于 STM32MP157,除了把 GPIO 引脚配置为输入功能外,GPIO 控制器里没有中断相关的寄存器。(和 F103 不一样)
#
2)EXTIGPIO 中断的配置都集成在这里了,包括
设置
EXTImux
:选择哪些 GPIO 可以发出中断。只有 16 个 EXTI 中断,从 EXTI0~EXTI15;每个 EXTIx 中断只能从 PAx、PBx、……中选择某个引脚。 具体而言,通过EXTI_EXTICR1
等寄存器来设置 EXTIx 的中断源是哪个 GPIO 引脚设置
Event Trigger
:设置中断触发方式,EXTI_RTSR1
\EXTI_FTSR1
设置
Masking
:允许某个 EXTI 中断,EXTI_IMR
查看中断状态、清中断:
#
3)GICARM 体系结构定义了通用中断控制器(GIC),该控制器包括一组用于管理单核或多核系统中的中断的硬件资源。GIC 提供了内存映射寄存器,可用于管理中断源和行为,以及(在多核系统中)用于将中断路由到各个 CPU 核。它使软件能够屏蔽,启用和禁用来自各个中断源的中断,以(在硬件中)对各个中断源进行优先级排序和生成软件触发中断。它还提供对 TrustZone 安全性扩展的支持。GIC 接受系统级别中断的产生,并可以发信号通知给它所连接的每个内核,从而有可能导致 IRQ 或 FIQ 异常发生。
GIC 比较复杂,在 7.GIC 小节介绍。
#
4)CPUCPU 的 CPSR 寄存器中有一位:I 位,用来使能/禁止中断。
可以使用以下汇编指令修改 I 位:
#
6.4 IMX6ULL 的 GPIO 中断IMX6ULL 中没有 EXTI 控制器,对 GPIO 的中断配置、控制,都在 GPIO 模块内部实现:
#
1)GPIO 控制器每组 GPIO 中都有对应的GPIOx_ICR1
、GPIOx_ICR2
寄存器(interrupt configuration register),每个引脚都可以配置为中断引脚,并配置它的触发方式。
使能 GPIO 中断:GPIOx_IMR
;
判断中断状态、清中断:GPIOx_ISR
。
#
2)GICARM 体系结构定义了通用中断控制器(GIC),该控制器包括一组用于管理单核或多核系统中的中断的硬件资源。GIC 提供了内存映射寄存器,可用于管理中断源和行为,以及(在多核系统中)用于将中断路由到各个 CPU 核。它使软件能够屏蔽,启用和禁用来自各个中断源的中断,以(在硬件中)对各个中断源进行优先级排序和生成软件触发中断。它还提供对 TrustZone 安全性扩展的支持。GIC 接受系统级别中断的产生,并可以发信号通知给它所连接的每个内核,从而有可能导致 IRQ 或 FIQ 异常发生。
GIC 比较复杂,下一个视频再详细讲解。
#
3)CPUCPU 的 CPSR 寄存器中有一位:I 位,用来使能/禁止中断。和 MP157 一样。
#
7.GIC 介绍从软件角度来看,GIC 具有两个主要功能模块,简单画图如下:
- 分发器(Distributor):系统中的所有中断源都连接到该单元。可以通过仲裁单元的寄存器来控制各个中断源的属性,例如优先级、状态、安全性、路由信息和使能状态。分发器把中断输出到“CPU 接口单元”,后者决定将哪个中断转发给 CPU 核。
- CPU 接口:CPU 核通过控制器的 CPU 接口单元接收中断。CPU 接口单元寄存器用于屏蔽,识别和控制转发到 CPU 核的中断的状态。系统中的每个 CPU 核心都有一个单独的 CPU 接口。 中断在软件中由一个称为中断 ID 的数字标识。中断 ID 唯一对应于一个中断源。软件可以使用中断 ID 来识别中断源并调用相应的处理程序来处理中断。呈现给软件的中断 ID 由系统设计确定,一般在 SOC 的数据手册有记录。
完整逻辑框图:
#
7.1 GIC 中断的不同类型① 软件触发中断(SGI,Software Generated Interrupt)
- 这是由软件通过写入专用仲裁单元的寄存器即软件触发中断寄存器(ICDSGIR)显式生成的。它最常用于CPU 核间通信。
- SGI 既可以发给所有的核,也可以发送给系统中选定的一组核心。中断号 0-15 保留用于 SGI 的中断号。用于通信的确切中断号由软件决定。
② 私有外设中断(PPI,Private Peripheral Interrupt)
- 这是由单个 CPU 核私有的外设生成的。PPI 的中断号为 16-31。它们标识 CPU 核私有的中断源,并且独立于另一个内核上的相同中断源,比如,每个核的计时器。
③ 共享外设中断(SPI,Shared Peripheral Interrupt)
- 这是由外设生成的,中断控制器可以将其路由到多个核。中断号为 32-1020。SPI 用于从整个系统可访问的各种外围设备发出中断信号。
- 中断可以是边沿触发的(在中断控制器检测到相关输入的上升沿时认为中断触发,并且一直保持到清除为止)或电平触发(仅在中断控制器的相关输入为高时触发)。
#
7.2 GIC 定义中断的四种状态- 非活动状态(Inactive)–这意味着该中断未触发。
- 挂起(Pending)–这意味着中断源已被触发,但正在等待 CPU 核处理。待处理的中断要通过转发到 CPU 接口单元,然后再由 CPU 接口单元转发到内核。
- 活动(Active)–描述了一个已被内核接收并正在处理的中断。
- 活动和挂起(Active and pending)–描述了一种情况,其中 CPU 核正在为中断服务,而 GIC 又收到来自同一源的中断。
#
7.3 配置GIC 作为内存映射的外围设备,被软件访问。所有内核都可以访问公共的 distributor 单元,但是 CPU interface 是备份的,也就是说,每个 CPU 核都使用相同的地址来访问其专用 CPU 接口。一个 CPU 核不可能访问另一个 CPU 核的 CPU 接口。
Distributor 拥有许多寄存器,可以通过它们配置各个中断的属性。这些可配置属性是:
中断优先级:Distributor 使用它来确定接下来将哪个中断转发到 CPU 接口。
中断配置:这确定中断是对电平触发还是边沿触发。
中断目标:这确定了可以将中断发给哪些 CPU 核。
中断启用或禁用状态:只有 Distributor 中启用的那些中断变为挂起状态时,才有资格转发。
中断安全性:确定将中断分配给 Secure 还是 Normal world 软件。
中断状态。
Distributor 还提供优先级屏蔽,可防止低于某个优先级的中断发送给 CPU 核。 每个 CPU 核上的 CPU interface,专注于控制和处理发送给该 CPU 核的中断。
#
7.4 初始化- Distributor 和 CPU interface 在复位时均被禁用。复位后,必须初始化 GIC,才能将中断传递给 CPU 核。
- 在 Distributor 中,软件必须配置优先级、目标核、安全性并启用单个中断;随后必须通过其控制寄存器使能。
- 对于每个 CPU interface,软件必须对优先级和抢占设置进行编程。每个 CPU 接口模块本身必须通过其控制寄存器使能。
- 在 CPU 核可以处理中断之前,软件会通过在向量表中设置有效的中断向量并清除 CPSR 中的中断屏蔽位来让 CPU 核可以接收中断。
- 可以通过禁用 Distributor 单元来禁用系统中的整个中断机制;可以通过禁用单个 CPU 的 CPU 接口模块或者在 CPSR 中设置屏蔽位来禁止向单个 CPU 核的中断传递。也可以在 Distributor 中禁用(或启用)单个中断。
- 为了使某个中断可以触发 CPU 核,必须将各个中断,Distributor 和 CPU interface 全部使能,并
将 CPSR 中断屏蔽位清零,如下图:
#
7.5 GIC 中断处理当 CPU 核接收到中断时,它会跳转到中断向量表执行。
- 顶层中断处理程序读取 CPU 接口模块的 Interrupt Acknowledge Register,以获取中断 ID。除了返回中断 ID 之外,读取操作还会使该中断在 Distributor 中标记为 active 状态。一旦知道了中断 ID(标识中断源),顶层处理程序现在就可以分派特定于设备的处理程序来处理中断。
- 当特定于设备的处理程序完成执行时,顶级处理程序将相同的中断 ID 写入 CPU interface 模块中的 End of Interrupt register 中断结束寄存器,指示中断处理结束。除了把当前中断移除 active 状态之外,这将使最终中断状态变为 inactive 或 pending(如果状态为 inactive and pending),这将使 CPU interface 能够将更多待处理 pending 的中断转发给 CPU 核。这样就结束了单个中断的处理。
- 同一 CPU 核上可能有多个中断等待服务,但是 CPU interface 一次只能发出一个中断信号。顶层中断处理程序重复上述顺序,直到读取特殊的中断 ID 值 1023,表明该内核不再有任何待处理的中断。这个特殊的中断 ID 被称为伪中断 ID(spurious interrupt ID)。 伪中断 ID 是保留值,不能分配给系统中的任何设备。