🌟🌟🌟博主主页:MuggleZero 🌟🌟🌟
《ARMv8架构初学者笔记》专栏地址:《ARMv8架构初学者笔记》
GIC-500控制器支持GICv3架构,具有以下中断类型:
-
SGI(软件触发中断),16个
ID0~15,处理器之间的中断,也就是说一个core产生的中断被送到其他core上。每个core上的SGI相互独立(设置独立、ID范围独立)。
-
PPI(私有的外设中断),16个
ID16~31,每个处理器核心的私有中断,PPI会被送到指定的CPU上处理。
-
SPI(共享的外设中断),960个
ID32~991,对应了spi[991:32]位。你可以对每个SPI进行编程,使其针对一个特定的核或任何核。在一个核上激活一个SPI,就会激活所有核的SPI。也就是说,GIC-500最多允许一个核来激活一个SPI。每个SPI的设置也在所有内核之间共享。
-
LPI(指定区域的外设中断)
GIC-500始终支持多达57344个LPI,有一个缓存用于保存最频繁中断的设置。ITS和LPI的设置存储在主存储器中,因此一个高速缓存的缺失可能会导致多达三次的内存往返。第一个LPI的ID号是8192。
LPI通常用于产生基于消息的中断的外围设备。一个LPI在一个给定的时间内只针对一个内核。当外设写到ITS(中断映射服务)时就会产生LPI,ITS(中断映射服务)也持有控制LPI产生和维护的寄存器。ITS(中断映射服务)提供中断ID转换,如果系统MMU也存在于这些外设中,则允许外设直接由虚拟机拥有。因此LPI更适合虚拟机。
GIC的一般架构
GIC控制器由仲裁单元、再分配单元、中断映射单元和CPU接口模块组成。仲裁单元为每一个中断源维护了一个状态机,状态包含inactive、pending、active和active and pending。
-
仲裁单元:提供了SPI的路由配置,并保存所有相关的路由和优先级信息。
-
再分配单元:提供了PPI和SGI的配置设置,总是在有限的时间内向CPU接口提交具有最高优先级的未决中断。
SPI中断检测流程
-
当GIC检测到中断发生的时候,将其标记为pending状态。
-
对于处于pending的中断,仲裁单元会确定目标CPU,将中断请求发送到这个CPU上。
-
对于每个CPU,仲裁单元会从pending中的中断选择优先级最高的,然后将其发到目标CPU的interaface上
-
CPU interface会决定这个中断是否可以发给CPU。如果可以发送,则GIC发送一个中断请求信号给该CPU,使得CPU进入中断异常。
-
当CPU进入中断异常后,中断处理程序会去读取GICC_IAR寄存器来响应中断,寄存器会返回硬件中断号。
-
当处理器完成中断服务后,必须发送一个EOI(End of Interrupt)给GIC控制器。
中断优先级抢占
GIC控制器支持中断优先级抢占功能。对于优先级高的中断A,如果有一个低优先级且处于pending状态的中断B,GIC会做出裁决,让A去抢占B,优先将A的中断请求发送给CPU。CPU也会应答高优先级中断。
下图是GIC400中的时序图。假设M和N都是SPI类型的中断并通过FIQ来处理,高电平触发,N比M优先级高,它们的目标CPU相同。
工作流程如下:
T1
GIC的仲裁单元检测到中断输入M的引脚电平出现了电平变化,
T2
此时仲裁单元设置中断M得状态为pending。
T17
经过tph个时钟后,CPU interface会拉低nFIQCPU[n]信号(在中断M变成pending后,大概需要15个周期来拉低nFIQCPU[n]信号),仲裁单元需要这15个周期来判断pending状态下哪个中断优先级最高。
T42
仲裁单元检测到另一个优先级更高的中断N。
T43
接着T42,仲裁单元用中断N替换中断M为当前pending状态下优先级最高的中断,并且设置中断N的状态的pending。
T58
CPU interface在nFIQCPU[n]信号低的状态下,更新GICC_IAR寄存器中的Interrupt ID域,将该域的值变为中断N的硬件中断号。
T61
CPU(Linux中的中断服务程序)读取GICC_IAR寄存器,即软件响应了中断。这时仲裁单元又会把中断N的状态从pending设置为active and pending。
T61~T131:Linux处理中断N的中断服务程序
T64时刻,在中断N被Linux内核响应后的3个时钟内,CPU interface模块完成了对nFIQCPU[n]信号的deasserts,即拉高了nFIQCPU[n]信号。
T126时刻外设也deassert了该中断N;
T128时刻移除了该中断N的pending状态;
T131时刻,Linux中的内核中断服务程序将中断N的ID号写入GICC_EOIR寄存器完成中断N的全部处理过程。
T146、T211和T214
在将中断N的ID号写入GICC_EOIR寄存器后的tph个时钟后,仲裁单元会选择下一个最高优先级的中断M,发送中断请求给CPU interface模块。CPU interface模块会拉低nFIQCPU[n]信号来向CPU报告这个中断M。
T211时刻,Linux中的内核中断服务程序读取GICC_IAR寄存器来响应中断,仲裁单元将中断M设置为active and pending。
T214时刻,在CPU响应中断后的3个时钟内,CPU interface模块会拉高nFIQCPU[n]信号来完成更多动作。
总结
对于中断时序来说,如果出现更高优先级的中断,仲裁单元会优先处理,将其设置为优先级最高的pending状态。
对于pending状态的处理,大致流程是:
-
CPU interface模块拉低nFIQCPU[n]信号来向CPU报告中断;
-
Linux中断服务程序读取GICC_IAR寄存器来响应中断,并且设置状态为active and pending;
-
响应后的三个周期内,CPU interface模块拉高nFIQCPU[n]信号
-
移除当前中断的pend ing状态
-
Linux中断服务程序将中断的硬件ID写入GICC_EOIR。
-
处理下一个中断。
欢迎关注我的个人微信公众号,一起交流学习嵌入式开发知识!
关注「求密勒实验室」