中断控制器(GIC)(上)

简介: 中断控制器(GIC)

前言

上篇大概讲了一下ARM的异常处理,但是处理器是如何知道是哪一种异常或中断的呢?这就需要中断控制器了。


linux中断管理机制

操作系统有个非常重要的部分外设,比如鼠标,键盘,声卡等。处理器与外设计算能力与处理速度上是不在一个数量级的。假设处理器要得到键盘或鼠标的事件,如果处理器发出一个请求信号,它就一直再轮询键盘或鼠标的响应,由于键盘鼠标响应速度慢得多,这就会导致浪费很多资源。但是如果键盘或鼠标产生数据了,去通知处理器,处理器停下当前工作来处理键盘,鼠标事件,处理完后继续原来的工作,这样就会高效很多。

从系统的角度来讲,linux内核中断管理可以分为4层:

  • 硬件层面:比如CPU和中断控制器的连接。
  • 处理器架构管理:比如CPU中断异常处理。
  • 中断控制器管理:比如IRQ中断号映射。
  • linux内核通用中断处理层:比如中断注册和中断处理。

不同体系结构中对中断控制器设计理念有所不同,ARM公司提供通用中断控制器(GIC),x86体系架构采用高级可编程中断控制器(PIC).

ARM中断控制器

GIC(Generic Interrupt Controller)作为 ARM 系统中通用中断控制器,目前有四个版本,V1~V4(V2最多支持8个ARM core,V3/V4支持更多的ARM core,主要用于ARM64系统结构)。我们以GIC-400为例:

如图所示,当中断发生的时候,通过中断控制器,发出中断给CPU。GIC-400通过AMBA(Advanced Microcontroller Bus Architecture)片上总线连接到一个或者多个ARM处理器上。从图中我们可以看出GIC 是联系外设中断和 CPU 的桥梁,也是各 CPU 之间中断互联的通道(也带有管理功能),它负责检测、管理、分发中断。简化图,如下:

根据简化图,ARM CPU 对外的连接只有2 个中断: IRQ和FIQ ,相对应的处理模式分别是一般中断(IRQ )处理模式和快速中断(FIQ )处理模式。所以GIC 最后要把中断汇集成2 条线,与CPU 对接。

GIC结构分析

如下图,是中断控制器的结构:

GIC中断控制器可以分为:仲裁单元和CPU接口模块。状态机有:inactive,pending,active,active and pending.

其中有两个重要组成部分分别是分发器(Distributor)与CPU接口单元(CPU Interface):

分发器(Distributor)

系统中的所有中断源都连接到该单元。可以通过仲裁单元的寄存器来控制各个中断源的属性,例如优先级、状态、安全性、路由信息和使能状态。

分发器把中断输出到“CPU接口单元”,后者决定将哪个中断转发给CPU核。

分发器的主要的作用是检测各个中断源的状态,控制各个中断源的行为,分发各个中断源产生的中断事件到指定的一个或者多个CPU接口上。虽然分发器可以管理多个中断源,但是它总是把优先级最高的那个中断请求送往CPU接口。分发器对中断的控制包括:

  1. 中断使能或禁能控制。分发器对中断的控制分成两个级别,一个是全局中断的控制(GIC_DIST_CTRL),一旦禁止了全局的中断,那么任何的中断源产生的中断事件都不会被传递到CPU接口;另外一个级别是对针对各个中断源进行控制(GIC_DIST_ENABLE_CLEAR),禁止某一个中断源会导致该中断事件不会分发到CPU接口,但不影响其他中断源产生中断事件的分发。
  2. 控制将当前优先级最高的中断事件分发到一个或者一组CPU接口。
  3. 优先级控制。
  4. 中断属性设定,例如是电平触发还是边沿触发。
  5. 中断的设定。
  6. 分发器可以管理若干个中断源,这些中断源用ID来标识,我们称之interrupt ID

CPU接口单元(CPU Interface)

CPU核通过控制器的CPU接口单元接收中断。CPU接口单元寄存器用于屏蔽,识别和控制转发到CPU核的中断的状态。系统中的每个CPU核心都有一个单独的CPU接口。分发器对中断的控制包括:

* 使能中断请求信号到CPU上;

