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 位亲和性字段组成。这些字段是节点 abcd

  • 使用 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 位的写入是否已完成。