Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 – 15SGI这些中断对 CPU interface 是本地的。INTID 0-1023 与 GIC 架构的早期版本兼容。
16 – 31PPI这些中断对 CPU interface 是本地的。(同上)
32 – 1019SPIDistributor 可以路由到特定 PE 或系统中任何参与节点 PE 的共享外设中断,请参见 参与节点。
1020 – 1023特殊中断号为特殊用途保留的中断 ID,如 特殊 INTID 中所述。
1024 – 1055-保留-
1056 – 1119PPI扩展 PPI。这些中断对 CPU interface 是本地的。INTID 1056-1119 与 GIC 架构的早期版本不兼容。此范围由 GICv3.1 架构支持。
1120 – 4095-保留-
4096 – 5119SPI扩展 SPI。由 GICv3.1 架构支持。
5120 – 8191-保留
8192 – IMPLEMENTATION DEFINEDLPI路由到特定 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 使用软件生成 SGI 时写入的亲和性地址和路由模式信息进行路由。

使用以下寄存器生成 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 位的写入是否已完成。