* 中断的确认;

* 标识中断处理的完成;

* 为处理器设置中断优先级掩码;

* 设置处理器的中断抢占策略;

* 确定处理器的最高优先级pending中断;

中断类型

SPI:公用外设中断:最多可以支持 988 个外设中断,硬件中断号从 ID32~ID1019。

PPI:私有外设中断:是每个 CPU 私有的中断。最多支持 16 个 PPI 中断,硬件中断号从 ID16~ID31。

SGI:软件触发中断:通常用于多核间通讯,最多支持 16 个 SGI 中断,硬件中断号从 ID0~ID15。

中断状态

  • lnactive:中断源没有发送中断;
  • Pending:中断源已经发送中断,等待处理器处理;
  • Active:处理器已经确认中断,正在处理;
  • Active and Pending:处理器正在处理中断,相同的中断源* 又发送了一个中断。

当GIC接收到一个中断请求,将其状态设置为Pending。重新产生一个挂起状态的中断不影响该中断状态。

中断处理顺序

① GIC决定该中断是否使能,若没有被使能对GIC没有影响;

② 对于每个Pending中断,GIC决定目标处理器;

③ 对于每个处理器 ,Distributor根据它拥有的每个中断优先级信息决定最高优先级的挂起中断,将该中断传递给目标CPU Interface;

④ GIC Distributor将一个中断传递给CPU Interface后,该CPU Interface决定该中断是否有足够的优先级将中断请求发给CPU;

⑤ 当CPU开始处理该异常中断,它读取GICC_IAR应答中断。读取的GICC_IAR获取到中断ID,对于SGI,还有源处理器ID。中断ID被用来查找正确的中断处理程序。

GIC识别读过程后,将改变该中断的状态:

a) 当中断状态变为active时,如果该中断挂起状态持续存在或者中断再次产生,中断状态将从Pending转化为pending & active

b) 否则,中断状态将从pending状态变为active

⑥ 当中断完成中断处理后,它需要通知GIC处理已经完成。这个过程称为 priority drop and interrupt deactivation:

a) 总是需要向EOIR寄存器写入一个有效的值(end of interrupt register)

b) 也需要接着向GICC_DIR写入值(deactivate interrupt register)

中断状态机

  1. 添加挂起状态(A1、A2)对于一个 SGI,发生以下 2 种情况的 1 种:
  • 软件写 GICD_SGIR 寄存器,指定目标处理器
  • 目标处理器上软件写GICD_SPENDSGIRn 寄存器
  1. 对于一个 SPI 或 PPI,发生以下 2 种情况的 1 种:
    * 外设发出一个中断请求信号
    * 软件写 GICD_ISPENDRn 寄存器
  2. 删除挂起状态(B1、B2)
    对于 SGI,目标处理器写 GICD_CPENDSGIRn 寄存器,对于一个 SPI 或 PPI,发生以下 2 种情况的 1 种:
    * 电平触发类型中断,信号取消
    * 边沿触发类型中断,软件写 GICD_ICPENDRn 寄存器
  3. 挂起到激活(C)
    如果中断使能,并且高优先级,软件从 GICC_IAR 寄存器读取时发生状态改变。
  4. 挂起到激活和挂起(D)
    对于 SGI,这种转变发生在以下任一情况下:
    * 将 SGI 状态设置为挂起的写入操作与读取 GICC_IAR 几乎同时发生
    * 当多个挂起的 SGI 具有相同 ID 时,并且它们来自同一个源处理器并指向同一个处理器。其中一个 SGI 状态变为激活(C),其他 SGI 状态变为激活和挂起(D)。
    对于 SPI 或 PPI,满足以下所有条件,则发生这种转换
    * 中断开启
    * 软件读取 GICC_IAR,读操作将激活状态添加到中断中。
    此外,还应满足以下条件之一:
    * 对于电平触发中断,中断信号保持。通常都是这样,因为外设直到处理器处理完中断后才会取消触发信号。
    * 对于边沿触发中断,是否发生此转换取决于读取 GICC_IAR 的时间(中断再次触发,上一次未处理),读取 GICC_IAR 可能会转换到 C,后面可能会转换到 A2。
  5. 删除激活状态(E1、E2)
    软件写入 GICC_EOIR 或 GICC_DIR 来停用中断,

