Configuring the GIC

This section of the guide describes how to enable and configure a GICv3-compliant interrupt controller in a bare metal environment. For detailed register descriptions see the Arm Generic Interrupt Controller Architecture Specification GIC architecture version 3.0 and 4.

The configuration of Locality-specific Peripheral Interrupts (LPIs) is significantly different to the configuration of Shared Peripheral Interrupts (SPIs), Private Peripheral Interrupt (PPIs), and Software Generated Interrupts (SGIs), and is beyond the scope of this guide. To learn more, refer to our guide Arm CoreLink Generic Interrupt Controller v3 and v4: Locality-specific Peripheral Interrupts.

Most systems that use a GICv3 interrupt controller are multi-core systems, and possibly also multi-processor systems. Some settings are global, which means that affect all the connected PEs. Other settings are particular to a single PE.

Let’s look at the global settings, and then the settings for each PE.

Global settings

The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode as follows:

  • Enable Affinity routing (ARE bits): The ARE bits in GICD_CTLR control whether the GIC is operating in GICv3 mode or legacy mode. Legacy mode provides backwards compatibility with GICv2. This guide assumes that the ARE bits are set to 1, so that GICv3 mode is being used.
  • Enables: GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
    • EnableGrp1S enables distribution of Secure Group 1 interrupts.
    • EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
    • EnableGrp0 enables distribution of Group 0 interrupts.

Note: Arm CoreLink GIC-600 does not support legacy operation, and the ARE bits are permanently set to 1.

Settings for each PE

This section covers settings that are specific to a single core or PE.

Redistributor configuration

Each core has its own Redistributor, as shown here:

The Redistributor contains a register called GICR_WAKER which is used to record whether the connected PE is online or offline. Interrupts are only forwarded to a PE that the GIC believes is online. At reset, all PEs are treated as being offline.

To mark the connected PE as being online, software must:

  • Clear GICR_WAKER.ProcessorSleep to 0.
  • Poll GICR_WAKER.ChildrenAsleep until it reads 0.

It is important that software performs these steps before configuring the CPU interface, otherwise behavior can be UNPREDICTABLE.

While the PE is offline (GICR_WAKER.ProcessorSleep==1), an interrupt that is targeting the PE will result in a wake-request signal being asserted. Typically, this signal will go to the power controller of the system. The power controller then turns on the PE. On waking, software on that PE would clear the ProcessorSleep bit, allowing the interrupt that woke the PE to be forwarded.

CPU interface configuration

The CPU interface is responsible for delivering interrupt exceptions to the PE to which it is connected. To enable the CPU interface, software must configure the following:

  • Enable System register access.
    The CPU interfaces (ICC_*_ELn) section describes the CPU interface registers, and how they are accessed as System registers in GICv3. Software must enable access to the CPU interface registers, by setting the SRE bit in the ICC_SRE_ELn registers.

     

    Note: Many recent Arm Cortex processors do not support legacy operation, and the SRE bits are fixed as set. On these processors this step can be skipped.

  • Set Priority Mask and Binary Point registers.
    The CPU interface contains the Priority Mask register (ICC_PMR_EL1) and the Binary Point registers (ICC_BPRn_EL1). The Priority Mask sets the minimum priority that an interrupt must have in order to be forwarded to the PE. The Binary Point register is used for priority grouping and preemption. The use of both registers is described in more detail in Handling Interrupts.
  • Set EOI mode.
    The EOImode bits in ICC_CTLR_EL1 and ICC_CTLR_EL3 in the CPU interface control how the completion of an interrupt is handled. This is described in more detail in End of interrupt.
  • Enable signaling of each interrupt group.
    The signaling of each interrupt group must be enabled before interrupts of that group will be forwarded by the CPU interface to the PE. To enable signaling, software must write to the ICC_IGRPEN1_EL1 register for Group 1 interrupts and ICC_IGRPEN0_EL1 registers for Group 0 interrupts. ICC_IGRPEN1_EL1 is banked by Security state. This means that ICC_GRPEN1_EL1 controls Group 1 for the current Security state. At EL3, software can access both Group 1 enables using ICC_IGRPEN1_EL3.

PE configuration

