ARM GIC 通用中断控制器
之前在学习 ARMv4 的时候,学习了中断控制器 NVIC。
之后,到ARMv7、ARMv8,我开始学习 GIC 了。GIC 全称的是 Generic Interrupt Controller
(通用中断控制器)。GIC目前已经到 GICv4 架构了,但下面还是主要讨论 GICv2 和 GICv3。
1. GICv2
GICv2 主要是由Distributor和CPU接口构成的。CPU接口最多有8个。
GICv2 所有的寄存器都是通过 MMIO(memory mapping I/O)
的形式访问的。
备注:
MMIO
在ARMv8-A中由两个内存类型:Normal
和 Device
。
Device memory type(设备内存类型)用于描述外围设备。通常,ARMv8-A外围设备寄存器都通过内存映射的。
与AArch64内存相关的资料:
Learn the architecture - AArch64 memory attributes and properties
2. GICv3
GICv3由 Distributor
、Redistributor
和 CPU接口
组成。每一个 CPU 均有一个 Redistributor
,主要的功能应该是管理 PPI
和 SGI
,比如这些中断的使能和禁用、优先级、边沿触发还是电平触发、Group0还是Group1还有中断状态。
GICv3中CPU接口寄存器均为系统寄存器。
下面讲讲中断处理中的一些概念。内容可能是GICv3也可能是GICv2的。
3. 运行优先级和抢占
前言:这里以GICv3相关的资料说明,因此CPU接口寄存器是系统寄存器
相关寄存器:ICC_IARn_EL1
, ICC_EOIRn_EL1
, ICC_RPR_EL1
, ICC_BPRn_EL1
优先级下降里面的优先级,应该就是指运行优先级(running priority)
。
当CPU通过CPU接口对中断进行确认时(换言之,读取IAR寄存器的值),运行优先级
就变成了这个中断的优先级。当CPU写EOIR寄存器时,就会使得运行优先级
降低,此时这个值会变为原来的值。
当前的运行优先级
存放在 ICC_RPR_EL1
(Running Priority register) 中。
当CPU在处理一个低优先级中断时,一个高优先级中断被触发,就很可能会发生抢占(优先级嵌套?),此时运行优先级
的变化如下图所示。
有时候,我们还是希望优先级高到一定程度的时候再抢占。GICv3里可通过设置 ICC_BPRn_EL1
(Binary Point registers) 来控制这个差异。这个二进制点寄存器将优先级分成两个部分:组优先级 (group priority) 和次优先级 (subpriority)。只有当组优先级高的时候才会发生抢占,次优先级上的差异不会考虑。
例如当N=4时,B不会抢占C,A可以抢占B和C。
备注:一般优先级在数值上越小,优先级越大。
4. End of interrupt
EOI
是指 End of Interrupt
,对应的寄存器是 ICC_EOIRn_EL1
。一般而言,当中断被处理完之后,会将从 IAR
寄存器读到的值回写到 EOIR
,表明我处理好了。这时候,同优先级和甚至较低一些的优先级可以触发信号了(但还是要比之前的运行优先级高)。根据一些寄存器的配置,写 EOIR
的操作可以降低运行优先级,甚至可以完成降低优先级 (Priority drop) 和失活中断 (Deactivation) 两个操作。
那么这个就取决于 ICC_CTLR_ELn.EOImode
了。置1时,这两个操作就是分离的,还需要写 ICC_DIR_EL1
失活中断,也就是将中断的状态从 active
变为 inactive
。
备注:图片均来自 ARM GIC 相关的手册。