Interrupt Handling
12.2 The Generic Interrupt Controller
The GIC architecture defines a Generic Interrupt Controller (GIC) that comprises a set of hardware resources for managing interrupts in a single or multi-core system. The GIC provides memory-mapped registers that can be used to manage interrupt sources and behavior and (in multi-core systems) for routing interrupts to individual cores. It enables software to mask, enable and disable interrupts from individual sources, to prioritize (in hardware) individual sources and to generate software interrupts. It also provides support for the TrustZone Security Extensions described in Chapter 21 Security. The GIC accepts interrupts asserted at the system level and can signal them to each core it is connected to, potentially resulting in an IRQ or FIQ exception being taken.
From a software perspective, a GIC has two major functional blocks: Distributor
to which all interrupt sources in the system are wired. The distributor has registers to control the properties of individual interrupts such as priority, state, security, routing information and enable status. The distributor determines which interrupt is to be forwarded to a core, through the attached CPU interface.
CPU Interface
through which a core receives an interrupt. The CPU interface hosts registers to mask, identify and control states of interrupts forwarded to that core. There is a separate CPU interface for each core in the system.
Interrupts are identified in the software by a number, called an interrupt ID. An interrupt ID uniquely corresponds to an interrupt source. Software can use the interrupt ID to identify the source of interrupt and to invoke the corresponding handler to service the interrupt. The exact interrupt ID presented to the software is determined by the system design,
Interrupts can be of a number of different types: Software Generated Interrupt (SGI)
This is generated explicitly by software by writing to a dedicated distributor register, the Software Generated Interrupt Register (ICDSGIR). It is most commonly used for inter-core communication. SGIs can be targeted at all, or a selected group of cores in the system. Interrupt numbers 0-15 are reserved for this. The exact interrupt number used for communication is at the discretion of software.
Private Peripheral Interrupt (PPI)
This is generated by a peripheral that is private to an individual core. Interrupt numbers 16-31 are reserved for this. These identify interrupt sources private to the core, and is independent of the same source on another core, for example, per-core timer.
Shared Peripheral Interrupt (SPI)
This is generated by a peripheral that the Interrupt Controller can route to more than one core. Interrupt numbers 32-1020 are used for this. SPIs are used to signal interrupts from various peripherals accessible across the whole the system. Interrupts can either be edge-triggered (considered to be asserted when the Interrupt Controller detects a rising edge on the relevant input – and to remain asserted until cleared) or
level-sensitive (considered to be asserted only when the relevant input to the Interrupt Controller is HIGH).
Interrupt Handling
An interrupt can be in a number of different states:
• Inactive – this means that the interrupt is not asserted yet.
• Pending – this means that the interrupt source has been asserted, but is waiting to be handled by a core. Pending interrupts are candidates to be forwarded to the CPU interface and then later on to the core.
• Active – this describes an interrupt that has been acknowledged by a core and is currently being serviced.
• Active and pending – this describes the situation where a core is servicing the interrupt and the GIC also has a pending interrupt from the same source.
The priority and list of cores to which an interrupt can be delivered to are all configured in the distributor. An interrupt asserted to the distributor by a peripheral will be marked in Pending state (or Active and Pending if was already Active). The distributor determines the highest priority pending interrupt that can be delivered to a core and forwards that to the CPU interface of the core. At the CPU interface, the interrupt is in turn signalled to the core, at which point the core takes the FIQ or IRQ exception.
The core executes the exception handler in response. The handler must query the interrupt ID from a CPU interface register and begin servicing the interrupt source. When finished, the handler must write to a CPU interface register to report the end of processing. Later on the CPU interface is prepared to signal the next interrupt forwarded to it by the distributor.
While servicing an interrupt, the distributor cycles through Pending, Active states, ending in Inactive state when it has finished. The state of an interrupt is therefore reflected in the distributor registers.
More detailed information on GIC behavior can be found in the TRMs for the individual processor types and in the ARM Generic Interrupt Controller Architecture specification.
12.2.1 Configuration
The GIC is accessed as a memory-mapped peripheral. All cores can access the common distributor block, but the CPU interface is banked, that is, each core uses the same address to access its own private CPU interface. It is not possible for a core to access the CPU interface of another core. See Handling interrupts in an SMP system on page 18-14 for more details. The distributor hosts a number of registers that you can use to configure the properties of individual interrupts. These configurable properties are:
• An interrupt priority. The distributor uses this to determine which interrupt is next forwarded to the CPU interface.
• An interrupt configuration. This determines if an interrupt is level- or edge-sensitive. • An interrupt target. This determines a list of cores to which an interrupt can be forwarded. • Interrupt enable or disable status. Only those interrupts that are enabled in the distributor
are eligible to be forwarded when they become pending.
• Interrupt security determines whether the interrupt is allocated to Secure or Normal world software.
Interrupt Handling
The CPU interfaces on each core helps with fine-tuning interrupt control and handling on that core:
12.2.2 Initialization
Both the distributor and the CPU interfaces are disabled at reset.The GIC must be initialized after reset before it can deliver interrupts to the core.
In the distributor, software must configure the priority, target, security and enable individual interrupts. The distributor block must subsequently be enabled through its control register. For each CPU interface, software must program the priority mask and preemption settings. Each CPU interface block itself must be enabled through its control register. This prepares the GIC to deliver interrupts to the core.
Before interrupts are expected in the core, software prepares the core to take interrupts by setting a valid interrupt vector in the vector table, and clearing interrupt masks bits in the CPSR. The entire interrupt mechanism in the system can be disabled by disabling the distributor block. Interrupt delivery to an individual core can be disabled by disabling its CPU interface block, or by setting mask bits in CPSR of that core. Individual interrupts can also be disabled (or enabled) in the distributor.
For an interrupt to reach the core, the individual interrupt, distributor and CPU interface must all be enabled, and the CPSR interrupt mask bits cleared.
12.2.3 Interrupt handling
When the core takes an interrupt, it jumps to the top-level interrupt vector obtained from the vector table and begins execution.
The top-level interrupt handler reads the Interrupt Acknowledge Register from the CPU Interface block to obtain the interrupt ID.
As well as returning the interrupt ID, the read causes the interrupt to be marked as active in the distributor. Once the interrupt ID is known (identifying the interrupt source), the top-level handler can now dispatch a device-specific handler to service the interrupt.
When the device-specific handler finishes execution, the top-level handler writes the same interrupt ID to the End of Interrupt register in the CPU Interface block, indicating the end of interrupt processing.
Apart from removing the active status, which will make the final interrupt status either Inactive, or Pending (if the state was Active and Pending), this will enable the CPU Interface to forward more pending interrupts to the core. This concludes the processing of a single interrupt. It is possible for there to be more than one interrupt waiting to be serviced on the same core, but the CPU Interface can signal only one interrupt at a time. The top-level interrupt handler repeats the above sequence until it reads the special interrupt ID value 1023, indicating that there are no more interrupts pending at this core. This special interrupt ID is called the spurious interrupt ID. The spurious interrupt ID is a reserved value, and cannot be assigned to any device in the system. When the top-level handler has read the spurious interrupt ID it can complete its execution, and prepare the core to resume the task it was doing before taking the interrupt.
Chapter 13
Boot Code
This chapter considers the boot code running in an ARM processor based system, and focuses on two distinct areas:
• Code to be run immediately after the core comes out of reset, on a so-called bare-metal system, that is, one in which code is run without the use of an operating system. This is a situation that is often encountered when first starting up a chip or system.
Boot Code