首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

一文搞懂GICv3中断控制器的工作原理

1,介绍

众所周知,要想获取一个功能的执行状态,我们可以采用两种方式:一种方式是,定时查询,查询功能是否完成;另一种方式是中断,当完成了某项功能,产生一个中断给到CPU,告诉CPU某个功能已经完成。为了尽可能提高CPU处理数据的性能,提高获取功能完成状态的实时性,中断是一个很好的选择。

为什么还要一个中断控制器呢?直接将外设的中断引到CPU上不更简单吗?是因为外设众多,如果每个外设的中断都直接给到CPU,由于外设数量众多,这会导致连接CPU引脚数量众多,从而增加CPU的体积。如果同时有多个中断发生,CPU需要维护一个中断等待队列,并且中断还有优先级,维护队列和判定优先级都会占用CPU的时间,降低CPU的性能。因此中断控制器就应运而生了,它是为了减少CPU的负载,让CPU更专注于计算。

中断控制器相当于一个代理,外设产生的中断会先发给中断控制器,中断控制器管理、控制可屏蔽中断,并且对中断的优先级进行判断,再高优先级中断转交给CPU,这样CPU既能专注计算,又能及时响应到中断事件,并执行相应的中断服务程序。

当前主流芯片架构通常采用不同的中断控制器:

我们重点关注一下ARM使用的GIC(Generic Interrupt Controller,通用中断控制器)中断控制器,它是ARM公司给Cortex-A/R 内核提供的一个中断控制器,目前GIC有4个版本,GICv1~GICv4,V1是比较旧的版本,当前已经被废弃了。GICv2~GICv4当前被使用的比较多,GICv2是给ARMv7-A架构使用的,比如Cortex-A7/A9/A15等,GICv3/GICv4是给ARMv8-A/R架构使用的。下表总结了GIC的主要版本及一起使用的典型处理器:

本文重点关注ARM的GICv3中断处理器。下面会从GICv3的框架、分组、状态机及切换、寄存器、中断处理流程几个方面展开介绍GICv3,力求通过这一篇文章能了解GICv3的工作原理。

2,框架

GICv3是基于ARMv8的SOC设计中应用较为广泛的一种中断控制器,GICv4与GICv3的功能基本相同,只是为了提高虚拟化的性能,增加了直接注入虚拟中断的能力。

  GICv3为CPU处理所有连接到其上的中断,包括管理所有的中断源、中断行为、中断分组以及中断路由方式等,同时还提供相应的寄存器接口用于软件对这些行为的控制。设或软件触发中断后,GICv3根据中断配置信息,将其路由到特定cpu的IRQ或FIQ中断线上。CPU接收到中断后执行必要的上下文保存后,跳转到中断异常入口,并执行相应的中断处理流程。

为了实现中断的配置、接收、仲裁和路由功能,GICv3设计了不同组件,它包含了SPI(shared peripheral interrupt)、PPI(private peripheral interrupt)、SGI(software generated interrupt)和LPI(locality-specific peripheral interrupt)四种中断类型,以及distributor、redistributor、ITS(interrupt translation service)和CPU interface四大组件。

组成模块如下:

PE(process element):处理器单元,中断的最终接收者和处理者。

Distributor:SPI中断的管理,将中断发送给Redistributor。外设中断分发器,外设经特定硬件中断线连接到Distributor。Distributor判断SPI中断的优先级,决定优先处理哪个中断,使用中断重映射表决定中断的目的PE,同时维护中断的active/pending/acknowledged状态。Distributor控制的功能如下:

打开或关闭每个SPI中断。Distributor对中断的控制分成两个级别。一个是全局中断的控制(GIC_DIST_CTRL)。一旦关闭了全局的中断,那么任何的中断源产生的中断事件都不会被传递到CPU interface。另外一个级别是对针对各个中断源进行控制(GIC_DIST_ENABLE_CLEAR),关闭某一个中断源会导致该中断事件不会分发到CPU interface,但不影响其他中断源产生中断事件的分发。控制将当前优先级最高的中断事件分发到一个或者一组CPU interface。当一个中断事件分发到多个CPU interface的时候,GIC的内部逻辑应该保证只assert一个CPU。

优先级控制。

interrupt属性设定。设置每个外设中断的触发方式:电平触发、边缘触发。

interrupt group的设定。设置每个中断的Group,其中Group0用于安全中断,支持FIQ和IRQ,Group1用于非安全中断,只支持IRQ。

