Arm CoreLink GIC fundamentals

In this section, we will look at the basic operation of the Arm CoreLink GICv3 and v4 interrupt controllers.

Interrupt types

The GIC can deal with four different types of interrupt sources:

  • Shared Peripheral Interrupt (SPI). Peripheral interrupts that can be delivered to any connected core.
  • Private Peripheral Interrupt (PPI). Peripheral interrupts that are private to one core. An example of a PPI is an interrupt from the Generic Timer.
  • Software Generated Interrupt (SGI). SGIs are typically used for inter-processor communication and are generated by a write to an SGI register in the GIC.
  • Locality-specific Peripheral Interrupt (LPI). LPIs were first introduced in GICv3 and have a very different programing model to the other three types of interrupt. The configuration of LPIs is covered in the Arm CoreLink Generic Interrupt Controller v3 and v4: Locality-specific Peripheral Interrupts guide.

Each interrupt source is identified by an ID number, which is referred to as an INTID. The interrupt types that are introduced in the preceding list are defined in terms of ranges of INTIDs:

INTID Interrupt Type Notes
0 - 15 SGIs Banked per PE
16 – 31
1056 – 1119 (GICv3.1)
PPIs Banked per PE
32 – 1019
4096 – 5119 (GICv3.1)
SPIs -
1020 - 1023 Special interrupt number Used to signal special cases, see Settings for each PE for more information.
1024 - 8191 Reserved -
8192 and greater LPIs The upper boundary is IMPLEMENTATION DEFINED

How interrupts are signaled to the interrupt controller

Traditionally, interrupts are signaled from a peripheral to the interrupt controller using a dedicated hardware signal, as shown in the following image:

Arm CoreLink GICv3 supports this model, but also provides an additional signaling mechanism: message-signaled interrupts (MSI). MSIs are transmitted by a write to a register in the interrupt controller, as you can see here:

Using a message to forward the interrupt from a peripheral to the interrupt controller removes the requirement for a dedicated signal for each interrupt source. This can be an advantage for designers of large systems, where potentially hundreds or even thousands of signals might be routed across an SoC and converge on the interrupt controller.

Whether an interrupt is sent as a message or using a dedicated signal has little effect on the way that the interrupt handling code handles the interrupt. Some configuration of the peripherals might be required. For example, it might be necessary to specify the address of the interrupt controller. This peripheral configuration is beyond of the scope of this guide.

In Arm CoreLink GICv3, SPIs can be message-signaled interrupts. LPIs are always message-signaled interrupts. Different registers are used for the different interrupt types, as shown in the following table:

Interrupt Type Registers
SPI GICD_SETSPI_NSR asserts an interrupt
GICD_CLRSPI_NSR de-asserts an interrupt
LPI GITS_TRANSLATER

Interrupt state machine

The interrupt controller maintains a state machine for each SPI, PPI, and SGI interrupt source. This state machine consists of four states:

  • Inactive. The interrupt source is not currently asserted.
  • Pending. The interrupt source has been asserted, but the interrupt has not yet been acknowledged by a PE.
  • Active. The interrupt source has been asserted, and the interrupt has been acknowledged by a PE.
  • Active and Pending. An instance of the interrupt has been acknowledged, and another instance is now pending.

Note: LPIs have a simpler state machine. See Taking an interrupt for more information.

The state machine is shown in the following diagram:

The life cycle of an interrupt depends on whether it is configured to be level-sensitive or edge-triggered:

  • For level-sensitive interrupts, a rising edge on the interrupt input causes the interrupt to become pending, and the interrupt is held asserted until the peripheral de-asserts the interrupt signal.
  • For edge-sensitive interrupts, a rising edge on the interrupt input causes the interrupt to become pending, but the interrupt is not held asserted.

Level sensitive interrupts

The following diagram shows how the interrupt state transitions correspond to the interrupt signal:

Considering each state transition in turn:

  • Inactive to pending. An interrupt transitions from inactive to pending when the interrupt source is asserted. At this point the GIC asserts the interrupt signal to the PE, if the interrupt is enabled and is of sufficient priority.
  • Pending to active and pending. An interrupt transitions from pending to active and pending when a Processor Element (PE) acknowledges the interrupt by reading one of the Interrupt Acknowledge Registers (IARs) in the CPU interface. This read is typically part of an interrupt handling routine that executes after an interrupt exception is taken. At this point the GIC de-asserts the interrupt signal to the PE.
  • Active and pending to active. An interrupt transitions from active and pending to active when the peripheral de-asserts the interrupt signal. This typically happens in response software writing to a status register in the peripheral.
  • Active to inactive. An interrupt goes from active to inactive when the PE writes to one of the End of Interrupt Registers (EOIRs) in the CPU interface. This indicates that the PE has finished handling the interrupt.

Edge-triggered interrupts

The following diagram shows how the interrupt state transitions correspond to the interrupt signal:

Considering each state transition in turn:

  • Inactive to pending. An interrupt transitions from inactive to pending when the interrupt source is asserted. At this point the GIC asserts the interrupt signal to the PE, if the interrupt is enabled and is of sufficient priority.
  • Pending to active. An interrupt transitions from pending to active when a PE acknowledges the interrupt by reading one of the IARs in the CPU interface. This read is typically part of an interrupt handling routine that executes after an interrupt exception is taken. However, software can also poll the IARs. At this point the GIC de-asserts the interrupt signal to the PE.
  • Active to active and pending. An interrupt goes from active to active and pending if the peripheral re-asserts the interrupt signal.
  • Active and pending to pending. An interrupt goes from active and pending to pending when the PE writes to one of the EOIRs in the CPU interface. This indicates that the PE has finished handling the first instance of the interrupt. At this point the GIC re-asserts the interrupt signal to the PE.

Target interrupts