Some configuration of the PE is also required to allow it to receive and handle interrupts. A detailed description of this is outside of the scope of this guide. In this guide, we will describe the basic steps that are required for an Armv8-A compliant PE executing in AArch64 state.

  • Routing controls
    The routing controls for interrupts are in SCR_EL3 and HCR_EL2 of the PE. The routing control bits determine the Exception level to which an interrupt is taken. The routing bits in these registers have an UNKNOWN value at reset, so they must be initialized by software.
  • Interrupt masks
    The PE also has exception mask bits in PSTATE. When these bits are set, interrupts are masked. These bits are set at reset.
  • Vector table
    The location of the vector tables of the PE is set by the VBAR_ELn registers. Like with SCR_EL3 and HCR_EL2, VBAR_ELn registers have an UNKNOWN value at reset. Software must set the VBAR_ELn registers to point to the appropriate vector tables in memory.

To learn more about these steps, see the Learn the Architecture: Exception model guide.

SPI, PPI, and SGI configuration

So far, we have looked at configuring the interrupt controller itself. We will now discuss the configuration of the individual interrupt sources.

Which registers are used to configure an interrupt depends on the type of interrupt:

  • SPIs are configured through the Distributor, using the GICD_* registers.
  • PPIs and SGIs are configured through the individual Redistributors, using the GICR_* registers.

These different configuration mechanisms are illustrated in the following diagram:

For each INTID, software must configure the following:

  • Priority: GICD_IPRIORITYn, GICR_IPRIORITYn
    Each INTID has an associated priority, represented as an 8-bit unsigned value. 0x00 is the highest possible priority, and 0xFF is the lowest possible priority. Running priority and preemption describes how the priority value in GICD_IPRIORITYn and GICR_IPRIORITYn masks low priority interrupts, and how it controls preemption. An interrupt controller is not required to implement all 8 priority bits. A minimum of 5 bits must be implemented if the GIC supports two Security states. A minimum of 4 bits must be implemented if the GIC support only a single Security state.
  • Group: GICD_IGROUPn, GICD_IGRPMODn, GICR_IGROUPn, GICR_IGRPMODn
    As described in Security model, an interrupt can be configured to belong to one of the three interrupt groups. These interrupt groups are Group 0, Secure Group 1 and Non-secure Group 1.
  • Edge-triggered or level-sensitive: GICD_ICFGRn, GICR_ICFGRn
    For PPIs and SPI, the software must specify whether the interrupt is edge-triggered or level-sensitive. SGIs are always treated as edge-triggered, and therefore GICR_ICFGR0 behaves as Read-As-One, Writes Ignored (RAO/WI) for these interrupts.
  • Enable: GICD_ISENABLERn, GICD_ICENABLER, GICR_ISENABLERn, GICR_ICENABLERn
    Each INTID has an enable bit. Set-enable registers and Clear-enable registers remove the requirement to perform read-modify-write routines. Arm recommends that the settings outlined in this section are configured before enabling the INTID.

For a bare metal environment, it is often unnecessary to change settings after initial configuration. However, if an interrupt must be reconfigured, for example to change the Group setting, you should first disable the interrupt before changing its configuration.

The reset values of most of the configuration registers are IMPLEMENTATION DEFINED. This means that the designer of the interrupt controller decides what the values are, and the values might vary between systems.

Arm CoreLink GICv3.1 and the extended INTID ranges

Arm CoreLink GICv3.1 added support for additional SPI and PPI INTIDs. The registers to configure these interrupts are the same as the original interrupt ranges, except that they have an E suffix. For example:

  • GICR_ISENABLERn - Enable bits for the original PPI range
  • GICR_ISENABLERnE - Enable bits for the additional PPIs that are introduced in GICv3.1

Setting the target PE for SPIs

For SPIs, the target of the interrupt must be configured. This is controlled by GICD_IROUTERn or GICD_IROUTERnE for the GICv3.1 extended SPIs. There is a GICD_IROUTERn register for each SPI, and the Interrupt_Routing_Mode bit controls the routing policy. The options are:

  • GICD_IROUTERn.Interrupt_Routing_Mode == 0
    The SPI is delivered to the PE A.B.C.D, which are the affinity co-ordinates specified in the register.
  • GICD_IROUTERn.Interrupt_Routing_Mode == 1
    The SPI can be delivered to any connected PE that is participating in distribution of the interrupt group. The Distributor, rather than software, selects the target PE. The target can therefore vary each time the interrupt is signaled. This type of routing is referred to as 1-of-N.
  • A PE can opt out of receiving 1-of-N interrupts. This is controlled by the DPG1S, DPG1NS and DPG0 bits in GICR_CTLR.

Previous Next