赞
踩
本文介绍了 Arm 通用中断控制器(GIC)v3和v4的功能,描述了 GICv3 中断控制器的相关操作,同时也介绍了如何在裸机环境中配置GICv3 中断控制器。
本文是 Arm 通用中断控制器相关指南中的第一篇:
中断是向处理器发出信号,表明发生了需要处理的事件,中断通常由外设产生。
例如,系统可能使用通用异步接收器/发送器 (UART) 接口与外界通信。当UART接收数据时,它需要一种机制来告诉处理器新数据已经到达。UART 可以使用的一种机制是生成中断,向处理器发出信号。
小型系统可能只有几个中断源和一个处理器。然而,大型系统可能有更多的中断源和处理器。GIC 执行中断管理、优先级和路由等关键任务。 GIC 管理来自整个系统的所有中断,确定优先级,并将它们发送到内核进行处理。GIC 主要用于提高处理器效率并开启中断虚拟化。
GIC 是基于Arm GIC 架构实现的。该架构已经从 GICv1 发展到最新版本 GICv3 和 GICv4。 Arm 拥有多个通用中断控制器,可为所有 Arm Cortex 多核处理器系统提供一系列中断管理解决方案,如用于小型CPU系统的 GIC‑400,用于高性能多芯片系统的 GIC‑600。 GIC‑600AE 额外添加了功能安全特性,针对高性能 ASIL B 至 ASIL D 系统。
在本指南的最后,您可以检查您的知识。您将了解不同类型的中断,能启用 GIC 并配置不同的中断类型。
本指南涵盖了 GICv3 和 v4 的基本操作,Shared Peripheral Interrupt(SPIs)、Private Peripheral Interrupt (PPIs) 和Software Generated Interrupt (SGIs)的使用。
本指南是Arm Generic Interrupt Controller Architecture Specification GIC architecture version 3.0 and 4.0的补充。有关寄存器和行为的详细说明,请参阅 Arm 通用中断控制器架构规范 GIC 架构 3.0 和 4.0 版本。
GICv3 和 GICv4 允许多种不同的配置和用例。为简单起见,本指南重点介绍以下场景的配置和用例:
本文并未覆盖:
本文假定您熟悉 Arm 异常模型。如果您想了解 Arm 异常模型,可以阅读Learn the Architecture: Exception model guide。
通用中断控制器 (GIC) 从外设获取中断,确定优先级,然后将它们送入到处理器内核。下图展示了 GIC 从 n 个不同的外设源获取中断,并将它们分配给两个不同的处理器。
GIC 是针对 Arm Cortex‑A 和 Arm Cortex‑R 系列处理器的标准中断控制器。GIC 提供了一种灵活且可扩展的中断管理方法,支持单核系统到具有数百个核的大型多芯片设计。
与 Arm 架构一样,GIC 架构也随着时间的推移而发展。下表总结了 GIC 规范的主要版本以及常运用的处理器。
GIC版本 | 关键特性 | 典型运用 |
---|---|---|
GICv1 | 最多支持8个PE | Arm Corte-A5 MPCore、Arm Corte-A9 MPCore、Arm Corte-R4、Arm Corte-R5 MPCore、Arm Corte-R7 MPCore、Arm Corte-R8 MPCore |
GICv2 | GICv1的所有功能、支持虚拟化 | Arm Corte-A7 MPCore、Arm Corte-A15 MPCore、Arm Corte-A17 MPCore |
GICv3 | GICv2的所有功能、支持8个以上PE、支持消息信号中断、支持超过1020个中断ID、系统寄存器可访问到CPU内部寄存器、一种增强的安全模型,将安全和非安全组中断隔离开 | Arm Corte-A3x MPCore、Arm Corte-A5x MPCore、Arm Corte-A7x MPCore |
GICv4 | GICv3的所有功能、直接注入虚拟中断 | Arm Corte-A3x MPCore、Arm Corte-A5x MPCore、Arm Corte-A7x MPCore |
本文涵盖了Arm CoreLink GICv3和GICv4,这些运用在大多数Armv-9A、Armv8-A及Armv8-R设计中。
GICv3和GICv4自发布以来,也进行了一些更新:
在本节中,我们将了解 Arm GICv3 和 v4 中断控制器的基本操作。
GIC 可以处理四种不同类型的中断源:
每个中断源由一个 ID 号标识,称为 INTID。前面介绍的中断类型是根据INTIDs的范围定义的:
INTID | 中断类型 | 注意 |
---|---|---|
0-15 | SGIs | 每个PE Banked |
16-31、1056-1119(GICv3.1) | PPIs | 每个PE Banked |
32-1019、4096-5119(GICv3.1) | SPIs | - |
1020-1023 | 特殊中断号 | 用于特殊情况,参考Setting for each PE章节 |
1024-8191 | 保留 | - |
8192及以上 | LPIs | 上限由实现定义 |
中断通常是从外设向中断控制器发送专用硬件信号,如下:
Arm CoreLink GICv3 支持此模型,但还提供了额外的信号机制:消息信号中断 (MSI)。 MSI 的传递是通过写中断控制器的寄存器实现,如下所示:
使用消息将中断从外设转发到中断控制器,无需为每个中断源提供专用信号。这对于大型系统的设计人员来说是一个优势,因为在大型系统中,可能有数百甚至数千个信号在 SoC 上路由并汇聚到中断控制器上。
中断是作为消息发送还是使用专用信号对中断处理影响不大,可能需要对外设进行一些配置。例如,可能需要指定中断控制器的地址,这些已经超出本文的范围。
在 Arm CoreLink GICv3 中,SPI 可以是消息信号中断,而LPI 始终是消息信号中断。不同的中断类型使用不同的寄存器,如下表所示:
中断类型 | 寄存器 |
---|---|
SPI | GICD_SETSPI_NSR |
LPI | GITS_TRANSLATER |
对于每一个SPI,PPI和SGI中断源,中断控制器维护了一个状态机,由四个状态组成:
中断状态机如下图所示。
中断的生命周期取决于其配置的是电平触发还是边沿触发:
下图展示了中断状态转换与中断信号间的对应关系:
Inactive to pending:当中断发生时,中断从非活跃状态转换为挂起状态。此时,如果中断使能并且优先级较高,GIC会向PE发出中断信号。
Pending to active and pending:当PE读取CPU接口中的中断应答寄存器(IARs)后,中断从挂起状态转化为活跃及挂起状态。这个读取动作是中断处理程序的一部分,然后GIC取消向PE发出中断信号。
Active and pending to active:当外设取消置位中断信号时,中断将从活跃及挂起状态转换为活跃状态。这通常发生在软件写入外设的状态寄存器时。
Active to inactive:当 PE 写入 CPU 接口的 End of Interrupt Registers (EOIRs) 时,中断从活跃状态变为非活跃状态,这表明PE已经完成了中断处理。
下图展示了中断状态转换与中断信号间的对应关系:
Inactive to pending:当中断发生时,中断从非活跃状态转换为挂起状态。此时,如果中断使能并且优先级较高,GIC会向PE发出中断信号。
Pending to active:当PE读取CPU接口中的中断应答寄存器(IARs)后,中断从挂起状态转化为活跃状态。这个读取动作是中断处理程序的一部分,然而软件也可以轮训IARs。然后GIC取消向PE发出中断信号。
Active to active and pending:当外设又发出中断信号时,中断将从活跃状态转换为活跃及挂起状态。
Active and pending to pending:当 PE 写入 CPU 接口的 End of Interrupt Registers (EOIRs) 时,中断从活跃及挂起状态变为挂起状态,这表明PE已经完成了第一个中断实例的处理。此时GIC重新向PE发出中断信号。
Arm架构为每个PE分配了一个分层标识符,称为affinity(亲和性)。GIC使用affinity值将中断路由到相应的core。
affinity 是一个32位值,分为4个字段:
<affinity level 3>.<affinity level 2>.<affinity level 1>.<affinity level 0>
每个PE的affnity值可以通过MPDIR_EL1
寄存器获取(Affinity值表示一个中断被分配给哪个处理器核心)。
不同等级的affinity含义是由处理器和SoC定义的。例如,Arm Cortex-A53 和 Arm Cortex-A57 使用
<group of groups>.<group of processors>.<processor>.<core>
后来的设计(例如 Arm Cortex‑A55 和 Arm Cortex‑A76 处理器中使用的设计)使用:
<group of processors>.<processor>.<core>.<thread>
所有的节点不太可能存在单个实现中。例如,移动设备的 SoC 布局如下:
0.0.0.[0:3] Cores 0 to 3 of a Cortex-A53 processor
0.0.1.[0:1] Cores 0 to 1 of a Cortex-A57 processor
affinity level 0:表示一个core中的第几个thread,大多数是sigle-threaded,因此该值为0。
affinity level 1:表示一个cluster中的第几个core。
affinity level 2/3:表示系统中第几个cluster。
Arm GICv3 架构支持 Arm TrustZone 技术。软件为每个 INTID 分配一个组和安全设置。GICv3 支持三种设置组合,如下:
中断类型 | 使用示例 |
---|---|
Secure Group 0 | EL3中断(Secure Firmware) |
Secure Group 1 | Secure EL1中断(Trusted OS) |
Non-secure Group 1 | No-secure状态中断(OS或Hypervisor) |
Group 0 中断始终以 FIQ 形式发出信号,而 Group 1 中断以 IRQ 或 FIQ 形式,这取决于 PE 当前的安全状态和异常等级,如下:
PE的异常等级和安全状态 | Group 0 | Group 1 | Group 1 |
---|---|---|---|
Secure | Non-Secure | ||
Secure EL0/1 | FIQ | IRQ | FIQ |
Non-secure EL0/1/2 | FIQ | FIQ | IRQ |
EL3 | FIQ | FIQ | FIQ |
这些规则旨在补充 AArch64 安全状态和异常等级路由控制。下图是一个简单的软件栈,在EL0执行时,当触发不同的中断类型,会发生什么:
上图 IRQ 路由到 EL1(SCR_EL3.IRQ=0
),FIQ 路由到 EL3(SCR_EL3.FIQ=1
)。考虑上述规则,在EL0或者EL1执行时,安全状态下的 Group 1 中断被视为 IRQ。
举例说明:当PE在 Secure EL0/1 (图右)下执行时,来了一个 Secure Group 1 中断,将发出 IRQ 信号;当PE在 Secure EL0/1 (图右)下执行时,来了一个 Non-secure Group 1 中断,将发出 FIQ 信号;当PE在 Non-secure EL0/1/2 (图左)下执行时,来了一个 Secure Group 1 中断,将发出 FIQ 信号;当PE在 Non-secure EL0/1/2 (图左)下执行时,来了一个 Non-secure Group 1 中断,将发出 IRQ 信号;而无论PE处于哪个异常等级和安全状态,来了一个 Group 0中断,始终发出 FIQ 信号。
当配置中断控制器时,软件进行 INTID 中断组的分配。软件只有在安全状态下才能进行 INTID 的分配。
通常,软件只有在安全状态下才能访问安全中断状态和配置:Group0 和 Secure Group 1。
也可以使能非安全状态访问安全状态和配置的权限,这是由每个 INTID 单独控制的,使用 GICD_NASACRn
和 GICR_NSACR
寄存器j进行配置。
GICv3 支持 Arm TrustZone 技术,但是否使用 TrustZone 是可选的。这意味着你可以配置是实现一个安全状态还是两个安全状态:
对于连接的所有PE,GIC须配置支持相同数量的安全状态。这意味着,如果连接 Arm Cortex-A系列处理器,GIC 将支持两种安全状态,而连接 Arm Cortex-R系列处理器,将只支持一种安全状态。
GICv3 中断控制器的寄存器接口分为三组:
这些接口如下图所示:
一般来说,Distributor 和 Redistributor 接口用于配置中断,CPU 接口用于处理中断。
Distributor 寄存器是内存映射,用于配置 SPI。Distributor 提供编程接口用于:
每个连接的 Core 都有一个 Redistributor。Redistributor 提供编程接口用于:
每个 Core 都包含一个 CPU 接口,这些接口是在中断处理期间使用的系统寄存器。CPU 接口提供编程接口用于:
在 Arm CoreLink GICv3 中,CPU 接口寄存器像系统寄存器一样进行访问:ICC_*_ELn
。
在使用这些寄存器之前,软件必须使能系统寄存器接口。这是由ICC_SRE_ELn
寄存器中的 SRE 位控制的,其中 n
表示异常等级:EL1-EL3。
本章介绍如何在裸机环境中启用和配置 GICv3 的中断控制器,详细寄存器配置参考Arm Generic Interrupt Controller Architecture Specification GIC architecture version 3.0 and 4。
LPI 与 SPI、PPI 以及 SGI 的配置明显不同,更多信息请参考Locality-specific Peripheral Interrupts。
大多数 GICv3 中断控制器都是用在多核系统,也有可能是多处理器系统。有些设置是全局的,即会影响所有连接的 PE,其他设置是针对单个PE。
Distributor 控制寄存器(GICD_CTLR)必须启用中断组,以及设置路由模型:
EnableGrp1S
:使能 Secure Group 1 中断分发EnableGrp1NS
:使能 Non-secure Group 1 中断分发EnableGrp0
:使能 Group 0 中断分发本节针对单个 Core 或者 PE 的配置。
每个Core都有自己的Redistributor,如下:
Redistributor 包含一个 GICR_WAKER 的寄存器,用于记录连接的 PE 是否在线或离线。中断只转发给 GIC 认为在线的 PE。复位时,所有 PE 均视为离线。
要将连接的 PE 标记为在线,软件必须:
GICR_WAKER.ProcessorsSleep
清零GICR_WAKER.ChildrenASleep
,直至读到0在配置 CPU 接口之前,软件必须执行这些步骤,否则可能工作异常。
当 PE 离线(GICR_WAKER.ProcessorsSleep==1
),中断将触发唤醒请求信号。通常,该信号将发送至系统的电源控制器,然后电源控制器会打开PE。当唤醒后,PE会清零 ProcessorSleep 位,允许转发该中断。
CPU 接口负责向与其连接的 PE 发送中断异常。为了使能CPU接口,软件必须配置:
启用系统寄存器访问
CPU 接口(ICC_*_ELn
)部分描述了 CPU 接口寄存器,以及如何在 GICv3 中如何像系统寄存器一样进行访问。软件必须设置ICC_SRE_ELn
寄存器中的 SRE 位,来启用对 CPU 接口寄存器的访问。
设置 Priority Mask 和 Binary Point 寄存器
CPU 接口包 Priority Mask(ICC_PMR_EL1)和 Binary Point(ICC_BPRn_EL1)。Priority Mask 设置中断必须具有的最低优先级,才能转发到 PE。Binary Point 寄存器用于优先级分组和抢占。下面处理中断章节中更详细地描述了这两个寄存器的使用。
设置 EOI 模式。
CPU 接口ICC_CTLR_EL1
和ICC_CTLR_EL3
中的 EOI 模式位决定如何处理中断完成。下面中断结束章节对此进行了更详细的描述。
使能每个中断组的信号。
在 CPU 接口将每个中断组的中断转发到 PE 之前,必须使能该中断所在的中断组。软件必须配置ICC_IGRPEN1_EL1
寄存器(用于Group 1中断)和ICC_IGRPEN0_EL1寄存器
(用于Group 0中断)。ICC_IGRPEN1_EL1
由安全状态存储,这意味着ICC_GRPEN1_EL1
控制Group 1的安全状态。在 EL3 中,软件可以使用 ICC_IGRPEN1_EL3,同时访问用于Group 1的上述两个寄存器。
PE的一些配置需要允许接收和处理中断,详细说明超出了本文的范围,这里我们只介绍在 AArch64 状态下执行所需的基本步骤。
路由控制
中断的路由控制位于PE 的SCR_EL3
和HCR_EL2
寄存器中。路由控制位决定中断发生的异常等级。在复位时,这些路由控制位是未知值,因此软件必须进行初始化。
中断屏蔽
在PSTATE
寄存器中,PE 有一个异常屏蔽位。当置位时,中断被屏蔽,复位时这些是置位的。
向量表
PE 向量表的位置是由VBAR_ELn
寄存器设置的。与SCR_EL3
和HCR_EL2
寄存器一样,VBAR_ELn
寄存器值复位时也是未知的。软件必须配置VBAR_ELn
寄存器,指向内存中的向量表。
到目前为止,我们介绍了中断控制器本身的配置,现在看一下各个中断源的配置。
使用哪些寄存器来配置中断取决于中断的类型:
GICD_*
寄存器。GICR_*
寄存器。下图说明了这些不同的配置机制:
对于每个 INTID,软件必须配置如下内容:
Priority:GICD_IPRIORITYn,GICR_IPRIORITYn
每个 INTD 都有一个优先级,用8位无符号值表示。0x00 表示最高优先级,0xFF 表示最低优先级。运行优先级和抢占决定了GICD_IPRIORITYn
和GICR_IPRIORITYn
中的优先级值如何屏蔽低优先级中断,如何控制抢占。中断控制器不需要实现所有 8 个优先级位,如果 GIC 支持两种安全状态,中断控制器至少需要实现5位; 如果 GIC 仅支持单个安全状态,则必须至少实现 4 位。
Group:GICD_IGROUPn, GICD_IGRPMODn, GICR_IGROUPn, GICR_IGRPMODn
如安全模型章节中所述,中断可以配置:Group 0、Secure Group 1 和 Non-secure Group 1。
边沿触发或者电平触发:GICD_ICFGRn,GICR_ICFGRn
对于 PPI 和 SPI,软件必须指定中断是边沿触发还是电平触发。 SGI 始终被视为边沿触发,因此GICR_ICFGR0
总是读为1、忽略写(RAO/WI)。
使能:GICD_ISENABLERn, GICD_ICENABLER, GICR_ISENABLERn, GICR_ICENABLERn
每个 INTID 都有一个使能位。Set-enable registers 和 Clear-enable registers 不需要了执行读取‑修改‑写入流程。Arm 建议在启用 INTID 之前按照本节所述进行配置。
不可屏蔽:不可屏蔽中断比同一组的其他中断优先级更高。也就是说,不可屏蔽的 Non-secure Group 1 中断比其他 Non-secure Group 1 中断的优先级高。
对于裸机环境,通常初始配置后无需再修改。然而,如果必须重新配置中断,例如更改组设置,则应先禁用该中断,然后再更改其它配置。
大多数配置寄存器的复位值都是由实现定义的。这意味着中断控制器的设计者决定这些值是什么,并且这些值可能因系统而异。
Arm GICv3.1 添加了对其他 SPI 和 PPI INTID 的支持。配置这些中断的寄存器与原始中断范围相同,只是它们有一个E
后缀。例如:
对于 SPI,可以配置中断的目标。这由 GICv3.1 扩展 SPI 的GICD_IROUTERn
或GICD_IROUTERnE
控制。每个SPI都有一个
GICD_IROUTERn
寄存器,Interrupt_Routing_Mode
位控制路由策略:
GICD_IROUTERn.Interrupt_Routing_Mode == 0
SPI 路由到 PE A.B.C.D,这是寄存器中指定的affinity坐标。
GICD_IROUTERn.Interrupt_Routing_Mode == 1
SPI 可以路由到参与中断组分配的任何 PE。Distributor(而不是软件)选择目标 PE。因此,每次发出中断信号时,目标都会有所不同。这种类型的路由称为 1‑of‑N。
PE 可以选择不接收 1‑of‑N 中断。这是由GICR_CTLR
中的DPG1S
、DPG1NS
和DPG0
位控制的。
本节介绍中断生成时会发生什么,例如:中断如何路由到PE,中断如何确定彼此的优先级,中断结束会发生什么。
上面中断状态机章节介绍了当中断源被置位时,中断如何从非活跃状态转换为挂起状态。当中断变为挂起状态时,中断控制器根据以下检查决定是否将中断发送到连接的 PE 。这些检查确定将中断发送到哪个 PE(如果有):
检查与中断关联的组是否已启用。
上面安全模型章节介绍了如何将 INTID 分配到一个组:Group 0,Secure Group 1,Non-secure Group 1。对于每个组,在 Distributor 和每个 CPU 接口中都有一个 Group 使能位。
中断控制器检查是否为该中断所在的组设置了 Group 使能位。
如果所在的组被禁用了,中断将无法发送到 PE。这些中断将保持挂起状态,直到该组被启用为止。
检查中断是否使能。
如果未使能,中断将挂起,不会转发到PE。
检查路由控制,决定哪些 PE 可以接收中断。
哪些 PE 可以接收中断取决于中断的类型:
GICD_IROUTERn
控制。SPI 可以针对一个特定的 PE,或任何一个连接的 PE。检查中断优先级和优先级屏蔽,决定哪些 PE 适合处理中断。
每个 PE 在 CPU接口中都有一个优先级屏蔽(Priority Mask)寄存器 ICC_PMR_EL1
。该寄存器设置将中断转发到该 PE 所需的最低优先级。只有优先级高于 mask 的中断才会发送给该 PE。
检查运行优先级,决定哪些 PE 可以处理中断。
下面 Running priority and preemption 介绍了运行优先级,以及这些如何影响抢占。如果PE尚未处理中断,则运行优先级为空闲优先级:0xFF。只有优先级高于运行优先级的中断才能抢占当前中断。
如果中断通过了这些检查,它将作为 IRQ 或 FIQ 异常转发到相应的Core。
当进入异常处理程序时,软件不知道它获取的是哪个中断。处理程序必须读取中断应答寄存器 (IAR) ,获取中断的 INTID。有两个 IAR:
寄存器 | 用途 |
---|---|
ICC_IAR0_EL1 | 用于确定 Group 0中断,通常在 FIQ 处理程序中读取 |
ICC_IAR1_EL1 | 用于确定 Group 1中断,通常在 IRQ 处理程序中读取 |
ICC_NMIAR1_EL1 | 用于确定不可屏蔽中断(仅限GICv3.3) |
读取 IAR 得到 INTID,进入中断的状态机。通常,IAR 在进入中断处理程序时被读取。然而,软件可以随时读取该寄存器。
有时,IAR 无法返回有效的 INTID。例如,软件读取ICC_IAR0_EL1,确认 Group 0 中断,但挂起的中断属于 Group 1。在这种情况下,读取返回的一个保留值 INTID,如下表所示:
ID | 含义 | 示例场景 |
---|---|---|
1020 | 仅读取ICC_IAR0_EL1返回、挂起的最高优先级中断是 Secure Group 1、仅在EL3出现。 | 当 PE 在非安全状态下执行时,Trusted OS 收到中断信号。这被视为 EL3 的 FIQ,以便 Secure Monitor可切换到Trusted OS。 |
1021 | 仅读取ICC_IAR0_EL1返回、挂起的最高优先级中断是 Non-secure Group 1、仅在EL3出现。 | 当 PE 在安全状态下执行时,Rich OS 收到中断信号。这被视为 EL3 的 FIQ,以便 Secure Monitor可切换到Rich OS。 |
1022 | 读取ICC_IAR1_EL1返回、挂起的最高优先级中断是 Non-secure Group 1、不可屏蔽属性。 | 不可屏蔽中断使用其它寄存器进行确认。 |
1023 | 虚假中断、没有启用的 INTID 处于挂起状态,或者处于挂起状态的所有 INTID 的优先级较低,不足以处理。 | 当轮询 IAR 时,该值表示没有可供确认的中断。 |
如果存在上述情况,读取 IAR 返回的是这些保留值之一,并不确认中断。
下图是一个手机系统示例,收到了电话,触发了 modem 中断。这个中断旨在由非安全状态的 Rich OS 处理。
中断处理的步骤如下:
SCR_EL3.FIQ=1
,异常转移到 EL3。在这个示例中,Non-secure Group 1中断导致 PE 立即从 Secure OS 退出。这可能并不是我们想要的结果,下面是一个替代路由方案,中断传入 Secure EL1:
中断处理的步骤如下:
SCR_EL3.FIQ=0
,异常转移到 Secure EL1。优先级屏蔽寄存器设置中断转发到PE的最低优先级,GICv3 架构也有运行优先级的概念。当 PE 接收一个中断时,其运行优先级也就变为与该中断优先级相同。当 PE 写入中断结束(EOI)寄存器时,运行优先级变为之前的值。下图展示了运行优先级随时间变化的过程:
当前运行优先级可以在 CPU 接口中的 Running Priority 寄存器中查看:ICC_RPR_EL1
。
在考虑抢占时,运行优先级的概念是很重要的。当 PE 正在处理较低优先级中断,又触发了高优先级中断信号时,就会
发生抢占。抢占使软件处理变得复杂,但可以防止低优先级中断阻塞较高优先级中断的处理。
下图展示了如果不允许抢占会发生什么:
高优先级中断将被挂起,直到先前低优先级中断处理完成。 接下来看下允许抢占的情况:
当较高优先级中断变为挂起状态时,它会抢占先前的低优先级中断。上图是一级抢占,然而可能存在多级抢占。
通过配置优先级的不同,Arm CoreLink GICv3 架构允许软件控制抢占发生。这是通过 Binary Point 寄存器实现的:ICC_BPRn_EL1
。
Binary Point 寄存器将优先级划分为两个字段:组优先级和子优先级。
对于抢占,只考虑组优先级,忽略子优先级。例如,考虑一下三个中断:
我们想达到如下目的:
为了实现这一点,组优先级和子优先级之间的划分可以设置为 N=4,如下所示:
通过这种拆分,B 和 C 现在具有相同的组优先级。而 A 仍然具有更高的组优先级,这意味着它可以抢占 B 或 C。
Binary Point 寄存器仅影响抢占,即当正在处理一个中断时,另外一个中断是否触发处理。在选择挂起的中断时,不使用 Binary Point 寄存器。
一旦中断处理完成,软件必须通知中断控制器中断,以便状态机可以切换到下一个状态。Arm CoreLink GICv3 架构将此视为两个任务:
在 GICv3 架构中,优先级下降和停用可以一起发生,也可以单独发生。这是由ICC_CTLR_ELn.EOImode
的配置决定的:
ICC_EOIR0_EL1
,对于Group 1 中断写入ICC_EOIR1_EL1
,这些会执行优先级下降和停用。该模式常用于简单的裸机环境。ICC_EOIR0_EL1
,对于Group 1 中断写入ICC_EOIR1_EL1
,这些会执行优先级下降。停用需要单独写入ICC_DIR_EL1
,这通常用于虚拟化。大多数软件都会使用EOIMode==0
。EOImode==1
通常用于虚拟机。
顾名思义,最高优先级挂起中断寄存器ICC_HPPIR0_EL1
和ICC_HPPIR1_EL1
指明 PE 挂起的最高优先级中断 INTID。
运行优先级是在上面介绍的,由运行优先级寄存器(ICC_RPR_EL1)指明 。
Distributor 提供寄存器,指示每个 SPI 的当前状态。类似地,Redistributors 提供寄存器,指示其连接 PE 的 PPI 和 SGI 状态。
这些寄存器还可以将中断移动到特定状态。例如,这对于测试配置是否正确十分有用,而不需要外设去断言中断。
有单独的寄存器来报告活跃状态和挂起状态。下表列出了活跃状态寄存器,挂起状态寄存器具有相同的格式:
寄存器 | 描述 |
---|---|
GICD_ISACTIVERn | 设置SPI的活动状态,每个INTID一个位 读取一位会返回中断的当前状态: - 1:INTID处于活动状态 - 0:INITID处于非活动状态 写 1 激活相应的INTID,写 0 无影响 |
GICD_ICACTIVERn | 清除SPI的活动状态,每个INTID一个位 读取一位会返回中断的当前状态: - 1:INTID处于活动状态 - 0:INITID处于非活动状态 写 1 激活相应的INTID,写 0 无影响 |
GICR_ISACTIVERn | 设置SGI和PPI的活动状态,每个INTID一个位,该寄存器涵盖INTID是0到31,是每个PE私有的 读取一位会返回中断的当前状态: - 1:INTID处于活动状态 - 0:INITID处于非活动状态 写 1 激活相应的INTID,写 0 无影响 |
GICR_ICACTIVERn | 清除SGI和PPI的活动状态,每个INTID一个位,该寄存器涵盖INTID是0到31,是每个PE私有的 读取一位会返回中断的当前状态: - 1:INTID处于活动状态 - 0:INITID处于非活动状态 写 1 激活相应的INTID,写 0 无影响 |
软件触发中断 (SGI) 是软件通过写入中断控制器中的寄存器来触发的中断。
SGI是通过写入下面CPU接口中的SGI寄存器生成的:
系统寄存器接口 | 描述 |
---|---|
ICC_SGI0R_EL1 | 生成Secure Group 0中断 |
ICC_SGI1R_EL1 | 生成Group 1中断,针对安全状态PE |
ICC_ASGI1R_EL1 | 生成Group 1中断,针对非安全状态PE |
下图是SGI寄存器的基本格式:
SGI ID 字段控制生成哪个 INTID。如中断类型中所述,INTID 0‑15 用于 SGI。
IRM(中断路由模式)字段控制 SGI 发送到哪个 PE,有两个选择:
IRM = 0
中断发生到 ... ,其中 对于下的每个affinity 0节点按1位编码。这意味着中断最多可以发送到 16 个PE,其中可能包括原始生成中断的 PE。
IRM = 1
中断发送到所有连接的 PE,除了原始 PE(自身)之外。
SGI 的安全状态和分组由以下控制:
在安全状态下执行的软件可以发送安全和非安全 SGI。在非安全状态执行的软件能否生成安全的 SGI 是由 GICR_NSACR
寄存器决定的。
SGI 寄存器只能在安全状态下访问。GIC 通过检查以下内容决定是否转发中断:
发送PE的安全状态 | SGI寄存器 | 接收PE的配置 | 是否转发 |
---|---|---|---|
Secure EL3/EL1 | ICC_SGI0R_EL1 | Secure Group 0 Secure Group 1 Non-secure Group 1 | Yes No No |
Secure EL3/EL1 | ICC_SGI1R_EL1 | Secure Group 0 Secure Group 1 Non-secure Group 1 | No(*) Yes No |
Secure EL3/EL1 | ICC_ASGIR_EL1 | Secure Group 0 Secure Group 1 Non-secure Group 1 | No No Yes |
Non-secure EL2/EL1 | ICC_SGI0R_EL1 | Secure Group 0 Secure Group 1 Non-secure Group 1 | 由GICR_NSACR配置(*) No No |
Non-secure EL2/EL1 | ICC_SGI1R_EL1 | Secure Group 0 Secure Group 1 Non-secure Group 1 | 由GICR_NSACR配置(*) 由GICR_NSACR配置 No |
Non-secure EL2/EL1 | ICC_ASGIR_EL1 | Secure Group 0 Secure Group 1 Non-secure Group 1 | 由GICR_NSACR配置(*) 由GICR_NSACR配置( No |
GICD_CTLR.DS==0
。当GICD_CTLR.DS==1
时,标有(*)的SGI也会转发。在 Arm GICv2 中,SGI INTID 由原始 PE 和目标 PE 进行存储。这就意味着对于同一个中断标识符,一个给定的处理器可能会有最多八个实例同时处于待处理状态,因为每个处理器都可以产生一次中断。
在 Arm GICv3 中,SGI 仅由目标 PE 存储。这意味着给定的 PE 只能有一个 SGI INTID 实例处于挂起状态。
举个例子说明一下这些差异,PE A 和 PE B 同时向 PE C发送 SGI INTID 中断。
C会接收多少个中断?
对于GICv2:两个中断
GIC 将同时接收来自 A 和 B 的中断。两个中断的顺序取决于设计和精确的时序。这两个中断可以通过以下区分:INTID 带了一个发出中断 PE ID 的前缀,由GICC_IAR
返回。
对于GICv3:一个中断
由于原始 PE 不存储 SGI,因此同一中断不能在两个 PE 上挂起。因此,C 只接收1个中断,ID为5,无前缀。
该示例假设两个中断同时或几乎同时发送。如果 C 能够在第二个 SGI 到达之前确认第一个 SGI,那么 C 将在 GICv3 中看到两个中断。
本指南附带了一个简单的示例。该示例配置系统计数器以生成系统计数,然后使用两个定时器根据系统计数生成中断。当每个定时器触发时,中断处理程序将禁用相关的定时器,以清除中断。
该示例需要 Arm Development Studio。如果您还没有,可以下载评估版。
请参阅 zip 文件中的 ReadMe.txt 文件,了解构建和运行该示例的完整说明。
Arm GICv3 中有哪四种中断类型?如何识别?
有四种类型:LPI,SPI,PPI和SGI。通过中断源 ID号 INTID 识别。
中断可以分配到哪些组,每个组通常用于什么?
Group 0 中断通常用于 EL3 固件。
Secure Group 1 中断通常用于安全状态。
Non-secure Group 1 中断通常用于针对非安全内核或虚拟机。
中断处理程序读取哪个寄存器来找出中断?
ICC_IARn_EL1
寄存器。
复位后,GIC 将所有连接的 PE 视为离线,软件如何将 PE 标记为在线?
通过清除该 PE 的 Redistributor 中的GICR_WAKER.ProcessorSleep
,然后轮询直到 ChildrenAsleep
读取为 0。
GIC 存储中断源的哪些配置?
PE 可以向自己发送 SGI 吗?
是的。
如果PE正在处理一个中断,如何控制其他中断进行抢占?
第二个中断的优先级和 Binary Point 寄存器:ICC_BPRn_EL1
。
本指南介绍了 Arm CoreLink GICv3 和 v4 架构以及如何在裸机环境中初始化 GIC。本指南简要介绍了局部特定外设中断 (LPI) 中断类型。在 Arm CoreLink 通用中断控制器 v3 和 v4 指南:局部特定外设中断中,介绍了如何处理和初始化 LPI。
Arm CoreLink GIC 架构支持虚拟化。要了解有关 GICv3 和 GICv4 中虚拟化功能的更多信息,请阅读指南 Arm CoreLink 通用中断控制器 v3 和 v4:虚拟化。
相比 GICv2,GICv3 编程模型有些变化。为了保留对 GICv2 系统的兼容,GICv3 可以支持 legacy 操作。支持 legacy 操作是可选的并已弃用,Arm 的几个最新 GIC 实现不再支持它。
编程模型是由 Affinity Routing Enable(ARE) 的GICD_CTRL
位控制的:
在具有两个安全状态的系统中,每个安全状态可以单独控制 affinity routing。仅允许特定组合,如下所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。