GIC驱动

节点信息

gic: interrupt-controller@2c001000 {
    compatible = "arm,cortex-a9-gic";//用于与具体的驱动来进行匹配
    #interrupt-cells = <3>;
    /*用于指定编码一个中断源所需要的单元个数,这个值为3。比如在外设在设备树中添加中断信号时,通常能看到类似interrupts = <0 23 4>;的信息,第一个单元0,表示的是中断类型(1:PPI,0:SPI),第二个单元23表示的是中断号,第三个单元4表示的是中断触发的类型;*/
    #address-cells = <0>;
    interrupt-controller;//表示该设备是一个中断控制器,外设可以连接在该中断控制器上;
    reg = <0x2c001000 0x1000>,//描述中断控制器的地址信息以及地址范围
          <0x2c000100 0x100>;
  };

内核启动后会将该节点解析成device_node结构。

驱动流程

GIC的工作,本质上是由中断信号来驱动,因此驱动本身的工作就是完成各类信息的初始化,注册好相应的回调函数,以便能在信号到来之时去执行set_handle_irq函数的设置很关键,它将全局函数指针handle_arch_irq指向了gic_handle_irq,而处理器在进入中断异常时,会跳转到handle_arch_irq执行,所以,可以认为它就是中断处理的入口函数了。驱动中完成了各类函数的注册,此外还完成了irq_chip, irq_domain等结构体的初始化,这些结构在下文会进一步分析。最后,完成GIC硬件模块的初始化设置,以及电源管理相关的注册等工作。

数据结构

GIC驱动中,使用struct gic_chip_data结构体来描述GIC控制器的信息,整个驱动都是围绕着该结构体的初始化,驱动中将函数指针都初始化好,实际的工作是由中断信号触发,也就是在中断来临的时候去进行回调struct irq_chip结构,描述的是中断控制器的底层操作函数集,这些函数集最终完成对控制器硬件的操作struct irq_domain结构,用于硬件中断号和Linux IRQ中断号(virq,虚拟中断号)之间的映射;

每个中断控制器都对应一个IRQ Domain;

中断控制器驱动通过irq_domain_add_*()接口来创建IRQ Domain;

IRQ Domain支持三种映射方式:linear map(线性映射),tree map(树映射),no map(不映射);

  1. linear map:维护固定大小的表,索引是硬件中断号,如果硬件中断最大数量固定,并且数值不大,可以选择线性映射;
  2. tree map:硬件中断号可能很大,可以选择树映射;
  3. no map:硬件中断号直接就是Linux的中断号;
目录
相关文章
|
3月前
|
Linux
使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题
使用funcgraph-retval和bpftrace/kprobe快速定位并解决cpu控制器无法使能的问题
|
5月前
|
7月前
|
芯片 索引
可编程中断控制器
可编程中断控制器
246 0
|
Linux 索引
RISC-V SiFive U54内核——CLINT中断控制器
RISC-V SiFive U54内核——CLINT中断控制器
|
传感器 调度
什么是中断系统?
一、什么是中断系统 中断系统是计算机系统中的一种机制,它允许外部设备和程序请求处理器的注意力,以便进行特定的操作。当一个中断请求被触发时,处理器会暂停当前正在执行的程序,转而执行与中断相关的程序或服务例程。中断系统可以提高计算机系统的效率和响应速度,因为它允许处理器在等待某些事件的同时执行其他任务。常见的中断包括硬件中断(例如键盘输入、鼠标移动、网络数据传输等)和软件中断(例如操作系统调度、系统调用等)。 二、中断系统的特点 中断系统具有以下特点: 1. 实时性:中断系统能够及时响应外部设备的请求,提高计算机系统的响应速度和效率。 2. 可靠性:中断系统能够保证中断请求的可靠性,确保外部设备的
288 0
|
编译器
中断的解析
中断的解析
99 0
|
Linux
中断控制器(GIC)(下)
中断控制器(GIC)(下)
200 0
|
芯片
中断系统结构及中断控制详解
本文详解了中断系统结构及中断控制。
528 0
详解中断系统
本文针对地详解了中断系统
273 0