Redistributor:SGI/PPI/LPI中断的管理,将中断发送给CPU interface。每个PE对应了一个redistributor,它是PPI/SGI/LPI中断的管理者,决定它们的优先级,触发方式,控制它们的状态,以及enable/disable特定中断。Redistributor支持的功能如下:

启用和禁用SGI和PPI。

设置SGI和PPI的优先级。

将每个PPI设置为电平触发或边缘触发。

将每个SGI和PPI分配给中断组。

控制SGI和PPI的状态。

内存中数据结构的基址控制,支持LPI 的相关中断属性和挂起状态。

电源管理支持。

CPU interface:传输中断给Core。每个redistributor连接了一个CPU interface,它负责打开和关闭PE的中断处理能力,acknowledge中断,为PE维护一个中断优先级掩码(只响应更高优先级中断),定义中断抢占策略,执行中断降级。CPU interface支持的功能如下:

打开或关闭CPU interface向连接的CPU assert中断事件。对于ARM,CPU interface 和CPU之间的中断信号线是nIRQCPU和nFIQCPU。如果关闭了中断,即便是Distributor分发了一个中断事件到CPU interface,也不会assert指定的nIRQ或者nFIQ通知Core。

中断的确认。Core会向CPU interface 应答中断(应答当前优先级最高的那个中断),中断一旦被应答,Distributor就会把该中断的状态从pending修改成active或者pending and active(这是和该中断源的信号有关,例如如果是电平中断并且保持了该 asserted电平,那么就是pending and active)。ack了中断之后,CPU interface 就会deassert nIRQCPU和nFIQCPU信号线。

中断处理完毕的通知。当interrupt handler处理完了一个中断的时候,会向写CPU interface的寄存器通知GIC CPU已经处理完该中断。做这个动作一方面是通知Distributor将中断状态修改为deactive,另外一方面,CPU interface会priority drop,从而允许其他pending的中断向CPU提交。

为CPU设置中断优先级掩码。通过priority mask,可以mask掉一些优先级比较低的中断,这些中断不会通知到CPU。

设置CPU的中断抢占(preemption)策略。

在多个中断事件同时到来的时候,选择一个最高优先级的中断通知CPU。

ITS:ITS接收LPI消息中断,根据消息携带的event id和device id,翻译得到物理中断线以及目标PE。ITS与device之间通过系统总线连接,device采用写内存地址的形式发一个中断消息给ITS。

中断类型如下:

SGI(software generated interrupt):中断号(0 - 15),软件产生的中断,一般用于核间通信,由软件写GIC的某个寄存器产生。该类型中断并没有实际的物理连线,而是由软件通过写寄存器方式触发,它只支持边沿触发。通常用于处理器之间的通信,如linux内核电源管理模块中调用的ipi中断就是通过SGI实现的。

PPI(private peripheral interrupt):中断号(16 – 31,1056 -1119),私有设备中断,一个PE可能有一些它本地专属的设备,比如PE私有的timer。这种设备产生的中断只能发给它专属的PE。因为PPI是PE私有的,所以每个PE都可以使用相同一段范围的PPI。该类型中断是每个处理器私有的,即一个特定的中断只会被路由到特定的处理器上。且其同一个中断号在每个处理器上都可以有不同的中断,如对于一个拥有两个PE的smp系统,中断号16的PPI中断可以分别被注册为PE0和PE1的私有中断,它们可以被独立触发并被特定的PE独立处理。

SPI(shared peripheral interrupt):中断号(32 – 1019,4096 - 5119),共享外设中断,它由外设产生,可以被路由至特定PE或一组PE,SPI由设备连接至Distributor中断控制器的硬件中断连线触发。该类型中断不与特定的CPU绑定,可以根据affinity配置被路由到任意CPU或一组特定的CPU上。如一般的外设中断都是通过SPI方式连接的。

LPI(locality-specific peripheral interrupt):中断号(8192 -),基于内存地址的中断,也称之为基于消息的中断,由外设写一个内存地址产生,这个内存地址一般映射至GIC ITS内部的translator寄存器。ITS接收外设写入的数据后进行翻译,然后再向特定redistributor产生一个中断。该类型中断是一种基于消息的中断,外设不需要通过硬件中断线连接到GIC上,而可以向特定地址写入消息来触发中断。LPI中断有一些其特有的属性,如只支持non secure group1分组、只支持边沿触发、可以选择使用或不使用ITS路由,以及没有active状态,也不需要显式的deactivation操作。

3,中断分组

为了支持ARMv8异常模型和security模型的中断处理,GICv3引入了中断分组机制。GICv3的中断可以分为以下三个group:

GICv3可以触发两种中断信号IRQ和FIQ,对中断分组的目的就是使不同group的中断,在不同状态下可分别被路由到IRQ或FIQ上,在AARCH64状态下,中断的路由方式如下:

在AARCH32状态下,中断的路由方式如下:

4,中断亲和性

GICv3使用hierarchy来标识一个具体的core, 如下图是一个四层的结构(AArch64):

用...的形式组成一个PE的路由。每一个core的affnity值可以通过MPDIR_EL1寄存器获取,每一个affinity占用8bit。配置对应 core的MPIDR值,可以将中断路由到该core上。每个core,连接一个cpu interface,而cpu interface会连接gic中的一个redistributor。redistributor的标识和core的标识一样。

各个affinity的定义是根据SOC自己的定义,比如:

5,中断处理流程及状态机

5.1 中断处理流程

通过如上的中断控制器编程接口框图,当对中断控制器的各组件配置完成后,中断即可被触发,GIC中断的触发和处理流程如下:

中断流程各状态介绍:

generate:外设发起一个中断

distribute:distributor对收到的中断源进行仲裁,然后发送给对应的cpu interface

deliver:cpu interface将中断发送给core

activate:core通过读取 GICC_IAR 寄存器,来对中断进行认可

priority drop: core通过写 GICC_EOIR 寄存器,来实现优先级重置

deactivation:core通过写 GICC_DIR 寄存器,来无效该中断

中断由外设或软件触发以后,distributor和redistributor将根据中断的分组、优先级等配置信息将其分发到特定的cpu interface,并以irq或fiq的方式发送给对应的PE。此时中断处于pending状态,PE上的软件可以通过读取ICC_IAR0_EL1 / ICC_IAR1_EL1寄存器应答该中断,中断被应答后将会变为active状态。中断处理完成后,软件可以写寄存器ICC_EOIR0_EL1 / ICC_EOIR1_EL1以执行中断的优先级下降和deactive操作。中断deactive之后,将会变为inactive状态。

实际上除了上面的情形之外,当中断被应答之后且未处理完成之前,可能还会再次被触发,此时其会处于active and pending状态。

5.2 中断状态机

对于中断各状态之前的切换如下图:

中断各状态的定义如下:

Inactive:中断未被触发,或者已经被cpu处理完成了。无中断状态,即没有Pending也没有Active。

Pending:中断已经被硬件触发或软件产生(SGI),但cpu还没有应答中断。硬件或软件触发了中断,该中断事件已经通过硬件信号通知到GIC,等待GIC分配的那个CPU进行处理,在电平触发模式下,产生中断的同时保持Pending状态。

Active:CPU已经应答(acknowledge)了该中断请求,并且正在处理中。

Active and pending:当一个中断源处于Active状态的时候,同一中断源又触发了中断,进入pending状态。

GICv3中断控制器状态切换过程如下:

当GIC检测到一个中断发生时,会将该中断标记为pending状态(A1)。

对处于pending状态的中断,仲裁单元会确定目标CPU,将中断请求发送到这个CPU上。

对于每个CPU,仲裁单元会从众多pending状态的中断中选择一个优先级最高的中断,发送到目标CPU的CPU Interface模块上。

CPU Interface会决定这个中断是否可以发送给CPU。如果该终端优先级满足要求,GIC会发生一个中断信号给该CPU。

当一个CPU进入中断异常后,会去读取GICC_IAR寄存器来响应该中断(一般是Linux内核的中断处理程序来读寄存器)。寄存器会返回硬件中断号(hardware interrupt ID),对于SGI中断来说是返回源CPU的ID。

当GIC感知到软件读取了该寄存器后,又分为如下情况:

如果该中断源是pending状态,那么状态将变成active。(C)

如果该中断又重新产生,那么pending状态变成active and pending。(D)

如果该中断是active状态,现在变成active and pending。(A2)

当处理器完成中断服务,必须发送一个完成信号EOI(End Of Interrupt)给GIC控制器。软件写GICC_EOIR寄存器,状态变成inactive。(E1)

对于level triggered类型中断来说,当触发电平消失,状态从active and pending变成active。(B2)

常用路径是A1->D->B2->E1。

6,中断寄存器

gicv3中对寄存器提供了2种访问方式,一种是memory-mapped的访问,一种是系统寄存器访问。对于系统寄存器访问方式的gic寄存器,是实现在core内部的。而memory-mapped访问方式的gic寄存器,是在gic内部的。两种方式的访问对应的寄存器如下:

memory-mapped访问的寄存器:

GICC: CPU interface寄存器

