扒开 ARM 中断控制器的底裤
GIC 硬件原理
GIC,Generic Interrupt Controller。是ARM公司提供的一个通用的中断控制器。主要作用为:接受硬件中断信号,并经过一定处理后,分发给对应的CPU进行处理。
当前GIC 有四个版本,GIC v1~v4, 本文主要介绍GIC v3控制器。
GIC v3中断类别
GICv3定义了以下中断类型:
- SGI (Software Generated Interrupt):软件触发的中断。软件可以通过写 GICD_SGIR 寄存器来触发一个中断事件,一般用于核间通信,内核中的 IPI:inter-processor interrupts 就是基于 SGI。
- PPI (Private Peripheral Interrupt):私有外设中断。这是每个核心私有的中断。PPI会送达到指定的CPU上,应用场景有CPU本地时钟。
- SPI (Shared Peripheral Interrupt):公用的外部设备中断,也定义为共享中断。中断产生后,可以分发到某一个CPU上。比如按键触发一个中断,手机触摸屏触发的中断。
- LPI (Locality-specific Peripheral Interrupt):LPI 是 GICv3 中的新特性,它们在很多方面与其他类型的中断不同。LPI 始终是基于消息的中断,它们的配置保存在表中而不是寄存器。比如 PCIe 的 MSI/MSI-x 中断。
中断类型 | 硬件中断号 |
---|---|
SGI | 0-15 |
PPI | 16-31 |
SPI | 32-1019 |
reserved | ...... |
LPI | 8192-MAX |
GIC v3 组成
GICv3 控制器由以下三部分组成:
- Distributor:SPI 中断的管理,将中断发送给 Redistributor
- 打开或关闭每个中断。Distributor对中断的控制分成两个级别。一个是全局中断的控制(GIC_DIST_CTRL)。一旦关闭了全局的中断,那么任何的中断源产生的中断事件都不会被传递到 CPU interface。另外一个级别是对针对各个中断源进行控制(GIC_DIST_ENABLE_CLEAR),关闭某一个中断源会导致该中断事件不会分发到 CPU interface,但不影响其他中断源产生中断事件的分发。
- 控制将当前优先级最高的中断事件分发到一个或者一组 CPU interface。当一个中断事件分发到多个 CPU interface 的时候,GIC 的内部逻辑应该保证只 assert 一个CPU。
- 优先级控制。
- interrupt属性设定。设置每个外设中断的触发方式:电平触发、边缘触发;
- interrupt group的设定。设置每个中断的 Group,其中 Group0 用于安全中断,支持 FIQ 和 IRQ,Group1 用于非安全中断,只支持 IRQ;
- Redistributor:SGI,PPI,LPI 中断的管理,将中断发送给 CPU interface
- 启用和禁用 SGI 和 PPI。
- 设置 SGI 和 PPI 的优先级。
- 将每个 PPI 设置为电平触发或边缘触发。
- 将每个 SGI 和 PPI 分配给中断组。
- 控制 SGI 和 PPI 的状态。
- 内存中数据结构的基址控制,支持 LPI 的相关中断属性和挂起状态。
- 电源管理支持。
- CPU interface:传输中断给 Core
- 打开或关闭 CPU interface 向连接的 CPU assert 中断事件。对于 ARM,CPU interface 和 CPU 之间的中断信号线是 nIRQCPU 和 nFIQCPU。如果关闭了中断,即便是 Distributor 分发了一个中断事件到 CPU interface,也不会 assert 指定的 nIRQ 或者 nFIQ 通知 Core。
- 中断的确认。Core 会向 CPU interface 应答中断(应答当前优先级最高的那个中断),中断一旦被应答,Distributor 就会把该中断的状态从 pending 修改成 active 或者 pending and active(这是和该中断源的信号有关,例如如果是电平中断并且保持了该 asserted 电平,那么就是 pending and active)。ack 了中断之后,CPU interface 就会 deassert nIRQCPU 和 nFIQCPU 信号线。
- 中断处理完毕的通知。当 interrupt handler 处理完了一个中断的时候,会向写 CPU interface 的寄存器通知 GIC CPU 已经处理完该中断。做这个动作一方面是通知 Distributor 将中断状态修改为 deactive,另外一方面,CPU interface 会 priority drop,从而允许其他的 pending 的中断向 CPU 提交。
- 为 CPU 设置中断优先级掩码。通过 priority mask,可以 mask 掉一些优先级比较低的中断,这些中断不会通知到 CPU。
- 设置 CPU 的中断抢占(preemption)策略。
- 在多个中断事件同时到来的时候,选择一个优先级最高的通知 CPU。
GICv3 控制器内部模块和各中断类型的关系如下图所示:
中断路由
GICv3 使用 hierarchy 来标识一个具体的 core, 如下图是一个四层的结构(aarch64):
用
各个 affinity 的定义是根据 SOC 自己的定义,比如:
. ..
...
中断亲和性的设置的通用函数为 irq_set_affinity,后面会做详细介绍。
中断状态机
中断处理的状态机如下图:
- Inactive:无中断状态,即没有 Pending 也没有 Active。
- Pending:硬件或软件触发了中断,该中断事件已经通过硬件信号通知到 GIC,等待 GIC 分配的那个 CPU 进行处理,在电平触发模式下,产生中断的同时保持 Pending 状态。
- Active:CPU 已经应答(acknowledge)了该中断请求,并且正在处理中。
- Active and pending:当一个中断源处于 Active 状态的时候,同一中断源又触发了中断,进入 pending 状态。
中断处理流程
https://dragonki先暂时略过.blog.这里的详细net/article/de相关内容在/1058后面详细分
- 外设发起中断,发送给 Distributor
- Distributor 将该中断,分发给合适的 Redistributor
- Redistributor 将中断信息,发送给 CPU interface
- CPU interface 产生合适的中断异常给处理器
- 处理器接收该异常,并且软件处理该中断
5T技术资源大放送!包括但不限于:C/C++,Arm, Linux,Android,人工智能,单片机,树莓派,等等。在上面的【人人都是极客】公众号内回复「peter」,即可免费获取!!
记得点击分享、赞和在看,给我充点儿电吧