The Arm architecture assigns each PE a hierarchal identifier that is called an affinity. The GIC uses affinity values to target interrupts at a specific core.

An affinity is a 32-bit value that is split into four fields:

<affinity level 3>.<affinity level 2>.<affinity level 1>.<affinity level 0>

The affinity of a PE is reported in MPIDR_EL1.

The exact meaning of the different levels of affinity is defined by the specific processor and SoC. For example, Arm Cortex-A53 and Arm Cortex-A57 processors use:

<group of groups>.<group of processors>.<processor>.<core>

Later designs, like those used in Arm Cortex-A55 and Arm Cortex-A76 processors, use:

<group of processors>.<processor>.<core>.<thread>

It is highly unlikely that all the possible nodes exist in a single implementation. For example, an SoC for a mobile device could have a layout like this:

0.0.0.[0:3] Cores 0 to 3 of a Cortex-A53 processor

0.0.1.[0:1] Cores 0 to 1 of a Cortex-A57 processor

Note: AArch32 state, and Armv7-A, can only support three levels of affinity. This means that a design that uses AArch32 state is limited to a single node at affinity level 3 (0.x.y.z). GICD_TYPER.A3V indicates whether the interrupt controller can support multiple level 3 nodes.

Security model

The Arm CoreLink GICv3 architecture supports Arm TrustZone technology. Each INTID must be assigned a group and security setting by software. GICv3 supports three combinations of settings, as you can see in the following table:

Interrupt Type Example use
Secure Group 0 Interrupts for EL3 (Secure Firmware)
Secure Group 1 Interrupts for Secure EL1 (Trusted OS)
Non-secure Group 1 Interrupts for the Non-secure state (OS or Hypervisor)

Group 0 interrupts are always signaled as FIQs. Group 1 interrupts are signaled as either IRQs or FIQs, depending on the current Security state and Exception level of the PE, as you can see here:

EL and Security state of PE Group 0 Group 1
Secure Non-secure
Secure EL0/1 FIQ IRQ FIQ
Non-secure EL0/1/2 FIQ FIQ IRQ
EL3 FIQ FIQ FIQ

These rules are designed to complement the AArch64 security state and Exception level routing controls. The following diagram shows a simplified software stack, and what happens when different types of interrupt are signaled while executing at EL0:

In this example, IRQs are routed to EL1 (SCR_EL3.IRQ==0) and FIQs routed to EL3 (SCR_EL3.FIQ==1) . Considering the rules described above, while executing at EL1 or EL0 a Group 1 interrupt for the current Security state is taken as an IRQ.

An interrupt for the other Security state triggers an FIQ, and the exception is taken to EL3. This allows software executing at EL3 to perform the necessary context switch.

Impact on software

Software controls the allocation of INTIDs to interrupt groups when configuring the interrupt controller. Only software executing in Secure state can allocate INTIDs to interrupt groups.

Typically, only software executing in Secure state should be able to access the settings and state of Secure interrupts: Group 0 and Secure Group 1.

Accesses from Non-secure state to Secure interrupt settings and state can be enabled. This is controlled individually for each INTID, using the GICD_NSACRn and GICR_NSACR registers.

Note: LPIs are always treated as Non-secure Group 1 interrupts.

Support for single Security state

GICv3 supports the Arm TrustZone technology, but the use of TrustZone is OPTIONAL. This means that you can configure your implementation to have either a single Security state or two Security states:

  • GICD_CTLR.DS == 0 Two Security states, Secure and Non-secure, are supported.
  • GICD_CTLR.DS == 1 Only a single Security state is supported.

Configure the GIC to use the same number of Security states as the attached PEs. Typically, this means that the GIC will support two Security states when connected to Arm Cortex-A profile processors and one Security state when connected to Arm Cortex-R profile processors.

Programmer’s model

The register interface of a GICv3 interrupt controller is split into three groups:

  • Distributor interface
  • Redistributor interface
  • CPU interface

These interfaces are illustrated in the following diagram:

In general, the Distributor and the Redistributors are used to configure interrupts, and the CPU interface is used to handle interrupts.

Distributor (GICD_*)

The Distributor registers are memory-mapped and used to configure SPIs. The Distributor provides a programming interface for:

  • Interrupt prioritization and distribution of SPIs
  • Enable and disable SPIs
  • Set the priority level of each SPI
  • Route information for each SPI
  • Set each SPI to be level-sensitive or edge-triggered
  • Generate message-signaled SPIs
  • Control the active and pending state of SPIs
  • Determine the programmer’s model that is used in each Security state: affinity routing or legacy.

Redistributors (GICR_*)

There is one Redistributor per connected core. The Redistributors provide a programming interface to:

  • Enable and disable SGIs and PPIs
  • Set the priority level of SGIs and PPIs
  • Set each PPI to be level-sensitive or edge-triggered
  • Assign each SGI and PPI to an interrupt group
  • Control the state of SGIs and PPIs
  • Control the base address for the data structures in memory that support the associated interrupt properties and pending state for LPIs
  • Provide power management support for the connected PE

CPU interfaces (ICC_*_ELn)

Each core contains a CPU interface, which are system registers that are used during interrupt handling. The CPU interfaces provide a programming interface to:

  • Provide general control and configuration to enable interrupt handling
  • Acknowledge an interrupt
  • Perform a priority drop and deactivation of interrupts
  • Set an interrupt priority mask for the PE
  • Define the preemption policy for the PE
  • Determine the highest priority pending interrupt for the PE

In Arm CoreLink GICv3, the CPU Interface registers are accessed as System registers: ICC_*_ELn.

Software must enable the System register interface before using these registers. This is controlled by the SRE bit in the ICC_SRE_ELn registers, where n specifies the Exception level: EL1-EL3.

Previous Next