转载自https://zhuanlan.zhihu.com/p/85313527 作者:兰新宇
前面的文章介绍了Linux的中断处理机制,而操作系统的中断处理是和硬件的中断控制器紧密相关的,本文将以ARM这样一个具体的处理器为例,讲解硬件层面对中断的支持。
ARM的中断控制器被称为GIC(Generic Interrupt Controller),最开始的v1版本最多支持8个PE和1020个中断源(interrupt source),用于ARM Cortex-A5,A9等。这里PE代表Processing Element,它是ARM架构对处理单元的抽象,为方便理解,就把它当做ARM cores好了。
v2版本增加了对虚拟化功能和TrustZone的支持,用于ARM Cortex-A7,A15,A53,A57等。
v3版本对支持的ARM cores数目和中断源的数目都有所增加,并增加了MSI(Message-Based Interrupt)功能。
v4版本加入了对直接注入虚拟中断的支持,v3和v4都可用于ARM Cortex-A53,A57,A72等。
本文接下来的叙述将以GIC v3/v4为基准。
GIC的组成
中断控制器是中断源和CPU之间的桥梁,自从CPU进入多核时代以后,中断控制器也慢慢地由单一的模块分化成了两个部分,一部分是直接连接中断源的,由所有的CPU共享,比如x86中的I/O APIC,另一部分是对接CPU的,其数目通常就等于CPU的数目,比如x86中的Local APIC。
类似地,ARM的GIC也由Distributer和Redistributor两部分构成,其中 Distributer 类似于I/O APIC,其发挥的作用顾名思义,就是根据CPU的配置,将到来的中断源派发到CPU对应的Redistributor。Redistributor 类似于Local APIC,它会将Distributer派发来的中断送到其连接的CPU。
中断源的分类
GIC中断源的编号从0开始,0到15是SGI(Software Generated Interrupt),所谓"software generated",就是指由CPU直接写对应的寄存器触发中断,因而这种中断不是由硬件产生的,而是由软件主动产生的。这种特殊的中断主要用于核间通信,类似于x86中的IPI(Inter-Processor Interrupt)。
编号16到31是PPI(Private Peripheral Interrupt),所谓"private",是指这个中断为CPU私有/专用,那什么中断会有这种特性呢?比如通用定时器中断啊,温度传感器中断啊。
SGI和PPI都是每个CPU各有一份,不同CPU的同一种SGI/PPI共享同一个编号,因而它们都属于"banked"形式的中断源。
与专有的PPI相对应的就是所有CPU全局共享的SPI(Shared Peripheral Interrupt),编号从32到1019。
编号16到31是PPI(Private Peripheral Interrupt),所谓"private",是指这个中断为CPU私有/专用,那什么中断会有这种特性呢?比如通用定时器中断啊,温度传感器中断啊。
SGI和PPI都是每个CPU各有一份,不同CPU的同一种SGI/PPI共享同一个编号,因而它们都属于"banked"形式的中断源。
与专有的PPI相对应的就是所有CPU全局共享的SPI(Shared Peripheral Interrupt),编号从32到1019。
至于编号大于8192的LPI,就比较特殊了,它是从GICv3版本开始引入的,主要用于前面提到的message based的中断(MSI)。消息(message)是操作系统中一种常用的通信手段,硬件在中断系统中引入类似的实现机制,相比于传统的中断可以实现更灵活的设计。LPI的中断一定是MSI形式的,而SPI的中断可以是MSI,也可以不是。
为了支持MSI的特性,其配置信息不是放在寄存器中,而是放在一段特殊的内存中,这种内存通常被称为PRAM(Parameter RAM),PRAM配置相比于寄存器配置的好处是可以根据需要更有效地利用存储空间。
从Linux的角度,这里的编号属于硬件中断号,需要经过转换才能得到操作系统处理所需的软件中断号(参考这篇文章)。
这种对中断源的划分是从GIC输入的角度进行的,而中断经过GIC(输出)到达CPU之后,则只有IRQ(Interrupt Request)和FIQ(Fast Interrupt Request)两种,其转换规则有一些复杂,在此就不展开了。
中断源的优先级
在GICv3中,有一个running priority的概念,当一个CPU不处理中断时,它的running priority就等于代表最低优先级的0xFF,而当它开始应答某个中断源后,该CPU的running priority就等于这个中断源的优先级。
引入running priority的目的主要是为了解决中断抢占(preemption)的问题。假设不允许抢占,那么在低优先级的中断处理期间,高优先级的中断将被阻塞。
而如果允许抢占,则高优先级的中断将被优先处理。
从软件的角度,GIC提供的这一硬件特性会导致中断处理函数的嵌套,增加软件的复杂度,因而同FIQ一样,通常并不被Linux等操作系统作为常规的特性使用。
本文主要介绍了ARM中断控制器的构成和其对中断源的分类。硬件提供特性,但操作系统不一定会支持,下文将结合Linux内核的实际代码,讲解Linux对ARM中断的处理过程。
评论 (0)