GICD: distributor寄存器

GICH: virtual interface控制寄存器,在hypervisor模式访问

GICR: redistributor寄存器

GICV: virtual cpu interface寄存器

GITS: ITS寄存器

系统寄存器访问的寄存器:

ICC: 物理 CPU interface 系统寄存器

ICV: 虚拟 CPU interface 系统寄存器

ICH: 虚拟 CPU interface 控制系统寄存器

GICv3架构中,没有强制,系统寄存器访问方式的寄存器,是不能通过memory-mapped方式访问的。也就是ICC, ICV, ICH寄存器,也是可以实现在GIC内部,通过memory-mapped方式去访问。那么为什么还提供了系统寄存器访问方式?

在GICv3中,将CPU interface从GIC中抽离出来,实现在core内部,而不实现在GIC中。core对CPU interface的访问,通过系统寄存器方式访问,也就是使用msr,mrs访问,那么core对cpu interface的寄存器访问,就加速了,而且还不占用axi总线带宽。这样core对中断的处理,就加速了。CPU interface与gic之间,是通过专用的AXI-stream总线,来传输信息的,这样也不会占用AXI总线的带宽。

GICv3可被分为几个不同的组件,且每个组件都会支持一个或多个编程接口,这些接口又可分为内存映射型寄存器接口和系统寄存器接口两类。其中Distributor、Redistributor和ITS为内存映射型寄存器接口,而CPU interface则是系统寄存器接口。在GICv3中不同组件的寄存器都以特定的前缀命名,各组件的寄存器命名可参考下图:

看到一篇很不错的介绍GICv3寄存器的文章,接下来的6、7、8三节基本来自这篇文章:《一文看懂GICv3》。

6.1 Distributor组件寄存器

Distributor的功能上面已经有过介绍,总结下来主要包含如下功能:

通过GICD_*寄存器,对中断控制器的一些全局属性以及SPI类型中断的属性进行配置。

中断触发时根据寄存器设定的中断分组、优先级以及亲和性等配置,将SPI和SGI中断路由到特定的redistributor和CPU interface上。

接下来分别描述Distributor的重要中断属性寄存器设置。

6.1.1 中断使能配置

GICv3可以设置特定SPI中断号对应的中断是否被使能,若未设置使能状态则该中断不会被发送到CPU interface。中断的使能可以通过GICD_ISENABLER寄存器设置(n为0 - 31),中断的失能可以使用GICD_ICENABLER寄存器设置,这两个寄存器都为32 bit寄存器,每个中断使用一个bit控制其使能、失能状态。

SPI中断使能寄存器的定义:

SPI中断失能寄存器的定义:

6.1.2 中断触发方式配置

中断的触发方式可分为边沿触发(上升沿、下降沿)和电平触发(高电平、低电平),两种触发方式的行为有所不同。

SPI的中断触发方式可用GICD_ICFGR寄存器设置(n为0 - 63),它是一个32bit寄存器,用两个bit表示一个中断的触发方式,每两bit的低bit属于保留位,高bit为0表示电平触发,为1表示边沿触发。比如bit0为保留位,bit1为0表示电平触发,为1表示边沿触发。相应的寄存器定义如下:

6.1.3 中断优先级配置

GICv3的中断优先级可用一个8bit的值表示,因此最多可包含256个优先级,实际的优先级数目要看具体的实现,含有两个security状态的系统最少需要32个中断优先级,含有一个security状态的系统最少需要16个中断优先级。GICv3的中断优先级值越小,则优先级越高。中断优先级的取值范围如下图:

在smp系统中每个PE可以支持不同的优先级bit,其可以通过ICC_CTLR_EL1.PRI bits和ICC_CTLR_EL3.PRI bits获取。

GICv3会确保unmasked且已使能的最高优先级pending中断会被发送给目标PE,但若有多个相同优先级的中断处于pending状态,则哪个中断被发送是由具体实现确定的。

GICv3还可以将中断优先级分组,以将其分为组优先级和子优先级。当组优先级相等的中断正在处理时,即使有子优先级更高的中断被触发也不会发生中断抢占。若多个组优先级相等的中断都处于待处理的pending状态,则子优先级更高的中断会被优先处理。寄存器ICC_BPR0_EL1、ICC_BPR1_EL1用于设置优先级分组。

GICv3中断优先级可以通过GICD_IPRIORITYR寄存器设置(n为0 - 254),它是一个32bit的寄存器,其定义如下:

当前active中断的优先级可通过ICC_RPR_EL1 、ICC_AP0R_EL1(group 0)或ICC_AP1R_EL1(group 1)寄存器读取,ICC_RPR_EL1寄存器的定义如下:

该寄存器返回的优先级为当前PE上处于active状态中断的组优先级。

ICC_AP0R_EL1寄存器定的义如下:

6.1.4 中断亲和性配置

SPI类型中断使用affinity值和路由模式信息来配置中断的亲和性,ARMv8中affinity层次结构可被配置为4个或3个affinity等级,对于每个PE可通过读MPIDR寄存器获取其对应的affinity值。

SPI的中断亲和性可通过GICD_CTLR的ARE_S、ARE_NS和GICD_IROUTER寄存器配置,其中GICD_CTLR的ARE_S、ARE_NS分别用于使能secure和non secure状态下亲和性路由功能。

GICD_CTLR寄存器的定义如下:

在相应位使能后,实际的中断路由模式由以下GICD_IROUTER寄存器设置(n为32 - 1019):

其中bit 31用于设置中断路由模式,其取值如下:

0:该中断被路由到aff0 – aff3指定的PE上。

1:该中断可被路由到partition node上的任意PE上。

6.1.5 中断分组配置

为了支持ARMv8异常模型和security模型的中断处理,GICv3引入了中断分组机制。

SPI中断group可通过GICD_IGROUPR和GICD_IGRPMODR寄存器配置(n为0 - 31),PPI和SGI的中断group可通过GICR_IGROUPR0和GICR_IGRPMODR0寄存器配置。下面以SPI的配置为例,GICD_IGROUPR是32bit寄存器,其与GICD_CTLR.DS(disable secure)配合,每个bit用于控制一个中断的group。其寄存器定义如下:

GICD_IGRPMODR寄存器也是每个bit控制一个中断,且当GICD_CTRL.DS等于0时,其与GICD_IGROUPR共同用于确定一个中断的group类型,其组合方式如下:

GICv3只能将中断以IRQ或FIQ信号的方式转发给CPU,要达到上表所示的不同group中断能被特定异常等级处理,还需要CPU的配合。在ARMv8中SCR_EL3寄存器是用于控制security相关配置的,其各bit的定义如下图:

其中IRQ和FIQ用于配置中断触发时会被路由到CPU的哪个异常等级和security状态,它们的定义如下:

若将FIQ位配置为0,且当前执行状态低于EL3时,则FIQ不会被路由到EL3,而路由到第一个可以处理该中断的异常等级FEL。

若将FIQ配置为1,则运行于任何执行状态时,FIQ都会被路由到EL3。

而IRQ的配置方式与FIQ类似。综合上面分析,结合GIC和CPU的配置,ARMv8的中断将有以下几种路由方式:

secure EL1中断

(1)当前执行在secure EL1,则触发方式为IRQ

由于secure EL1中断需要在secure EL1中处理,故只要将SCR.IRQ设置为0即可将它路由到FEL。

(2)当前执行在non secure EL1,则触发方式为FIQ

同样,由于它需要被secure EL1处理,而EL3具有中断转发功能,因此可以将中断先路由到EL3,然后由EL3转发给secure EL1。故可以将SCR.FIQ设置为1。

(3)当前执行在EL3,则触发方式为FIQ

此时,FIQ需要被设置为1,中断被路由到EL3,然后转发给secure EL1。

non secure EL1中断

(1)当前执行在secure EL1,则触发方式为FIQ

由于中断希望被non secure EL1处理,因此中断可以先路由到EL3,然后转发到non secure EL1。因此SCR.FIQ设置为1。

(2)当前执行在non secure EL1,则触发方式为IRQ

此时,中断被当前EL处理即可,故SCR.IRQ需设置为0。

(3)当前执行在EL3,则触发方式为FIQ

此时,FIQ需要被设置为1,中断被路由到EL3,然后转发给non secure EL1。

EL3中断

(1)当前执行在secure EL1,则触发方式为FIQ

将SCR.FIQ设置为1,以使中断路由到EL3。

(2)当前执行在non secure EL1,则触发方式为FIQ

将SCR.FIQ设置为1,以使中断路由到EL3。

(3)当前执行在EL3,则触发方式为FIQ

将SCR.FIQ设置为1,以使中断路由到EL3。

根据上面的几种情况,即可知道异常等级切换时只要将SCR.FIQ和SCR.IRQ值按下表设置,即可正确地配置中断路由关系:

6.1.6 中断控制器的security支持

ARMv8支持四个异常等级和两种security状态。GICv3各中断分组可以独立控制是否使能,也可以控制non secure状态下是否可以访问group 0中断的寄存器。它是通过GICD_CTLR寄存器控制的,其寄存器定义如下:

其中EnableGrp0、EnableGrp1NS和EnableGrp1S分别用于控制group0、non secure group1和secure group1中断的使能。DS用于控制non secure状态是否能访问group0中断的寄存器,以及中断是否能支持两个secure状态,当DS值为0时GICv3支持两个security状态以及三个中断group,当DS值为0时GICv3只支持一个security状态以及最多两个中断group。

6.1.7 中断状态控制

GICv3支持通过软件控制中断的状态,如将某个中断设置为pending状态、active状态或清除其pending、active状态。它可以通过配置以下几个寄存器实现:

6.2 Redistributor组件

Redistributor位于Distributor和CPU interface之间,前面也对它的功能做了讲述,它主要包含如下两部分功能:

作为编程接口可以通过GICR寄存器,对PPI和SGI类型中断的属性进行配置,以设定其中断触发类型、中断使能以及中断优先级等配置。同时,其还包含了电源管理、LPI中断管理功能。

将最高优先级的pending中断发送到其对应的CPU interface上。

与SPI中断属性在distributor中不同,PPI和SGI的中断属性设置位于redistributor中。如中断使能、优先级、触发方式、分组一种中断状态转换等,由于这些设置除了寄存器不同之外,与SPI的设置方式类似,因此这部分寄存器只选取少部分做示例说明。

6.2.1 最高优先级pending中断发生改变的条件

(1)先前的最高优先级中断已经被应答。

(2)先前的最高优先级中断被更高优先级中断抢占。

(3)先前最高优先级中断被移除。

(4)中断使能状态被修改。

(5)该PE不再处理中断,如进入睡眠状态等。

6.2.2 PPI和SGI的中断使能配置

PPI和SGI中断的使能可以通过GICR_ISENABLER0寄存器设置,中断的失能可以使用GICR_ICENABLER0寄存器设置,这两个寄存器都为32 bit寄存器,每个中断使用一个bit控制其使能/失能状态。其寄存器定义如下:

6.2.3 PPI和SGI的中断优先级配置

PPI和SGI的中断优先级可通过GICR_IPRIORITYR设置(n为0 - 7),其寄存器定义如下:

6.2.4 LPI管理功能

由于LPI支持的中断数量较多,若这些中断的配置寄存器都使用GIC内部寄存器则需要的寄存器空间很大,因此GICv3通过将其配置信息保存在内存的方式,以节约寄存器空间使用。这些表包括LPI配置表、LPI pending状态表、虚拟LPI配置表和虚拟LPI状态表。在GIC初始化时需要为这些配置表分配内存,并将内存基地址设置到相应寄存器,从而将该段内存的管理转交给GICv3。其寄存器定义分别如下:

以上定义中物理地址需要执行一定的对齐操作,其它的bit会被用于定义一些该段内存属性信息,如cache,share的属性等。

除了设置配置表基地址外,Redistributor还实现了改变LPI中断状态的寄存器,如设置LPI pending状态和清除LPI pending状态寄存器,其定义如下:

6.2.5 电源管理功能

在GICv3中CPU interface和PE必须位于同一个power domain,而redistributor不需要跟它们处于同一个power domain。因此,在CPU interface和PE电源关闭且GIC处于上电的情况下(distributor、redistributor、ITS),则GIC需要维护与该PE之间接口的状态。它可以通过如下流程完成:

(1)在CPU和PE下电之前,软件需要将redistributor和cpu interface之间的接口设置为静默(quiescent)模式。它可以通过将GICR_WAKER.ProcessorSleep设置为1实现。并且轮询GICR_WAKER.ChildrenAsleep的状态,当该值也被设置为1时设置完成。

(2)在CPU和PE上电之后,软件需要将GICR_WAKER.ProcessorSleep设置为0,且轮询GICR_WAKER.ChildrenAsleep的状态,直到该值为0时退出静默模式。

相应的寄存器定义如下:

6.3 CPU interface组件

CPU interface可用于物理中断、虚拟中断处理,以及可为hypervisor提供虚拟机控制接口。包括SGI中断产生、PPI、SGI的优先级设置,最高pending优先级读取以及应答、deactivate、完成操作执行等。

6.3.1 中断使能配置

CPU interface可以使能或关闭某一group中断,在CPU interface中一共有三个寄存器用于配置中断的使能:

(1) ICC_IGRPEN0_EL1:它用于控制是否使能group 0中断

