Chapter 2: 中断的分发和路由
本章描述使用亲和性路由向目标 PE 分发和路由中断,以及中断 ID 的分配。包含以下部分:
-
Distributor 和 Redistributor 。
-
INTID 。
-
亲和性路由 。
2.1 Distributor 和 Redistributor
Distributor 提供 SPI 的路由配置,并保存所有相关的路由和优先级信息。
Redistributor 提供 PPI 和 SGI 的配置设置。
Redistributor 总是在有限时间内向 CPU interface 呈现具有最高优先级的待处理中断。有关中断优先级排序的更多信息,请参见 中断优先级排序 。
最高优先级待处理中断可能因以下原因而改变:
-
先前的最高优先级中断已被确认。
-
先前的最高优先级中断已被抢占。
-
先前的最高优先级中断被移除且不再有效。
-
组中断使能已被修改。
-
PE 不再是参与 PE。请参见 参与节点 。
2.2 INTID
中断使用 ID 号(INTID)标识。GICv3 支持的 INTID 范围是 IMPLEMENTATION DEFINED,根据以下规则:
-
对于 Distributor 和 Redistributor 支持的 INTID 位数:
-
如果不支持 LPI,Distributor 中的 ID 空间限制为 10 位。这与 GIC 架构的早期版本相同。
-
如果支持 LPI,INTID 字段在 14-24 位范围内是 IMPLEMENTATION DEFINED,如 GICD_TYPER 的寄存器描述中所述。
注意
可以通过 GICR_PROPBASER 配置 Redistributor 使用比 GICD_TYPER 指定的更少的位数。
-
对于 ITS 支持的 INTID 位数: — 如果支持 LPI,INTID 字段在 14-24 位范围内是 IMPLEMENTATION DEFINED。
-
INTID 字段的大小由 GITS_TYPER.IDbits 定义。
必须对 ITS 进行编程,以便转发到 Redistributor 的中断在该 Redistributor 支持的中断范围内,否则行为是 UNPREDICTABLE。
-
对于 CPU interface 支持的 INTID 位数:
- GICv3 CPU interface 支持 16 位或 24 位 INTID 字段,选择是 IMPLEMENTATION DEFINED。支持的物理中断标识符位数由 ICC_CTLR_EL1.IDbits 和 ICC_CTLR_EL3.IDbits 指示。
有效的 INTID 空间由 CPU interface 和 Distributor 中的实现大小决定。将大于支持大小的 INTID 转发到 CPU interface 是编程错误。
未使用的 INTID 位为 RAZ。这意味着任何受影响的位字段都是零扩展的。
表 2-1 显示了 INTID 空间如何按中断类型划分。
表 2-1 INTID
| INTID | 中断类型 | 详细信息 | 注释 |
|---|---|---|---|
| 0 – 15 | SGI | 这些中断对 CPU interface 是本地的。 | INTID 0-1023 与 GIC 架构的早期版本兼容。 |
| 16 – 31 | PPI | 这些中断对 CPU interface 是本地的。 | (同上) |
| 32 – 1019 | SPI | Distributor 可以路由到特定 PE 或系统中任何参与节点 PE 的共享外设中断,请参见 参与节点。 | |
| 1020 – 1023 | 特殊中断号 | 为特殊用途保留的中断 ID,如 特殊 INTID 中所述。 | |
| 1024 – 1055 | - | 保留 | - |
| 1056 – 1119 | PPI | 扩展 PPI。这些中断对 CPU interface 是本地的。 | INTID 1056-1119 与 GIC 架构的早期版本不兼容。此范围由 GICv3.1 架构支持。 |
| 1120 – 4095 | - | 保留 | - |
| 4096 – 5119 | SPI | 扩展 SPI。 | 由 GICv3.1 架构支持。 |
| 5120 – 8191 | - | 保留 | |
| 8192 – IMPLEMENTATION DEFINED | LPI | 路由到特定 PE 的外设硬件中断。 | - |
注意 Arm 推荐的 PPI INTID 分配由服务器基础系统架构提供,请参见 Arm[®] Server Base System Architecture (SBSA) 。
GICv4 架构通过支持 vPEID 以及 INTID 空间为每个 VM 提供唯一的 INTID 空间。有关 VM 的更多信息,请参见 关于 GIC 对虚拟化的支持 ,有关 vPEID 的更多信息,请参见 中断转换服务 。
Arm 强烈建议实现的中断分组使用最低的 INTID 号和尽可能小的 INTID 范围。这减少了必须实现的内存中关联表的大小,以及发现例程必须检查的大小。
Arm 强烈建议软件保留:
-
INTID0 - INTID7 用于 Non-secure 中断。
-
INTID8 - INTID15 用于 Secure 中断。
2.2.1 特殊 INTID
GIC 架构为特殊用途保留的 INTID 列表如下:
1020 GIC 返回此值以响应在 EL3 读取 ICC_IAR0_EL1 或 ICC_HPPIR0_EL1,指示被确认的中断是预期在 Secure EL1 处理的中断。此 INTID 仅在 PE 使用 AArch64 状态在 EL3 执行时,或者 PE 在 AArch32 状态下以 Monitor 模式执行时返回。
当 ICC_CTLR_EL3.RM == 1 时,此值也可以由在 EL3 读取 ICC_IAR1_EL1 或 ICC_HPPIR1_EL1 返回,请参见 非对称操作和 ICC_CTLR_EL3.RM 的使用 。
1021 GIC 返回此值以响应在 EL3 读取 ICC_IAR0_EL1 或 ICC_HPPIR0_EL1,指示被确认的中断是预期在 Non-secure EL1 或 EL2 处理的中断。此 INTID 仅在 PE 使用 AArch64 状态在 EL3 执行时,或者 PE 在 AArch32 状态下以 Monitor 模式执行时返回。当 ICC_CTLR_EL3.RM == 1 时,此值也可以由在 EL3 读取 ICC_IAR1_EL1 或 ICC_HPPIR1_EL1 返回,请参见 非对称操作和 ICC_CTLR_EL3.RM 的使用。
1022 此值仅适用于传统操作。有关更多信息,请参见 特殊 INTID 1022 的使用。
1023 如果没有具有足够优先级的待处理中断可以向 PE 发出信号,或者如果最高优先级待处理中断不适合以下条件,则此值作为中断确认的响应返回:
- 当前安全状态。
- 与系统寄存器关联的中断组。
注意 这些 INTID 不需要中断结束或停用。
有关特殊 INTID 使用的更多信息,请参见以下寄存器的描述:
-
ICC_IAR0_EL1。
-
ICC_IAR1_EL1。
-
ICC_HPPIR0_EL1。
-
ICC_HPPIR1_EL1。
2.2.2 混合 INTID 大小的实现
实现可能选择为 GIC 的不同部分实现不同的 INTID 大小,受以下规则约束:
-
PE 可以实现 16 位或 24 位 INTID。
注意
系统可能包含支持 16 位 INTID 的 PE 和支持 24 位 INTID 的 PE 的混合。
-
Distributor 和 Redistributor 必须全部实现相同数量的 INTID 位。
-
在支持 LPI 的系统中,Distributor 和所有 Redistributor 必须实现至少 14 位 INTID。在 Distributor 和 Redistributor 中实现的位数不得超过系统中任何 PE 实现的最小位数。
注意 因为中断可能针对任何 PE,每个 PE 必须能够接收 Redistributor 可以发送的最大 INTID。这意味着 Redistributor 支持的 INTID 大小不能超过系统中每个 PE 支持的最小 INTID 大小。
-
在不支持 LPI 的系统中,Distributor 和所有 Redistributor 必须实现至少 5 位 INTID,不能实现超过 10 位 INTID。对于 GIC 版本 3.1,不能实现超过 13 位 INTID。
-
在包含一个或多个 ITS 的系统中,ITS 可以实现任何值,最多包括 Distributor 和 Redistributor 支持的位数,最少为 14 位,这是 LPI 支持所需的最小位数。
2.2.3 有效中断 ID 检查伪代码
以下伪代码描述了 GIC 如何检查物理中断的 INTID 是否有效:
// InterruptIdentifierValid()
// ==========================
boolean InterruptIdentifierValid(bits(64) data, boolean lpiAllowed)
// First check whether any out of range bits are set
integer N = CPUInterfaceIDSize();
if !IsZero(data<63:N>) then
if GenerateLocalSError() then
// Reporting of locally generated SEIs is supported
IMPLEMENTATION_DEFINED "SError INVALID_INTERRUPT_IDENTIFIER";
UNPREDICTABLE;
intID = data<INTID_SIZE-1:0>;
if !lpiAllowed && IsLPI(intID) then // LPIs are not supported
if GenerateLocalSError() then
// Reporting of locally generated SEIs is supported
IMPLEMENTATION_DEFINED "SError INVALID_INTERRUPT_IDENTIFIER";
UNPREDICTABLE;
以下伪代码描述了 GIC 如何检查虚拟中断的 INTID 是否有效:
// VirtualIdentifierValid()
// ========================
boolean VirtualIdentifierValid(bits(64) data, boolean lpiAllowed)
// First check whether any out of range bits are set
integer N = VIDBits();
if !IsZero(data<63:N>) then
if ICH_VTR_EL2.SEIS == '1' then
// Reporting of locally generated SEIs is supported
IMPLEMENTATION_DEFINED "SError INVALID_INTERRUPT_IDENTIFIER";
UNPREDICTABLE;
intID = data<INTID_SIZE-1:0>;
if !lpiAllowed && IsLPI(intID) then // LPIs are not supported
if ICH_VTR_EL2.SEIS == '1' then
// Reporting of locally generated SEIs is supported
IMPLEMENTATION_DEFINED "SError INVALID_INTERRUPT_IDENTIFIER";
UNPREDICTABLE;
// Now check for special identifiers
if IsSpecial(intID) then
return FALSE; // It is a special ID
// All the checks pass so the identifier is valid
return TRUE;
以下伪代码描述 CPU interface ID 大小函数。
// CPUInterfaceIDSize()
// Returns TRUE if the value supplied has bits above the implemented range or
// if the value supplied exceeds the maximum configured size in the
// appropriate GITS_BASERn
boolean VCPUOutOfRange(bits(16) vcpu);
2.3 亲和性路由
亲和性路由是一种基于分层地址的方案,用于识别特定的 PE 节点进行中断路由。
对于 PE,亲和性值在 AArch64 状态下在 MPIDR_EL1 中定义,在 AArch32 状态下在 MPIDR 中定义:
-
亲和性路由是一个 32 位值,由四个 8 位亲和性字段组成。这些字段是节点 a 、b 、c 和 d 。
-
使用 AArch64 状态的 GICv3 可以支持:
-
四级路由层次结构,a.b.c.d。
-
三级路由层次结构,0.b.c.d。
-
-
使用 AArch32 状态的 GICv3 仅支持三个亲和性级别。
-
ICC_CTLR_EL3.A3V、ICC_CTLR_EL1.A3V 和 GICD_TYPER.A3V 指示是否实现四级或三级亲和性。
注意 需要四级亲和性的实现必须仅支持 AArch64 状态。
在亲和性层次结构中指定节点的枚举符号为以下形式,其中 Affx 是亲和性级别 x:
Aff3.Aff2.Aff1.Aff0
在 Distributor 中使用 亲和性路由使能(ARE)位启用安全状态的亲和性路由。亲和性路由在以下情况下启用:
-
对于 Secure 中断,如果 GICD_CTLR.ARE_S 设置为 1。
-
对于 Non-secure 中断,如果 GICD_CTLR.ARE_NS 位设置为 1。
如果永久启用亲和性路由,GICD_CTLR.ARE_S 和 GICD_CTLR.ARE_NS 为 RAO/WI。
当启用亲和性路由时处理物理中断,还必须启用系统寄存器访问,请参见 GIC 系统寄存器访问 。对于其他情况,请参见第 14 章 传统操作和非对称配置 。
2.3.1 按 PE 亲和性路由 SPI 和 SGI
SPI 使用亲和性地址和 GICD_IROUTER
使用以下寄存器生成 SGI:
-
ICC_SGI0R_EL1。
-
ICC_SGI1R_EL1。
-
ICC_ASGI1R_EL1。
Arm 强烈建议在亲和性级别 0 仅使用 0-15 范围内的值,以与 SGI 目标列表功能对齐。请参见 软件生成中断 。
SPI 和 SGI 使用不同的寄存器进行路由:
-
SPI 使用 GICD_IROUTER
.Interrupt_Routing_Mode 进行路由: -
如果 GICD_IROUTER
.Interrupt_Routing_Mode 清除为 0,SPI 路由到由 a.b.c.d 指定的单个 PE。 -
如果 GICD_IROUTER
.Interrupt_Routing_Mode 设置为 1,SPI 路由到定义为参与节点的任何 PE: -
IRI 选择目标 PE 的机制是 IMPLEMENTATION DEFINED。
-
当 ICC_CTLR_EL3.PMHE == 1 或 ICC_CTLR_EL1.PMHE == 1 时,IRI 可能使用与 PE 关联的 ICC_PMR_EL1 寄存器来确定目标 PE。
-
-
有关参与节点的更多信息,请参见 参与节点 。
-
SGI 使用 ICC_SGI0R_EL1.IRM 和 ICC_SGI1R_EL1.IRM 进行路由:
-
如果 IRM 位设置为 1,SGI 路由到系统中所有参与的 PE,不包括发起 PE。
-
如果 IRM 位清除为 0,SGI 路由到由 a.b.c.targetlist 指定的 PE 组。
-
2.3.2 参与节点
配置为使用 1 of N 分发模型的启用 SPI 在以下情况下可以针对 PE:
-
GICR_WAKER.ProcessorSleep == 0 且中断的中断组在 PE 上启用。
-
GICD_CTLR.E1NWF == 1。
-
GICR_TYPER.DPGS == 1,且对于中断的中断组,GICR_CTLR.{DPG1S, DPG1NS, DPG0} == 0。
有关使用 1 of N 分发模型时 PE 是否可以被选择为目标的更多信息,请参见 GICR_CTLR,Redistributor 控制寄存器第 12-621 页 。
有关启用中断和中断组的更多信息,请参见 启用中断分发 。
2.3.3 更改亲和性路由使能
本手册描述了在启用亲和性路由的系统中的 GICv3 架构。这意味着:
-
GICD_CTLR.ARE_NS == 1。
-
GICD_CTLR.ARE_S == 1。
如果 GICD_CTLR.ARE_NS 或 GICD_CTLR.ARE_S 的值从 1 更改为 0,结果是 UNPREDICTABLE。
当 GICD_CTLR.DS == 0 时:
-
将 GICD_CTLR.ARE_S 从 0 更改为 1 是不可预测的,除非以下所有条件都适用:
-
GICD_CTLR.EnableGrp0 == 0。
-
GICD_CTLR.EnableGrp1S == 0。
-
GICD_CTLR.EnableGrp1NS == 0。
-
-
将 GICD_CTLR.ARE_NS 从 0 更改为 1 是不可预测的,除非 GICD_CTLR.EnableGrp1NS == 0。
当 GICD_CTLR.DS == 1 时:
-
将 GICD_CTLR.ARE 从 0 更改为 1 是不可预测的,除非以下所有条件都适用: — GICD_CTLR.EnableGrp0 == 0。
- GICD_CTLR.EnableGrp1 == 0。
注意 清除 GICD_CTLR.EnableGrp0、GICD_CTLR.EnableGrp1S 或 GICD_CTLR.EnableGrp1NS(视情况而定)的效果必须在将 GICD_CTLR.ARE_S 或 GICD_CTLR.ARE_NS 从 0 更改为 1 时可见。软件可以轮询 GICD_CTLR.RWP 来检查清除 GICD_CTLR.EnableGrp0、GICD_CTLR.EnableGrp1S 或 GICD_CTLR.EnableGrp1NS 位的写入是否已完成。