中断控制器和Linux中断子系统

中断对于cpu来说扮演着举足轻重的角色,从软硬件层面涉及面广,因此流程相对也比较复杂。硬件层面涉及到arm的gic中断控制器以及CPU内部扩展的gpio中断控制器,外设利用中断资源硬件设备,软件层面涉及和架构强相关的异常处理代码,linux为屏蔽硬件涉及差异搞出来的中断子系统。以下从各个层面对中断进行展开讨论。

一.中断体系架构

中断控制器和Linux中断子系统

中断从软硬件上来分层大致可以分成四层,概述如下:
1.硬件连接层:普通外设连接到中断控制器,中断控制器连接到处理器核的IRQ和FIQ脚,对于处理器来说,中断控制器和普通外设一样,都是外设,所不同的是中断控制器电路是集成在了处理器内部。
2.架构代码:中断对于处理器来说属于异常模式,当中断来临的时候,处理器需要切换到异常模式,执行处理异常的代码,就是上图中的arch code,这一块代码和处理器的体系架构相关,arm64的代码路径位于:kernel\arch\arm64\kernel\entry.S。其次就是中断控制器的驱动代码,ARM中断控制器是ARM用来管理外设中断的硬件电路,分为四个版本GIC_V1/GIC_V2/GIC_V3/GIC_V4/
3.中间层:和硬件无关,对于所有体系架构来说都是一样,是linux用来屏蔽硬件架构差异做的一个通用层;
4.应用层:各种外设驱动,调用中间层提供的通用接口来设置自己的中断和中断服务程序

二.中断控制器
2.1:GIC中断控制器硬件模块介绍
首先需要了解一下中断控制器这个硬件模块。中断控制器是帮助处理器管理繁杂外设中断的硬件电路,让处理器可以专心的做一件事情:机械的根据PC指针来执行对应代码段。从arm发布的GIC_V3规格书来看支持如下功能:

— The Armv8 architecture. —>arm8架构
— Locality-specific Peripheral Interrupts (LPIs). —>特殊外设中断(INTID:8192-)
— Private Peripheral Interrupts (PPIs). —>CPU私有外设中断(INTID:16-31)
— Software Generated Interrupts (SGIs). —>软中断,用于核间通信(INTID:0-15)
— Shared Peripheral Interrupts (SPIs). —>共享外设中断,用于普通外设(INTID:32-1019)
— Interrupt masking and prioritization. —>中断使能和优先级处理
— Uniprocessor and multiprocessor systems.—>兼容单核和多核系统
— Wakeup events in power management environments —>支持唤醒

GIC从硬件模块组成来看可以分成三部分,distributor,redistributor,cpu-interface

中断控制器和Linux中断子系统

从上图中可以看出:
1.SPI经过distributor分发给redistributor,redistributor再分发给cpu interface,再经过cpu interface路由给目标CPU进行处理;
2.PPI和LPI进过redistrubutor和cpu interface路由给目标CPU进行处理;
3.SGI是由CPU产生的,经过GIC分发给目标CPU处理,用于核间通信

三个部分扮演角色主要责任如下:
distributor:
GICD_CTLR provides global settings for:
• Enabling affinity routing.
• Disabling security.
• Enabling Secure and Non-secure Group 1 interrupts.
• Enabling Group 0 interrupts.
For SPIs, the Distributor provides a programming interface for:
• Enabling or disabling SPIs. //使能 spi
• Setting the priority level of each SPI. //设置每一路spi中断的优先级
• Routing information for each SPI. //保存每一路spi中断的路由信息
• Setting each SPI to be level-sensitive or edge-triggered. //设置每一路spi中断的触发条件
• Generating message-based SPIs.
• Assigning each SPI to an interrupt group.
• Controlling the pending and active state of SPIs.

redistributor:
• Identifying, controlling, and configuring supported features to enable interrupts and
interrupt routing of the implementation.
• Enabling or disabling SGIs and PPIs.
• Setting the priority level of SGIs and PPIs.
• Setting each PPI to be level-sensitive or edge-triggered.
• Assigning each SGI and PPI to an interrupt group.
• Controlling the pending state of SGIs and PPIs.
• Controlling the active state of SGIs and PPIs.
• Power management support for the connected PE.
• Where LPIs are supported, base address control for the data structures in memory that
support the associated interrupt properties and their pending status.
• Where GICv4 is supported, base address control for the data structures in memory
that support the associated virtual interrupt properties and their pending status.

cpu-interface
• General control and configuration to enable interrupt handling in accordance with the
Security state and legacy support requirements of the implementation.
• Acknowledging an interrupt. //告知收到一个中断
• Performing a priority drop. //降低中断的优先级
• Deactivation of an interrupt.//让一个中断休眠
• Setting an interrupt priority mask for the PE.//为CPU设置中断优先级
• Defining the preemption policy for the PE.//为CPU定义中断优先级
• Determining the highest priority pending interrupt for the PE.//为CPU决定一个处于pending状态,最高优先级的中断

一个中断从产生开始,一共有如下几种状态,由GIC来维护着这个状态机
中断控制器和Linux中断子系统

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。©
* 如果该中断又重新产生,那么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。

2.2:中断控制器驱动流程
GIC驱动的初始化相对简单,执行流程如下图所示
中断控制器和Linux中断子系统

三.linux中断子系统
linux针对硬件差异,做了一个中间层,屏蔽底层硬件差异,让驱动开发者调用统一接口注册中断,从而让驱动的复用大大提高,围绕三个问题对对linux的中断子系统进行展开
。。。持续更新中

四.附件
arm官方发布的gic中断控制文档
https://developer.arm.com/documentation/ihi0069/f/?search=5eec74c8e24a5e02d07b278e