(2)ICC_IGRPEN1_EL3:它用于控制group 1中断的使能,其中bit 0用于控制non secure group 0的使能,bit 1用于控制secure group 1的使能

(3)ICC_IGRPEN1_EL1:它用于控制当前secure状态下group 1中断使能。该寄存器其实只是ICC_IGRPEN1_EL3寄存器的别名,即在non secure状态下其与ICC_IGRPEN1_EL3的bit 0等价,在secure状态下其与ICC_IGRPEN1_EL3的bit 1等价。

6.3.2 中断的状态转换

中断的状态转换包括中断应答、中断deactivate以及中断完成操作。其中中断应答通过读取ICC_IAR0_EL1(group 0)和ICC_IAR1_EL1(group 1)寄存器完成,寄存器定义如下:

中断的deactivate可通过向寄存器ICC_DIR_EL1写入中断ID完成。其寄存器定义如下:

只有当前异常等级和security状态下的EOI mode为1时,才需要执行deactivate操作。否则只要执行完成操作即可。中断完成操作通过向寄存器ICC_EOIR0_EL1(group 0)或ICC_EOIR1_EL1(group 1)写入中断ID实现,该操作之后CPU将又可以响应新的中断。

6.3.3 最高优先级pending中断获取

当前PE上最高优先级pending中断可分别通过读取ICC_HPPIR0和ICC_HPPIR1寄存器获取。其中ICC_HPPIR0的寄存器定义如下:

6.3.4 SGI中断产生

SGI是由软件通过写CPU interface寄存器触发的,其需要设置的内容包括中断号,中断需要被发送的目的PE。根据不同的security状态和中断group其可分别通过ICC_SGI0R_EL1、ICC_SGI1R_EL1和 ICC_ASGI1R_EL1寄存器产生,其对应关系如下表:

这三个寄存器的定义类似,以ICC_SGI0R_EL1为例其定义如下:

  其中IRM指定中断路由模型,当其为0时中断被路由到affinity指定的PE list上,否则会被发送给系统中除自身之外的其他PE。TargetList指定中断将要被发送的PE组,它与aff0的定义相匹配。

6.4 ITS组件

ITS的作用是将一个来自device的输入eventID转换为LPI中断号,并确定该中断将被发送的目的PE。它通过device table、interrupt translate table、collection table和vPE table这几张转换表,实现中断号的转换。这些表的关系如下图:

6.4.1 Device table

Device table提供了一组device table entry(DTE),其中每个DTE为指向特定deviceID相关的中断转换表(ITT)基地址。其转换关系如下:

6.4.2 中断转换表

每个连接到ITS上且含有多个event的设备,都拥有一张ITT表。对于物理中断和虚拟中断ITE分别提供了两种类型的映射,对于物理中断其映射关系如下:

(1)eventID到中断ID的映射。

(2)eventID到ICID的映射,其中ICID又指向collection表。

对于虚拟中断其映射关系如下:

(1)eventID到虚拟中断ID的映射。

(2)eventID到vPE表的映射,vPE表包含了虚拟PE number(vPEID)。

6.4.3 Collection表

Collection表提供了ICID到目的redistributor寄存器基地址的映射。对于每个ITS只有一个collection表,它可被保存在寄存器或内存中。CT entry的定义如下:

6.4.4 vPE表

vPE表提供了vPEID到目的redistributor和虚拟LPI pending表基地址之间的映射。它提供了ITS中所有相关vPE的信息,其定义如下:

6.4.5 ITS命令接口

ITS使用命令队列的方式处理相关命令,命令队列的结构如下图:

如图所示它是通过三个寄存器GITS_CBASER、GITS_CREADR和GITS_CWRITER控制队列运行的。其中寄存器GITS_CBASER用于指定ITS命令队列基地址的物理地址,寄存器GITS_CWRITER由软件控制用于向命令队列中断写入ITS命令,GITS_CREADR由ITS控制读取并处理队列中的命令。该队列是循环缓冲区,因此当读写指针达到队列尾后可回绕回队列头继续执行相应操作。

7,虚拟中断处理

GICv3提供了对虚拟化的支持,在虚拟化环境中虚拟机可以支持以下特性:

(1)vPE可以被配置为接收虚拟group 0中断和虚拟group 1中断。

(2)虚拟group 0中断使用vFIQ信号发送给non secure 1的vPE。

(3)虚拟group 1中断使用vIRQ信号发送给non secure 1的vPE。

(4)vPE可以像处理物理中断一样处理虚拟中断。

