本章节涉及到的参考文档有三个:
在早期的 ARM 系统中,比如ARM7,ARM9 都是采用单核处理器设计,比如STM32,三星的2410。基本上几个简单的寄存器就可以描述中断源的使能,关闭以及状态。
树莓派4B上默认的 legacy 中断控制器就是采用了类似的实现。当然了树莓派4B上的中断源比较多,可以采用多级串联的方式来实现。三星的2410也是采用多级串联的方式实现。

但随着Soc 越来越复杂,中断源越来越多,中断类型也越来越多,以及现在比较流行的支持虚拟化等等因素。 ARM 公司开发了 GIC (Generic Interrupt Controller) 专门来管理中断。

GIC -V2 有两个硬件单元组成的。


GIC-V2 最多支持 8 个CPU.
GICD_ITARGETSRn 寄存器用来配置 Distributor 可以把中断路由到 哪个CPU 上,
GIC检测中断
GIC检测中断的流程如下:

当然,实际情况可能更复杂。

3.2.4 Interrupt handling state machine, ARM Generic Interrupt Controller Architecture Specification.pdf
GIC中断时序图
GIC 支持中断优先级抢占功能。一个高优先级的中断可以抢占一个处于 active 状态的低优先级中断,即 GIC 的分发器会先找出并记录当前优先级最高并且处于 peding 的中断,然后抢占当前的中断服务,转而先处理高优先级中断,上述内容是从 GIC 角度分析的。总之,GIC 的分发器总会把 pending 状态中优先级最高的中断请求发送给 CPU。
从 Linxu 内核角度分析,如果在低优先级的中断处理程序中发生了 GIC 抢占,虽然 GIC 会发送高优先级中断请求给 CPU, 但是CPU处于关中断的状态,需要等到CPU开中断时才会响应高优先级中断。这一点需要注意。

B1. Interrupt signaling in the GIC-400 with physical interrupts only, CoreLink GIC-400 Generic Interrupt Controller Technical Reference Manual.pdf
假设中断N和中断M 都是 SPI 类型的外设中断且通过快速中断请求(Fast Interrupt Request, FIR) 来处理,高电平触发,N的优先级比M的高,它们的目标CPU 相同。
不考虑虚拟化的话,GIC 的寄存器可以分为两组:

Chapter 4.1 Distributor register map, ARM Generic Interrupt Controller Architecture Specification.pdf

Chapter 4.1 CPU interface register map, ARM Generic Interrupt Controller Architecture Specification.pdf
GIC-V2寄存器有个特点:名称以n 结束的寄存器会有 n个。比如 GICD_ISENABLERn寄存器就有 n 个GICD_ISENABLER 寄存器。
第一种:一个bit表示一个中断号类型的寄存器
GICD_ISENABLERn寄存器是用来使能某个中断号的,并且是按照中断号来描述的。
![]()
Chapter 4.1 Distributor register map, ARM Generic Interrupt Controller Architecture Specification.pdf
此寄存器的偏移量是 0x100~0x17c。 总共有n = (0x17c-0x100)/4 = 31 个寄存器。分别是 GICD_ISENABLER0 到 GICD_ISENABLER31。
对于中断号 m 来说,我们需要计算中断m对应的是哪个寄存器,也就是说我们要计算偏移多少。

Chapter 4.3.5 Interrupt Set-Enable Registers, GICD_ISENABLERn, ARM Generic Interrupt Controller Architecture Specification.pdf
GICD_ISENABLERn寄存器中每bit表示一个中断源。所以 n=m/32。 那么对于中断号 m 的GICD_ISENABLERn寄存器的地址就是 (0x100+4n)。
假设 m = 50, 即50号中断。 n = 50/32=1。 即GICD_ISENABLER1,偏移地址是(0x100+4*1)
第二种:8bits表示一个中断源类型的寄存器
GICD_ITARGETsRn 寄存器 使用 8位表示一个中断源所能路由的目标CPU有哪些。

Chapter 4.3.5 Interrupt Set-Enable Registers, GICD_ISENABLERn, ARM Generic Interrupt Controller Architecture Specification.pdf

Chapter 4.3.12 Interrupt Processor Targets Register, GICD_ITARGETSRn, ARM Generic Interrupt Controller Architecture Specification.pdf

