Generic Interrupt Controller versions 3 and 4
This page seeks to give a quick reference to the behaviour of the version 3 and 4 GIC, especially relative to version 2. It heavily references Generic Interrrupt Controller, and recommends that page as prior reading.
Version 3 of the GIC specification is no longer separate from the core ARM specification, but as of version 3, the GICv3 is part of the architectural state of the ARM architecture, from ARMv8 and onward. In particular, from ARMv8 onwards, access to the GICC_*, GICV_* and GICH_* groups of registers are provided as ARM architected system registers, and not only as memory-mapped registers. In other words, they are accessible as ARM coprocessors. The GICD_*, GICR_* and GICS_* groups of registers however, are always memory mapped.
On an ARMv7 platform, the GIC is an extension that is not architecturally specified. On ARMv8 platforms, the GIC, if implemented, is architecturally specified.
Another key improvement over GICv2 is that CPUIDs in GICv3 are no longer restricted to a maximum of 8 processor IDs, and so GICv3 and upwards supports the delivery of IRQs to more than 8 Processing Elements (PEs).
Version difference summary
Differences between GICv2 and GICv3
Differences between GICv3 and GICv4
Interrupt Grouping changes
In GICv3, the meaning of interrupt Grouping has been expanded a bit; in GICv2, group0 was simply about secure IRQs, and group1 was about non-secure IRQs. This remains the same in GICv2. However, there are slight changes to the way that group1 IRQs are handled. In a system with two security states, an IRQ can either be:
- Group0: ARM expects that these will be handled at EL3 (Monitor mode).
- Secure Group1: ARM expects that these will be handled by Secure PL1.
- Non-secure Group1: ARM expects that these will be handled by non-secure PL2 (Hyp mode) or non-secure PL1 (kernel/supervisor mode). Essentially, if a Hypervisor exists, then the Hypervisor will handle these and re-inject them into the guest VM as virtual IRQs; if there is no hypervisor, then these will be handled by the PL1 kernel directly.
GICD_CTLR.DS indicates if the GIC is configured with one or two security states; or more specifically, GICD_CTLR.DS indicates whether or not the GIC implements a security model compatible with the ARMv8 security model.
In a system where there is only one security state supported (no Security Extensions), IRQs can be configured as either:
LPIs are always Group1 IRQs. In a GICv3 implementation that has 2 security states, they are specifically non-secure Group1 IRQs.
Acknowledging and EOIing Group0 IRQs
For group0 IRQs, software should attempt to manage them using: ICC_IAR0_EL1, ICC_EOIR0_EL1, ICC_BPR0_EL1, ICC_HPPIR0_EL1, and finally ICC_IGRPEN0_EL1 to enable Group0 IRQs at the CPU interface.
Acknowledging and EOIing Group1 IRQs
For group1 IRQs, software should attempt to manage them using: ICC_IAR1_EL1, ICC_EOIR1_EL1, ICC_BPR1_EL1, ICC_HPPIR1_EL1, and finally ICC_IGRPEN1_EL1 to enable Group1 IRQs at the CPU interface for the target security state (secure vs non-secure PL1).
Redistributors are a new component of the IRI (Interrupt Routing Infrastructure) that are responsible for holding information about all pending physical LPIs (MSI IRQs). In a GICv4 implementation, a Redistributor also holds information about pending virtual LPIs, enabling the injection of virtual MSI IRQs into CPUs (which is not supported in hardware in GICv3; a hypervisor must emulate the injection of a virtual MSI IRQ in GICv3).
Introduced in GICv3, Affinity routing is a form of specifying PE node IDs in a multiprocessor system using a 32-bit integer that is split into 4 subcomponents: a, b, c and d. If you want to use all 4 levels of addressing, you must be running on an AArch64 processor. AArch32 only supports 3 levels.
- A 4-level identifier is of the form a.b.c.d.
- A 3-level identifier is of the form 0.b.c.d, where the "a" component must be 0.
To enable affinity-based routing in the Distributor for Secure IRQs, set GICD_CTLR.ARE_S to 1. To enable affinity-based routing in the Distributor for non-secure IRQs, set GICD_CTLR.ARE_NS to 1. Changing the value of either or both of these bits from 1 to 0 is <UNPREDICTABLE>. Changing the value from 0 to 1 is <UNPREDICTABLE> unless both groups of interrupts (group0 and group1) are disabled. Specifically:
- If GICD_CTLR.DS == 0, changing the value from 0 to 1 is <UNPREDICTABLE> when:
- GICD_CTLR.EnableGrp0 == 0.
- GICD_CTLR.EnableGrp1S == 0.
- GICD_CTLR.EnableGrp1NS == 0.
- If GICD_CTLR.DS == 1, then changing the value from 0 to 1 is <UNPREDICTABLE> when:
- GICD_CTLR.EnableGrp0 == 0.
- GICD_CTLR.EnableGrp1 == 0.
Software (the kernel) should ensure that the Distributor has commited the effects of these writes before proceeding, by polling GICD_CTLR.RWP before continuing.
Some GIC implementations may have affinity based routing permanently enabled. In such a case, GICD_CTLR.ARE_S and GICD_CTLR.ARE_NS are both RAO/WI.
Affinity routing mode with SPIs
SPIs are routed using the GICD_IROUTER<n>.Interrupt_Routing_Mode bit:
- If GICD_IROUTER<n>.Interrupt_Routing_Mode == 0, SPIs are forwarded to a single target PE, matching a.b.c.d.
- If GICD_IROUTER<n>.Interrupt_Routing_Mode == 1, SPIs are forwarded to all PEs that qualify as a "participating node".
Affinity routing mode with SGIs
SGIs are routed using the ICC_SGI0R_EL1.IRM and ICC_SGI1R_EL1.IRM bit:
- If the IRM bit is set to 1, SGIs are broadcast to all participating PEs in the system, excluding the originating PE (all-but-self).
- If the IRM bit is set to 0, SGIs are routed to a group of PEs, selected according to a.b.d.<TARGET_LIST>. TARGET_LIST is a bitfield for encoding values from 0-15.
See section 3.3.2, which I could not understand.
Interrupt IDs are the unique identifiers for an IRQ. The number of IntIDs available in hardware at the Distributor and Redistributor is limited to a 10-bit space if LPIs are not supported. If LPIs are supported, the IntID space is of bit-width <IMPLEMENTATION DEFINED>, between 14 and 24 bits. Read GICD_TYPER to find out the bit-width of the IntID space in this case.
The number of IntIDs supported by the ITS (if LPIs are supported) is defined as a bit-width that is IMPLEMENTATION DEFINED between 14-and 24 bits. Read GITS_TYPER to discover the bit-width of the IntID space. Given that the ITS is used for the purpose of managing LPIs, one can assume that if an ITS exists, then LPIs also exist, but this is just my personal conclusion. Be careful to only program the ITS to forward IRQs whose IntIDs are within the range of the target Redistributor's IntID bit-space.
The number of IntIDs supported by the GICv3 CPU Interface is is either an IMPLEMENTATION DEFINED 16 bits or 24 bits. Check ICC_CTLR_EL1.IDbits and ICC_CTLR_EL3.IDbits.
ARM imposes the following constraints on GIC implementations:
- PEs (Processor Interfaces) must implement either 16 or 24 bits of IntID. However, a system might have a mixture of PEs that support both sizes!
- The Distributor and Redistributors must all implement the same number of ID bits. The ID bits for the Distributor and Redistributor must not exceed the minimum IntID size implemented by any single PE in the system. I.e, the Distributor and Redistributor IntID bit-width cannot must be smaller than or equal to the bit width of the smallest PE bit-width.
- IF LPIs are supported, the Distributor and Redistributors must implement at least 5 bits of IntID, and at most 10 bits of IntID.
- If an ITS exists, the ITS may implement any bit-width up to or equal to the bit-width of the Redistributors; and this bit width must be a minimum of 14 bits.
IntID space division
- ID0-ID15: Software Generated Interrupts (SGIs.)
- ID16-ID31: Private Peripheral Interrupts (PPIs.)
- ID32-ID1019: Shared Peripheral Interrupts (SPIs.)
- ID1020-ID1023: Special interrupt IDs.
- ID1024-ID8191: Reserved.
- ID8192-<IMPLEMENTATION DEFINED MAX BIT WIDTH>: Locality-based Peripheral Interrupts (LPIs.)
Orthogonal insertion: GICv4 assists in making IntIDs unique per-guest VM by providing a vPEID in addition to the IntID space.
ARM's Recommended default mapping of private peripheral IRQs to PPI IDs
This is ARM's recommended mapping; SoC designers do not need to conform to it. Where the SoC implementation differs, the core or SoC or platform documentation will state what the PPI IntIDs are. That being said, ARM recommneds that the following mapping be used:
- ID30: Non-secure Physical Timer IRQ.
- ID29: Secure Physical Timer IRQ.
- ID27: Virtual Timer IRQ.
- ID26: Hypervisor Timer Interrupt.
- ID25: Virtual CPU Interface Maintenance IRQ (VGIC Maintenance IRQ).
- ID24: Cross Trigger Interface IRQ.
- ID23: PMC (Perf Monitor Counter) Overflow IRQ.
- ID22: DCC (Debug Communications Channel) IRQ.
Special IntIDs (and changes from GICv2)
In GICv2, the special IntID 1022 is used to signal to the Secure Monitor that the current highest priority IRQ was meant to be handled in non-secure world (most likely by the hypervisor). In GICv3 onwards, this value is deprecated.
In GICv2 and GICv3 onwards, IntID 1023 is used to signal a Spurious IRQ, or to state to a non-secure world handler that the current highest-priority IRQ is meant to be handled by the secure world.
In GICv3 onwards, two new special IntIDs are introduced:
- ID1020: The GIC returns this value when ICC_IAR0_EL1 or ICC_HPPIR0_EL1 is read from EL3 (Secure Monitor Mode), but the current highest priority IRQ is meant to be handled by Secure EL1.
- ID1021: The GIC returns this value when ICC_IAR0_EL1 or ICC_HPPIR0_EL1 is read from EL3 (Secure Monitor Mode), but the current highest priority IRQ is meant to be handled by non-Secure EL1.
Interrupt acknowledgement is accomplished through a read from ICC_IAR0_EL1 for group0 IRQs, and it is accomplished via a read from ICC_IAR1_EL1 for group1 IRQs.
EOI is accomplished via a write to ICC_EOIR0_EL1 for group0 IRQs, and it is accomplished via a read from ICC_EOIR1_EL1 for group1 IRQs.
Message-Based IRQ support
The ITS is one method of supporting MSI IRQs on ARM platforms that implement the GIC architecture. There are two approaches, and a platform must support only one (GICv3&4 specification, section 6.2):
- The device generates an LPI by writing directly to the Redistributor's GICR_SETLPIR.
- The device generates an LPI via the ITS service, which will generate the LPI on its behalf.
In GICv3 the ITS is optional, one option (ITS vs no-ITS). In GICv4, there must be at least one ITS, in order to support the injection of virtual LPIs into vPEs (so GICv4 must choose the ITS approach, and it does not have the option of using the non-ITS approach).
Locality-based Peripheral IRQ
Support for a new type of IRQ is added from GICv3 onwards: Locality-based Peripheral IRQs (LPIs), which are used for message-based IRQs. LPIs are not routed through the Distributor, but they are routed directly to Redistributors, which are connected directly to PEs. The Distributor manages pin-based IRQs (SPIs, PPIs and SGIs) while the ITS+Redistributors manage MSIs.
LPIs can be generated either by writing to a Redistributor's GICR_SETLPIR, or through the ITS.
LPIs are always edge-triggered. (GICv3&4 specification, section 1.2.1). When LPIs are acknowledged (read from the IAR), their pending state goes from pending to not-pending in the Redistributor. The Redistributor does not maintain an active state for LPIs.
Section 4.2 explains that "In a system where two Security states are enabled, LPIs are always non-secure Group 1 IRQs".
Interrupt Translation Service
Note that the configuration of ITS should have no effect on SPIs, SGI, PPIs (GICv3&4 specification, section 6.2: "An ITS has no effect on SGIs, SPIs or PPIs."). Its purpose is confined to generating IRQ signals from in-band bus messages.
For the GIC architecture, ARM devices that support MSI (message-signaled IRQs) are each assigned a DeviceID. Additionally, each MSI IRQ that the device will generate is assigned an EventID. This combination of DeviceID+EventID are used as inputs to the ITS. The ITS then uses the DeviceID to index into its Device Table, and select that device's Interrupt Translation Table (ITT). The EventID is then used to index into the ITS' ITT for that device, and select the pertinent Interrupt Translation Entry (ITE).
Each ITE then indicates a Collection Table (CT) entry, which gives the target Redistributor for a physical MSI IRQ. For GIVc3, if a device has a physical MSI IRQ, and the OS Hypervisor would like to virtualize that IRQ to a Guest VM, the hypervisor must deliver that IRQ as a standard virtual IRQ (Not 100% sure on this yet).
GICv4 also adds support for delivering virtual MSI IRQs. In this case, the ITE indicates a vPEID, which indicates a vPE table entry (and therefore, the physical Redistributor that hosts the target vPE for the virtual MSI).
These tables may seem tedious, and that is because they are; but thankfully they are not exposed to the hypervisor. The hypervisor is required to simply update the global IPL configuration table, and then issue INVALIDATE (INV and INVALL) commands to the ITS machinery (if it exists), so that the ITS can read the new configuration values. It is not possible to directly access the ITS' internal tables (GICv3&4 specification, section 6.2). The hypervisor should also issue a SYNC command to the ITS if it needs to be sure that the INVALIDATE command has completed before execution continues.
Where there is no ITS hardware implemented, the hypervisor performs invalidation of LPI configuration via writes to GICR_INVALLR (invalidate all entries) or GICR_INVLPIR (invalidate single entry).
Caveat: All the ITS' tables are stored in non-secure physical memory. Author's comment: It appears that the entire GIC MSI IRQ architecture is based on routing of MSI IRQs directly to a Redistributor, or indirectly to a Redistributor through an ITS.