中断虚拟化需要GICv3和hypervisor上的软件共同配合。支持虚拟化之后,EL3或EL2将物理中断配置为路由到EL2,EL2上的hypervisor捕获到中断以后根据中断的类型,分别执行不同的处理。这些中断包含以下两类:

(1)本身就发送给hypervisor的中断。这类中断如由系统产生的中断、或维护虚拟机的中断。它们由虚拟机按照普通的物理中断处理即可。

(2)需要被发送给vPE的中断。虚拟机接收到这种类型中断后,若接收中断的vPE正在运行,则会通过GICv3将其按照虚拟中断的方式注入到特定vPE的list register中。否则虚拟机将中断信息暂存到内存中,并在合适的时机执行实际的虚拟中断注入。虚拟中断注入包括将特定vPE的虚拟中断ID设置为pending状态,并设置与其相关的物理中断信息

7.1 虚拟中断的注入和处理

虚拟中断注入后,GICv3将会选择list register中最高优先级的pending虚拟中断,并以vIRQ或vFIQ的形式发送给vPE,此后vPE就可以将其使用与物理中断相同的方式处理,包括应答中断、优先级降低以及deactivate操作等。若虚拟中断与物理中断关联,则当其处理完成后,相应的物理中断也会被deactivate。

由于list register的数量有限,为了确保vPE接收到的是最高优先级的pending中断。虚拟机需要为每个vPE维护一个pending中断优先级列表,并且其优先级最高的一组pending中断会被注入到list register中。若pending中断超过list register的数量,虚拟机将剩余的pending中断信息保存在内存中,并在此后按优先级顺序恢复注入到list register中。List register相当于所有active、pending中断的cache。

7.2 虚拟中断类型

Hypervisor的虚拟机维护中断包含以下几种类型:

(1)当list register中不含有pending中断时,发出中断信号以允许hypervisor向其load pending中断。或当list寄存器为空或将为空时,发出中断以允许hypervisor向其load保存在内存中的pending中断。

(2)当接收到一个不再list register中的中断的EOI命令时(该中断信息可能被保存在内存中),向hypervisor发出中断。

(3)enable和disable虚拟中断group,需要向hypervisor发送中断以可能需要改变list register的内容。

由于list register保存了部分vPE的上下文,因此当虚拟机将一个vPE切换为另一个vPE时,也需要切换相应list register的内容。

7.3 虚拟中断与物理中断的关联

Hypervisor可以向vPE注入两种类型的中断:

(1)与物理中断关联的虚拟中断,如某一个由特定VM拥有的外设中断。

(2)由hypervisor通过软件产生,而与物理中断无关的虚拟中断,如hypervisor用于模拟虚拟外设的中断。

为了支持以上两种模式,GIC list register支持与物理中断关联的虚拟中断。

(1)hypervisor配置ICC_CTRL_EL1.EOImode = 1。

(2)当vPE相关的物理中断被发送到PE时,由hypervisor接收并应答,此时物理中断处于active状态。

(3)hypervisor将虚拟中断插入目的vPE的pending中断列表。若hypervisor希望执行该中断的优先级下降,则执行一个EOI操作,但不要deactivate该中断。

(4)当该虚拟中断能够被vPE处理时,hypervisor将该pending中断写到LR寄存器中,并且将ICH_LR_EL2.HW设置为1,以表示该虚拟中断是与物理中断关联的。此时,与其关联的物理中断ID也会被保存在相同的list register中。

(5)vPE运行并处理该虚拟中断,当vPE处理完成该中断后,deactivate虚拟中断后,物理中断也会被deactivate。

8,LPI中断处理

LPI是基于消息的中断,它可以有两种触发方式:

(1)使用ITS将device ID和event ID转换为LPI的中断ID。

(2)通过写GICR_SETLPIR寄存器直接将LPI中断号转发到redistributor上。

下面分别是包含ITS和不包含ITS的LPI系统架构图:

若一个redistributor含有对LPI的支持,则其需要包含以下两张LPI中断信息表:

(1) LPI配置表:该表用于配置LPI中断的优先级和使能位。它由redistributor的GICR_PROPBASER寄存器指定。其每个中断号在表中的定义如下:

(2) LPI pending表:该表用于指示LPI中断的pending中断号。它由redistributor的GICR_PENDBASER寄存器指定。

这两张表的size取决于系统支持的LPI中断数量,它由GICR_PROPBASER.IDBits域指定。

GICv3提供了对虚拟LPI的支持,其也提供了两张类似的表GICR_VPROPBASER和GICR_VPENDBASER,以支持虚拟LPI中断的配置和pending状态管理。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20230326A04OTG00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券