Chapter 4.3.12 Interrupt Processor Targets Register, GICD_ITARGETSRn, ARM Generic Interrupt Controller Architecture Specification.pdf
对于中断 m来说,这个寄存器 n的计算公式变成了 n =m/4。这里是取整计算。 寄存器的偏移量等于(0x800+4n)。
假设 m =50, 即50号中断。 n=50/4=12。 即GICD_ITARGETSR12。寄存器的偏移量是 0x800 +4*12 = 0x830。
树莓派4B上集成了 GIC-V2架构的GIC-400。 GIC-400 上的具体中断号的分配和Soc 芯片的实现相关。

6.3 GIC-400 interrupt controller, BCM2711 ARM Peripherals.pdf
树莓派上的GIC-400分配有5种情况:
这些中断是如何映射到GIC-400 中的呢?
ARMC 外设中断组中每个中断定义如下

Chapter 6.2.3 ARMC interrupt, BCM2711 ARM Peripherals.pdf
GIC-400 分配的 ARMC peripheral IRQs 的 中断号是从 64-79,直接映射过去即可,比如 Timer 在ARMC中断组的id是0 ,那么映射到GIC-400就是64。 Software Interrupt 7 在ARMC组的id是15, 那么映射到GIC-400就是79。
另外,ARMC 中断组的寄存器 IRQn_PENDING2 每个bit 表示一个中断。

Chapter 6.5.3 ARMC, BCM2711 ARM Peripherals.pdf
VC(VideoCore) 外设中断组详细中断号如下

Chapter 6.2.4. VideoCore interrupts, BCM2711 ARM Peripherals.pdf
GIC-400 分配的 VC(VideoCore) peripheral IRQs 的 中断号是从 96-159, 那么System Timer 1 映射到 GIC-400,中断号就是97。
另外,VC 中断组的寄存器IRQn_PENDING0, IRQn_PENDING1 每个bit 表示一个中断。总共64个。

Chapter 6.5.3 ARMC, BCM2711 ARM Peripherals.pdf
PCIe 的中断组详细的中断号如下

Chapter 6.2.5. ETH_PCIe interrupts, BCM2711 ARM Peripherals.pdf
树莓派4B有两种地址模式
一般我们使用低地址模式(enable low peripheral),对应的基地址是0x0 FF84 0000。

Chapter 6.5.1 GIC-400, BCM2711 ARM Peripherals.pdf
然后,我们需要继续查看 GIC-V2的手册来确定 Distributor 和 CPU interface 的偏移量。

3.2 GIC-400 register map, CoreLink GIC-400 Generic Interrupt Controller Technical Reference Manual.pdf
从上图可以知道, Distributor 和CPU interface 的基地址分别是 0x1000和0x2000。
最后,在查看对应的寄存器的偏移量。寄存器的偏移量可以参考[[014 - GIC-400#2.5. GIC-v2 寄存器]]
我们继续使用中断 m 来举例, 假设通过[[014 - GIC-400#3. 树莓派4B 上的 GIC-400]]c 参考到中断M的中断号是 50。
我们来计算下,中断 m 对应的 GICD_ISENABLER1 和 GICD_ITARGETSR12 在树莓派4B设置为低地址模式下的访问地址。
GICD_ISENABLER1 的访问地址 = GIC-400 的基地址+ GIC-400 的 Distributor的偏移量+ 指定寄存器的偏移量 = 0x FF84 0000 + 0x100 + (0x100+4*1) = 0x FF84 0204
GICD_ITARGETSR12 的访问地址 = GIC-400 的基地址+ GIC-400 的 Distributor 的偏移量+ 指定寄存器的偏移量 = 0xFF84 0000 + 0x100 +(0x800+4*\12) = 0xFF84 093C
这些地址的来源总结下:
Chapter 6.5.1 GIC-400, BCM2711 ARM Peripherals.pdf3.2 GIC-400 register map, CoreLink GIC-400 Generic Interrupt Controller Technical Reference Manual.pdf4.3 Distributor register descriptions, ARM Generic Interrupt Controller Architecture Specification 以及 4.4 CPU interface register descriptions, ARM Generic Interrupt Controller Architecture Specification.pdf“GICC_” 打头的寄存器也可以这样计算访问地址。