1.中断是怎么处理的
下文通过几个疑问 给出了硬件和软件是怎么交互并处理中断的
1.1 中断什么时候初始化?
中断初始化是伴随内核【就是操作系统】的初始化过程进行的。各硬件及外设的中断处理程序注册时间是不确定的,有的是在内核初始化过程中就完成注册,有的外设是在运行过程中后来接入的,时间就不可预知。
下面的链接详细区分了内核/os/进程
1.2 中断是一个独立的进程吗?
中断的发生时刻是不可预知的,所以内核在初始化时完成中断初始化,这里的中断初始化主要是
- 对中断控制器硬件的初始化,分配寄存器地址,配置寄存器等
- 给中断向量表分配地址空间,并初始化【这个向量表会在后续有新的外设接入时更新】
- 注册中断irq_domain
中断不是一个进程,进程是内核/操作系统为管理运行的各种用户程序而给出的概念。像管理硬件资源这种操作都是OS操作系统处理的。
而OS是和cpu core绑定的,可以理解为cpu core的驱动程序。cpu core上有中断的硬件连线,收到中断后,OS直接跳到中断处理流程,而无论当前执行的是什么进程。
中断的硬件连线又是来自于中断控制器的输出,输出是直接给了cpu core,也不是给哪个进程
1.3 硬件中断是各种各样的,cpu是如何正确执行对应的中断处理函数
硬件是各种各样的,但是当硬件运行起来后【初始化时候】,该硬件的驱动程序就会到内核中注册自己的中断处理函数,就建立了中断号到中断处理程序的对应关系,CPU获取到一个中断号后,查到对应的中断处理程序调用就好了。这两者的对应关系最后会抽象成了中断向量表
, 现在叫 IDT
中断描述符表。
2.gic中断管理器
2.1 中断管理器的结构和组件
为了适应大规模的SoC设计,GIC-600被设计成分布式IP【和noc/nic一样可以分布在不同clk domain/power domain/harden】。所谓分布式,GIC-600由几种组件构成,每个组件可以跟其它相关模块在物理设计上摆放在一起,并与其拥有共同的电源域;组件之间通过片上网络(network on chip,简称NoC)通信,从而达到更好的时序。
2.1.1 gic组件
GIC-600的重要组件包括以下几种:
- Distributor:GIC-600的核心部件,负责与其它组件通信,主要处理SPI和LPI
- Redistributor:与cluster或core交互,主要处理PPI和SGI,同时将Distributor发送过来的SPI与直接传输过来的PPI、SGI进行优先级排序,然后输出给cpu core/cluster
- ITS(Interrupt Translation Service):处理基于消息的中断,用于解析LPI
- SPI collator:顾名思义,收集整理SPI
- Wake request:组件的主要作用就是可以产生唤醒信号给core,如果SoC设计中没有做关于core功耗方面的设计,这个组件可以不需要;如果有功耗控制的需求,这些唤醒信号要给SCP(system control processor)或者相关的模块,再做进一步的设计,具体取决于设计需要了。
一个soc里只有一个Distributor,同时可以有若干redistributor,但是redistributor只与distributor通信,且需要双向传输,Redistributor是和cpu core或cluster一一对应的。
GIC与cpu通信的接口是cpu interface。cpu interface,将GICD[Distributor]发送的中断信息,通过IRQ,FIQ管脚,发送给连接到该cpu接口的core。有种说法有reDistributor的GIC只通过reD与core交互,也就是reD与core用cpu interface连接
2.1.2 中断类型
- 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 中断。
怎么理解PPI和SPI呢?这里的私有和共用是相对于cpu core/cluster而言的,比如说一个DMA的中断既可以上报给core0也可以上报给core1,那么它就是一个SPI。SPI最终上报给哪个core这就是Distributor的工作。而关于core0的clk的中断是只能给core0的,那么这个中断就属于core0的私有中断。无论PPI还是SPI都是外设产生的
SGI这类软件中断和PPI有一个共同点就是产生的时候已经确定要哪一个core处理,所以PPI和SGI都是不需要Distributor进行仲裁的,也就不需要经过Distributor,而是直接连接到reDistributor
LPI是一种新类型的中断,基于消息的中断,需要ITS[Interrupt Translation Service]来解析才能给core处理。
下图给出了PPI的一些中断示例。
2.1.3 gic的结构
gic既然是分布式组件,那么组件间就需要有互联。有两种典型的互联架构:
- 组件间通过私域互联
- 组件间通过支持AXI-stream接口的noc互联
上图就是私有桥接的方式,互联组件
上图是走系统的互联总线
第一种方法,适合规模较小的,全局时钟方案简单的SoC,GIC-600的组件不依赖于片上网络(因为没有可用接口,比如NIC等)。这种方法的弊端是,组件之间的走线可能会非常长,并且可能需要在别的IP中穿行。好处是,不占用任何NoC的带宽。
第二种方法,适合大规模的物理设计,尤其是全局时钟方案复杂的SoC。比如有很多的cluster,一般而言,一个redistributor对应一个cluster,这样redistributor可以和cluster一起做布局布线,redistributor和cluster之间的通信可以保持在一个比较高的频率,且timing容易实现。同样,对于有很多PCIe控制器的设计,ITS可以和PCIe控制器放在一起,实现LPI。对于SPI来说,一般多是给低速的外设准备的,所以SPI collator可以和distributor放在一起。
2.2 AXI stream接口
gic组件间无论采用私域互联还是总线互联,组件的互联接口都是AXI4-stream接口,该接口可参考
相比于AXI4接口,AXI-stream接口只相当于只有AXI的aw/w/b/ar/r中的wch和rch,也就是只有读写两个方向的数据流,没有cmd和响应通道。
注意AXI5新增的一个TWAKEUP信号。
2.2.1 属性层次(affinity level)
AXI-stream用TDEST信号来寻址目的地,下面给出了GICv3的core层次结构,可根据层次结构来设置TDEST。
GICv3的一大变化,是对core的标识。对core不在使用单一数字来表示,而是使用属性层次来标识,和arm core,使用MPIDR_EL1系统寄存器来标识core一致。
每个core,根据属性层次的不同,使用不同的标号来识别。如下图所示,是一个4层结构,那么对于一个core来说,就可以用 xxx.xxx.xxx.xxx 来识别。
这种标识方式,和ARMv8架构的使用MPIDR_EL1寄存器,来标识core是一样的。
2.3 中断处理状态转换
下面一段摘自:
Linux 中断 —— ARM GIC 中断控制器_gic 中断抢占-CSDN博客
GIC仲裁单元:为每一个中断维护一个状态机,分别是:inactive、pending、active and pending、active。
下面是来自IHI0048B GIC-V2规格书3.2.4 Interrupt handling state machine截图:
GIC检测中断流程如下:
(1) 当GIC检测到一个中断发生时,会将该中断标记为pending状态(A1)。
(2) 对处于pending状态的中断,仲裁单元回确定目标CPU,将中断请求发送到这个CPU上。
(3) 对于每个CPU,仲裁单元会从众多pending状态的中断中选择一个优先级最高的中断,发送到目标CPU的CPU Interface模块上。
(4) CPU Interface会决定这个中断是否可以发送给CPU。如果该终端优先级满足要求,GIC会发生一个中断信号给该CPU。
(5) 当一个CPU进入中断异常后,会去读取GICC_IAR寄存器来响应该中断(一般是Linux内核的中断处理程序来读寄存器)。寄存器会返回硬件中断号(hardware interrupt ID),对于SGI中断来说是返回源CPU的ID。
当GIC感知到软件读取了该寄存器后,又分为如下情况:
* 如果该中断源是pending状态,那么转改将变成active。(C)
* 如果该中断又重新产生,那么pending状态变成active and pending。(D)
* 如果该中断是active状态,现在变成active and pending。(A2)
(6) 当处理器完成中断服务,必须发送一个完成信号EOI(End Of Interrupt)给GIC控制器。软件写GICC_EOIR寄存器,状态变成inactive。(E1)
补充:
(7) 对于level triggered类型中断来说,当触发电平消失,状态从active and pending变成active。(B2)
常用路径是A1->D->B2->E1。
3.参考资料
吐血整理 | 肝翻 Linux 中断所有知识点 - 阅读清单 - 腾讯云开发者社区-腾讯云
上面链接从硬件和linux内核中断两方面介绍了中断的处理,更偏向于linux内核中断处理,从初始化到中断向量表,到检测到中断触发开始中断处理的过程。
Linux中断一网打尽(1) —— 中断及其初始化-腾讯云开发者社区-腾讯云
上面这一篇侧重于讲解内核中断初始化过程,比第一篇关于初始化的过程详细一些