Kernelite 0.1.0
Kernelite is a minimalist, educational operating system kernel built from scratch. The project aims to recreate core components of the Linux architecture to explore the fundamentals of operating system design and hardware-software interaction.
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Enumerations | Functions | Variables
gicv3.c File Reference

ARM GICv3 interrupt controller support. More...

#include "gicv3.h"
#include "asm/asm_helper.h"
#include "fdt/fdt.h"
#include "icu/icu.h"
#include "linker/symbols.h"
#include "mem_layout/mem_layout.h"
#include "page_table/page_table.h"
#include "utils/kprintf.h"
#include "utils/string.h"
#include "utils/utils.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Include dependency graph for gicv3.c:

Data Structures

union  gicd_ctlr_t
 GICv3 Distributor Control Register, GICD_CTLR (0x0000). More...
 
union  gicd_typer_t
 GICv3 Distributor Type Register, GICD_TYPER (0x0004, RO). More...
 
union  gicd_iidr_t
 Distributor Implementer Identification Register, GICD_IIDR (0x0008, RO). More...
 
union  gicd_ipriorityr_t
 Interrupt Priority Register entry, GICD_IPRIORITYR<n>. More...
 
union  gicd_irouter_t
 Interrupt Routing Register entry, GICD_IROUTER<n>. More...
 
union  gicd_isenabler_t
 GICD_ISENABLER<n> — Distributor Interrupt Set-Enable Registers (offset 0x0100 + 4n, RW) More...
 
union  gicd_igroupr_t
 GICD_IGROUPR<n> — Distributor Interrupt Group Registers (offset 0x0080 + 4n, RW) More...
 
union  gicd_igrpmodr_t
 GICD_IGRPMODR<n> — Distributor Interrupt Group Modifier Registers (offset 0x0D00 + 4n, RW) More...
 
union  gicr_waker_t
 GICR_WAKER — Redistributor Wake Register (RD frame, offset 0x0014, RW) More...
 
union  gicr_isenabler0_t
 GICR_ISENABLER0 — Redistributor Interrupt Set-Enable Register 0 (SGI frame, offset 0x0100, RW) More...
 
union  gicr_igroupr0_t
 GICR_IGROUPR0 — Redistributor Interrupt Group Register 0 (SGI frame, offset 0x0080, RW) More...
 
union  gicr_igrpmodr0_t
 GICR_IGRPMODR0 — Redistributor Interrupt Group Modifier Register 0 (SGI frame, offset 0x0D00, RW) More...
 
union  gicr_ipriorityr_t
 GICR_IPRIORITYR — Redistributor Interrupt Priority Registers (SGI frame, offset 0x0400-0x041C, RW) More...
 
union  icc_sre_el1_t
 ICC_SRE_EL1 — Interrupt Controller System Register Enable (EL1). More...
 
union  icc_ctlr_el1_t
 ICC_CTLR_EL1 — Interrupt Controller Control Register (EL1). More...
 
union  icc_pmr_el1_t
 ICC_PMR_EL1 — Interrupt Controller Priority Mask Register (EL1). More...
 
union  icc_bpr1_el1_t
 ICC_BPR1_EL1 — Interrupt Controller Binary Point Register 1 (EL1). More...
 
union  icc_igrpen1_el1_t
 ICC_IGRPEN1_EL1 — Interrupt Controller Group 1 Enable (EL1). More...
 
union  icc_iar1_el1_t
 ICC_IAR1_EL1 — Interrupt Controller Interrupt Acknowledge Register 1. More...
 
union  icc_eoir1_el1_t
 ICC_EOIR1_EL1 — Interrupt Controller End Of Interrupt Register 1. More...
 
struct  gicv3_memap_t
 Memory map for GICv3 register regions. More...
 

Macros

#define MAX_INT_ID   1024
 Maximum number of interrupt INTIDs supported by the dispatch table. Covers SGIs (0-15), PPIs (16-31), and SPIs (32-1019). INTIDs 1020-1023 are reserved for spurious interrupt signalling and are never dispatched.
 
#define GICR_IPRIORITYR_COUNT   8U
 Number of GICR_IPRIORITYR registers per redistributor (8 regs x 4 INTIDs each = 32 SGI/PPI priority fields).
 

Typedefs

typedef union gicd_ctlr_t gicd_ctlr_t
 GICv3 Distributor Control Register, GICD_CTLR (0x0000).
 
typedef union gicd_typer_t gicd_typer_t
 GICv3 Distributor Type Register, GICD_TYPER (0x0004, RO).
 
typedef union gicd_iidr_t gicd_iidr_t
 Distributor Implementer Identification Register, GICD_IIDR (0x0008, RO).
 
typedef union gicd_ipriorityr_t gicd_ipriorityr_t
 Interrupt Priority Register entry, GICD_IPRIORITYR<n>.
 
typedef enum gicd_irm_t gicd_irm_t
 Interrupt Routing Mode (IRM) for GICD_IROUTER<n>[31].
 
typedef union gicd_irouter_t gicd_irouter_t
 Interrupt Routing Register entry, GICD_IROUTER<n>.
 
typedef union gicd_isenabler_t gicd_isenabler_t
 GICD_ISENABLER<n> — Distributor Interrupt Set-Enable Registers (offset 0x0100 + 4n, RW)
 
typedef gicd_isenabler_t gicd_icenabler_t
 Distributor Interrupt Clear-Enable Registers, GICD_ICENABLER<n> (offset 0x0180 + 4n, RW).
 
typedef union gicd_igroupr_t gicd_igroupr_t
 GICD_IGROUPR<n> — Distributor Interrupt Group Registers (offset 0x0080 + 4n, RW)
 
typedef union gicd_igrpmodr_t gicd_igrpmodr_t
 GICD_IGRPMODR<n> — Distributor Interrupt Group Modifier Registers (offset 0x0D00 + 4n, RW)
 
typedef union gicr_waker_t gicr_waker_t
 GICR_WAKER — Redistributor Wake Register (RD frame, offset 0x0014, RW)
 
typedef union gicr_isenabler0_t gicr_isenabler0_t
 GICR_ISENABLER0 — Redistributor Interrupt Set-Enable Register 0 (SGI frame, offset 0x0100, RW)
 
typedef union gicr_igroupr0_t gicr_igroupr0_t
 GICR_IGROUPR0 — Redistributor Interrupt Group Register 0 (SGI frame, offset 0x0080, RW)
 
typedef union gicr_igrpmodr0_t gicr_igrpmodr0_t
 GICR_IGRPMODR0 — Redistributor Interrupt Group Modifier Register 0 (SGI frame, offset 0x0D00, RW)
 
typedef union gicr_ipriorityr_t gicr_ipriorityr_t
 GICR_IPRIORITYR — Redistributor Interrupt Priority Registers (SGI frame, offset 0x0400-0x041C, RW)
 
typedef union icc_sre_el1_t icc_sre_el1_t
 ICC_SRE_EL1 — Interrupt Controller System Register Enable (EL1).
 
typedef union icc_ctlr_el1_t icc_ctlr_el1_t
 ICC_CTLR_EL1 — Interrupt Controller Control Register (EL1).
 
typedef union icc_pmr_el1_t icc_pmr_el1_t
 ICC_PMR_EL1 — Interrupt Controller Priority Mask Register (EL1).
 
typedef union icc_bpr1_el1_t icc_bpr1_el1_t
 ICC_BPR1_EL1 — Interrupt Controller Binary Point Register 1 (EL1).
 
typedef union icc_igrpen1_el1_t icc_igrpen1_el1_t
 ICC_IGRPEN1_EL1 — Interrupt Controller Group 1 Enable (EL1).
 
typedef union icc_iar1_el1_t icc_iar1_el1_t
 ICC_IAR1_EL1 — Interrupt Controller Interrupt Acknowledge Register 1.
 
typedef union icc_eoir1_el1_t icc_eoir1_el1_t
 ICC_EOIR1_EL1 — Interrupt Controller End Of Interrupt Register 1.
 
typedef struct gicv3_memap_t gicv3_memap_t
 Memory map for GICv3 register regions.
 

Enumerations

enum  gicd_irm_t { GICD_IRM_AFFINITY = 0b0 , GICD_IRM_ANY_PE = 0b1 }
 Interrupt Routing Mode (IRM) for GICD_IROUTER<n>[31]. More...
 

Functions

static volatile gicd_ctlr_tget_gicd_ctlr (void)
 Get GICD_CTLR register.
 
static volatile gicd_typer_tget_gicd_typer (void)
 Get GICD_TYPER register.
 
static volatile gicd_iidr_tget_gicd_iidr (void)
 Get GICD_IIDR register.
 
static volatile gicd_igroupr_tget_gicd_igroupr (const uint32_t n)
 Get GICD_IGROUPR<n> (offset 0x0080 + 4n, RW). Group assignment register for INTIDs [32n+31:32n].
 
static volatile gicd_igrpmodr_tget_gicd_igrpmodr (const uint32_t n)
 Get GICD_IGRPMODR<n> (offset 0x0D00 + 4n, RW). Group modifier register for INTIDs [32n+31:32n].
 
static volatile gicd_ipriorityr_tget_gicd_ipriorityr (const uint32_t n)
 Get GICD_IPRIORITYR<n> (offset 0x0400 + 4n, RW). Priority register covering INTIDs [4n+3:4n].
 
static volatile gicd_irouter_tget_gicd_irouter (const uint32_t intid)
 Get GICD_IROUTER<n> (offset 0x6000 + 8n, RW). Affinity routing register for SPI INTID n (n >= 32).
 
static volatile gicd_isenabler_tget_gicd_isenabler (const uint32_t n)
 Get GICD_ISENABLER<n> (offset 0x0100 + 4n, RW). Set-Enable register for INTIDs [32n+31:32n].
 
static volatile gicd_icenabler_tget_gicd_icenabler (const uint32_t n)
 Get GICD_ICENABLER<n> (offset 0x0180 + 4n, RW). Clear-Enable register for INTIDs [32n+31:32n].
 
static virt_addr get_redist_base (const uint32_t cpu_num)
 Get Re-disturbutor base.
 
static virt_addr get_gicr_sgi_base (const uint32_t cpu_num)
 Get the SGI frame base address for the given Redistributor.
 
static volatile gicr_waker_tget_gicr_waker (const uint32_t cpu_num)
 Get GICR_WAKER register (RD frame, offset 0x0014). Controls Redistributor wake state. Clear ProcessorSleep then poll ChildrenAsleep == 0 before enabling interrupts.
 
static volatile gicr_isenabler0_tget_gicr_isenabler0 (const uint32_t cpu_num)
 Get GICR_ISENABLER0 register (SGI frame, offset 0x0100, RW).
 
static volatile gicr_igroupr0_tget_gicr_igroupr0 (const uint32_t cpu_num)
 Get GICR_IGROUPR0 register (SGI frame, offset 0x0080, RW).
 
static volatile gicr_igrpmodr0_tget_gicr_igrpmodr0 (const uint32_t cpu_num)
 Get GICR_IGRPMODR0 register (SGI frame, offset 0x0D00, RW).
 
static volatile gicr_ipriorityr_tget_gicr_ipriorityr (const uint32_t cpu_num, const uint32_t n)
 Get a GICR_IPRIORITYR register (SGI frame, offset 0x0400+n*4, RW).
 
static void print_gicd_typer (void)
 Print decoded GICD_TYPER register for debugging.
 
static void print_gicd_iidr (void)
 Dump and decode the GICD_IIDR register for debugging.
 
static void print_gicd_ctlr (void)
 Dump and decode the GICD_CTLR register for debugging.
 
static void print_gicr_waker (const uint32_t cpu_num)
 Dump and decode the GICR_WAKER register for debugging.
 
static void print_gicr_isenabler0 (const uint32_t cpu_num)
 Dump and decode GICR_ISENABLER0 for the given PE.
 
static void print_gicr_igroup (const uint32_t cpu_num)
 Dump and decode GICR_IGROUPR0 and GICR_IGRPMODR0 together.
 
static void print_gicr_ipriorityr (const uint32_t cpu_num)
 Dump and decode all GICR_IPRIORITYR registers for the given PE.
 
static void print_mpidr_el1 (void)
 Dump and decode MPIDR_EL1 for the current PE.
 
static void print_icc_sre_el1 (void)
 Dump and decode ICC_SRE_EL1 for the current PE.
 
static void print_icc_ctlr_el1 (void)
 Dump and decode ICC_CTLR_EL1 for the current PE.
 
static void print_icc_pmr_el1 (void)
 Dump and decode ICC_PMR_EL1 for the current PE.
 
static void print_icc_bpr1_el1 (void)
 Dump and decode ICC_BPR1_EL1 for the current PE.
 
static void print_icc_igrpen1_el1 (void)
 Dump and decode ICC_IGRPEN1_EL1 for the current PE.
 
static void set_up_gicd_ctrl (void)
 Enable Group 1 NS interrupts and affinity routing on the distributor.
 
static void set_gicr_waker (uint32_t cpu_num)
 Wake the redistributor for a PE and wait until it acknowledges.
 
static void enable_icc_sys_reg_interface (void)
 Set ICC_SRE_EL1.SRE to enable the System Register interface for the CPU interface.
 
static void set_core_priority_threshold (uint8_t threshold)
 Set the priority mask threshold for the current PE.
 
static void unmask_all_core_interrupts (void)
 Unmask all interrupts on the current PE.
 
static void mask_all_core_interrupts (void)
 Mask all interrupts on the current PE.
 
static void set_core_binary_point (uint8_t binary_point)
 Configure ICC_BPR1_EL1 for the current PE.
 
static void set_core_min_binary_point (void)
 Configure ICC_BPR1_EL1 to the minimum allowed value for this PE.
 
static void set_combined_eoi_mode (void)
 Enable combined EOI mode on the current PE.
 
static void enable_grp1_interrupts (void)
 Enable Group 1 interrupt forwarding on the current PE.
 
static bool map_continuous (phy_addr p_base, virt_addr v_base, size_t size, page_permissions_t perms, mem_type_t mem_type)
 Map a contiguous physical memory region to a virtual address range.
 
static bool enable_sgi_ppi (const uint32_t cpu_num, const uint32_t intid)
 Enable forwarding of a single SGI or PPI for the given PE.
 
static bool set_sgi_ppi_group1_ns (const uint32_t cpu_num, const uint32_t intid)
 Assign a single SGI or PPI to Group 1 Non-secure for the given PE.
 
static bool set_sgi_ppi_priority (const uint32_t cpu_num, const uint32_t intid, const uint8_t priority)
 Set the priority of a single SGI or PPI for the given PE.
 
static bool configure_sgi_ppi (const uint32_t cpu_num, const uint32_t intid, const uint8_t priority)
 Configure a single SGI or PPI for Group 1 NS delivery.
 
static bool enable_spi (const uint32_t intid)
 Enable forwarding of a single SPI for delivery.
 
static bool set_spi_group1_ns (const uint32_t intid)
 Assign a single SPI to Group 1 Non-secure.
 
static bool set_spi_priority (const uint32_t intid, const uint8_t priority)
 Set the priority of a single SPI.
 
static bool set_spi_route (const uint32_t intid, const uint32_t aff0, const uint32_t aff1, const uint32_t aff2, const uint32_t aff3)
 Route a single SPI to a specific PE via affinity.
 
static bool configure_spi (const uint32_t intid, const uint8_t priority, const uint32_t aff0, const uint32_t aff1, const uint32_t aff2, const uint32_t aff3)
 Configure a single SPI for Group 1 NS delivery to a specific PE.
 
static void unmask_all_exceptions (void)
 Unmask all exceptions on the current PE.
 
static void mask_all_exceptions (void)
 Mask all exceptions on the current PE.
 
static volatile gicr_isenabler0_tget_gicr_icenabler0 (const uint32_t cpu_num)
 Get GICR_ICENABLER0 register (SGI frame, offset 0x0180, RW).
 
static bool disable_sgi_ppi (const uint32_t cpu_num, const uint32_t intid)
 Disable forwarding of a single SGI or PPI for the given PE.
 
static bool clear_sgi_ppi_group (const uint32_t cpu_num, const uint32_t intid)
 Assign a single SGI or PPI to Group 0 for the given PE.
 
static bool clear_sgi_ppi_priority (const uint32_t cpu_num, const uint32_t intid)
 Reset the priority of a single SGI or PPI to 0 for the given PE.
 
static bool unconfigure_sgi_ppi (const uint32_t cpu_num, const uint32_t intid)
 Fully unconfigure a single SGI or PPI for the given PE.
 
static bool disable_spi (const uint32_t intid)
 Disable forwarding of a single SPI.
 
static bool clear_spi_group (const uint32_t intid)
 Reset the Group assignment of a single SPI to Group 0.
 
static bool clear_spi_priority (const uint32_t intid)
 Reset the priority of a single SPI to 0.
 
static bool clear_spi_route (const uint32_t intid)
 Reset the affinity routing of a single SPI to PE 0.0.0.0.
 
static bool unconfigure_spi (const uint32_t intid)
 Fully unconfigure a single SPI.
 
void gicv3_init (const void *fdt)
 Initialize the ARM GICv3 interrupt controller.
 
bool gicv3_register_irq (uint32_t irq_num, handler_data_t handler_data)
 Register a handler for a hardware interrupt source and enable it.
 
void gicv3_unregister_irq (uint32_t irq_num)
 Unregister a handler for a hardware interrupt source and disable it.
 
void gicv3_handle_irq (void)
 EL1 IRQ handler.
 

Variables

static handler_data_t dispatch_table [MAX_INT_ID]
 Global interrupt dispatch table indexed by INTID.
 
static volatile struct gicv3_memap_t memap
 Represents the memory-mapped base address of the GICv3 interrupt controller.
 

Detailed Description

ARM GICv3 interrupt controller support.

Provides an abstraction layer for initializing and managing the ARM GICv3 interrupt controller. This file is intentionally minimal and may be extended with platform-specific hardware access routines.

Author
Abhin Parekadan Jose
Date
2026-06-14

Typedef Documentation

◆ gicd_ctlr_t

typedef union gicd_ctlr_t gicd_ctlr_t

GICv3 Distributor Control Register, GICD_CTLR (0x0000).

Bit layout per Arm IHI 0069. On QEMU virt the GIC runs with a single security state (DS reads as 1, RAO/WI), in which case ARE_S/ARE_NS/ EnableGrp1S are not meaningful and only EnableGrp0/EnableGrp1NS/DS/RWP are relevant.

◆ gicd_icenabler_t

Distributor Interrupt Clear-Enable Registers, GICD_ICENABLER<n> (offset 0x0180 + 4n, RW).

Same layout as gicd_isenabler_t. Writing 1 to a bit disables forwarding of the corresponding INTID; writing 0 has no effect.

◆ gicd_igroupr_t

GICD_IGROUPR<n> — Distributor Interrupt Group Registers (offset 0x0080 + 4n, RW)

Controls Group 0 vs Group 1 assignment for each SPI. Register n covers INTIDs [32n+31 : 32n].

Combined with GICD_IGRPMODR<n>: IGROUPR=0, IGRPMODR=0 → Group 0 IGROUPR=1, IGRPMODR=0 → Group 1 Non-secure IGROUPR=0, IGRPMODR=1 → Group 1 Secure IGROUPR=1, IGRPMODR=1 → Reserved

Reset to 0 on GIC reset (all INTIDs default to Group 0).

◆ gicd_igrpmodr_t

GICD_IGRPMODR<n> — Distributor Interrupt Group Modifier Registers (offset 0x0D00 + 4n, RW)

Modifier bits working in conjunction with GICD_IGROUPR<n> to select between Group 1 Secure and Group 1 Non-secure for each SPI. Register n covers INTIDs [32n+31 : 32n].

Reset to 0 on GIC reset.

◆ gicd_iidr_t

typedef union gicd_iidr_t gicd_iidr_t

Distributor Implementer Identification Register, GICD_IIDR (0x0008, RO).

Identifies the implementer and product of the Distributor. Useful as a diagnostic during bring-up (e.g. confirming an Arm GICv3 implementation), but not required for normal operation.

◆ gicd_ipriorityr_t

Interrupt Priority Register entry, GICD_IPRIORITYR<n>.

Each register holds the priority of four consecutive INTIDs: for register index n, priority0..3 correspond to INTIDs 4n..4n+3. Lower values are higher priority. The number of bits actually implemented is IMPLEMENTATION DEFINED; unimplemented low-order bits are RAZ/WI.

◆ gicd_irm_t

typedef enum gicd_irm_t gicd_irm_t

Interrupt Routing Mode (IRM) for GICD_IROUTER<n>[31].

Controls how Shared Peripheral Interrupts (SPIs) are routed in a multi-core affinity hierarchy.

The IRM bit determines whether routing is performed using an explicit affinity path (Aff3.Aff2.Aff1.Aff0) or dynamically to any participating PE.

◆ gicd_irouter_t

Interrupt Routing Register entry, GICD_IROUTER<n>.

Selects the target PE for SPI INTID n by affinity, or broadcasts it to all participating PEs if IRM is set. On a single-core system, leaving the entire register zero routes the interrupt to PE 0.0.0.0.

◆ gicd_isenabler_t

GICD_ISENABLER<n> — Distributor Interrupt Set-Enable Registers (offset 0x0100 + 4n, RW)

Each bit enables forwarding of the corresponding SPI INTID. Register n covers INTIDs [32n+31 : 32n].

GICD_ISENABLER0 → INTIDs 0-31 (SGI/PPI range, RAZ/WI) GICD_ISENABLER1 → INTIDs 32-63 (SPIs start here) GICD_ISENABLER2 → INTIDs 64-95 ... and so on.

Writing 1 enables the interrupt. Writing 0 has no effect. Use GICD_ICENABLER<n> to disable. Resets to 0 on GIC reset.

◆ gicd_typer_t

typedef union gicd_typer_t gicd_typer_t

GICv3 Distributor Type Register, GICD_TYPER (0x0004, RO).

Bit layout per Arm IHI 0069. Fields relating to extended SPIs, LPIs, and the 1-of-N/range-selector extensions are decoded for completeness but are not exercised by this driver, which targets a single PE without an ITS.

◆ gicr_igroupr0_t

GICR_IGROUPR0 — Redistributor Interrupt Group Register 0 (SGI frame, offset 0x0080, RW)

Controls the Group assignment of each SGI and PPI for this PE. Each bit selects whether the corresponding INTID belongs to Group 0 or Group 1.

Bit values: 0 = Group 0 (secure, signaled as FIQ) 1 = Group 1 (non-secure or secure depending on GICR_IGRPMODR0)

Combined with GICR_IGRPMODR0: IGROUPR0=0, IGRPMODR0=0 → Group 0 IGROUPR0=1, IGRPMODR0=0 → Group 1 Non-secure IGROUPR0=0, IGRPMODR0=1 → Group 1 Secure IGROUPR0=1, IGRPMODR0=1 → Reserved

Reset to 0 on GIC reset (all SGIs/PPIs default to Group 0).

◆ gicr_igrpmodr0_t

GICR_IGRPMODR0 — Redistributor Interrupt Group Modifier Register 0 (SGI frame, offset 0x0D00, RW)

Modifier bits that work in conjunction with GICR_IGROUPR0 to select between Group 1 Secure and Group 1 Non-secure for each SGI and PPI.

Combined with GICR_IGROUPR0: IGROUPR0=0, IGRPMODR0=0 → Group 0 IGROUPR0=1, IGRPMODR0=0 → Group 1 Non-secure IGROUPR0=0, IGRPMODR0=1 → Group 1 Secure IGROUPR0=1, IGRPMODR0=1 → Reserved

Reset to 0 on GIC reset.

◆ gicr_ipriorityr_t

GICR_IPRIORITYR — Redistributor Interrupt Priority Registers (SGI frame, offset 0x0400-0x041C, RW)

Eight 32-bit registers, each holding the 8-bit priority of 4 INTIDs. Covers all 32 SGIs and PPIs (INTIDs 0-31).

Register n covers INTIDs [4n+3 : 4n]: GICR_IPRIORITYR0 → INTIDs 0- 3 (offset 0x0400) GICR_IPRIORITYR1 → INTIDs 4- 7 (offset 0x0404) GICR_IPRIORITYR2 → INTIDs 8-11 (offset 0x0408) GICR_IPRIORITYR3 → INTIDs 12-15 (offset 0x040C) GICR_IPRIORITYR4 → INTIDs 16-19 (offset 0x0410) GICR_IPRIORITYR5 → INTIDs 20-23 (offset 0x0414) GICR_IPRIORITYR6 → INTIDs 24-27 (offset 0x0418) GICR_IPRIORITYR7 → INTIDs 28-31 (offset 0x041C)

Lower value = higher priority. Only the high bits are implemented (determined by ICC_CTLR_EL1.PRIbits); unimplemented low bits are RAZ/WI.

◆ gicr_isenabler0_t

GICR_ISENABLER0 — Redistributor Interrupt Set-Enable Register 0 (SGI frame, offset 0x0100, RW)

Each bit enables forwarding of the corresponding SGI or PPI INTID to the CPU interface for this PE.

Writing 1 enables forwarding. Writing 0 has no effect. Use GICR_ICENABLER0 to disable individual interrupts. Resets to 0 on GIC reset — all SGIs and PPIs are disabled by default and must be explicitly enabled by software.

Bit layout: [15:0] SGIs (INTIDs 0-15) : RW — reset to 0, write 1 to enable [31:16] PPIs (INTIDs 16-31) : RW — reset to 0, write 1 to enable

◆ gicr_waker_t

typedef union gicr_waker_t gicr_waker_t

GICR_WAKER — Redistributor Wake Register (RD frame, offset 0x0014, RW)

Controls and reflects the sleep/wake state of this Redistributor. The boot sequence requires clearing ProcessorSleep and then polling ChildrenAsleep until it reads 0 before the PE can receive interrupts.

◆ icc_bpr1_el1_t

ICC_BPR1_EL1 — Interrupt Controller Binary Point Register 1 (EL1).

Defines the split between the priority group field and the subpriority field for Group 1 interrupts. Controls preemption behavior.

The binary point value N means:

  • Priority group = priority[7:N+1] (determines preemption)
  • Subpriority = priority[N:0] (no preemption effect)

Setting BinaryPoint=0 gives the finest preemption granularity (all priority bits participate in preemption). Higher values reduce preemption sensitivity.

◆ icc_ctlr_el1_t

ICC_CTLR_EL1 — Interrupt Controller Control Register (EL1).

Controls the behavior of the CPU interface for the current Security state. Key fields are EOImode (split vs priority-drop-and-deactivate) and read-only capability fields populated by hardware.

Verified against ARM IHI0069 (GICv3 Architecture Specification).

◆ icc_eoir1_el1_t

ICC_EOIR1_EL1 — Interrupt Controller End Of Interrupt Register 1.

Write-only. Writing the INTID obtained from ICC_IAR1_EL1 signals End of Interrupt for the corresponding Group 1 interrupt.

When ICC_CTLR_EL1.EOImode == 0: performs priority drop AND deactivation. When ICC_CTLR_EL1.EOImode == 1: performs priority drop ONLY; a separate write to ICC_DIR_EL1 is required for deactivation.

Note: Always write the INTID value read from ICC_IAR1_EL1, not a modified value. Writing an incorrect INTID is UNPREDICTABLE.

◆ icc_iar1_el1_t

ICC_IAR1_EL1 — Interrupt Controller Interrupt Acknowledge Register 1.

Read-only. Reading this register acknowledges the highest-priority pending Group 1 interrupt and returns its INTID. This simultaneously moves the interrupt from pending to active state.

Special INTIDs:

  • 1020 : Interrupt was a Group 0 interrupt (spurious for Group 1 read)
  • 1021 : Interrupt was a Non-secure Group 1 (from Secure state read)
  • 1022 : Reserved
  • 1023 : Spurious interrupt (no pending interrupt, or PMR/enable masked)

◆ icc_igrpen1_el1_t

ICC_IGRPEN1_EL1 — Interrupt Controller Group 1 Enable (EL1).

Enables or disables forwarding of Group 1 interrupts to the PE for the current Security state. This is the final gate before interrupts are actually signaled to the processor.

Note: The Distributor (GICD_CTLR.EnableGrp1NS) and Redistributor (GICR_CTLR DPG bits) must also permit the interrupt for delivery to occur. All three gates must be open.

◆ icc_pmr_el1_t

ICC_PMR_EL1 — Interrupt Controller Priority Mask Register (EL1).

Sets the minimum priority threshold for interrupt delivery to the PE. Only interrupts with a priority numerically LESS THAN this value are forwarded to the PE. Set to 0xFF to allow all priorities through.

Note: In a two-security-state system, Non-secure reads/writes to this register may see a shifted view of the priority (bit 7 forced to 1).

◆ icc_sre_el1_t

ICC_SRE_EL1 — Interrupt Controller System Register Enable (EL1).

Controls whether the CPU interface registers are accessed via the memory-mapped GICC interface or the AArch64 ICC_* system registers. SRE must be set to 1 before any other ICC_* register can be used.

Note: If EL3 is present, ICC_SRE_EL3.SRE must also be set first, and ICC_SRE_EL2.SRE/Enable must be set to allow EL1 access.

Enumeration Type Documentation

◆ gicd_irm_t

enum gicd_irm_t

Interrupt Routing Mode (IRM) for GICD_IROUTER<n>[31].

Controls how Shared Peripheral Interrupts (SPIs) are routed in a multi-core affinity hierarchy.

The IRM bit determines whether routing is performed using an explicit affinity path (Aff3.Aff2.Aff1.Aff0) or dynamically to any participating PE.

Enumerator
GICD_IRM_AFFINITY 

Route interrupt using affinity path.

IRM = 0

The interrupt is delivered to the Processing Element (PE) whose affinity values match: Aff3.Aff2.Aff1.Aff0.

This provides deterministic routing to a specific CPU.

GICD_IRM_ANY_PE 

Route interrupt to any participating PE.

IRM = 1

The interrupt is routed to any PE that is part of the affinity group. The exact target is chosen by the interrupt controller implementation.

Function Documentation

◆ clear_sgi_ppi_group()

static bool clear_sgi_ppi_group ( const uint32_t  cpu_num,
const uint32_t  intid 
)
inlinestatic

Assign a single SGI or PPI to Group 0 for the given PE.

Clears the corresponding bit in GICR_IGROUPR0 and clears the corresponding bit in GICR_IGRPMODR0, configuring the INTID as Group 0 (the reset default).

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to unconfigure (0-31).
Returns
true if successful, false if intid is out of range.

◆ clear_sgi_ppi_priority()

static bool clear_sgi_ppi_priority ( const uint32_t  cpu_num,
const uint32_t  intid 
)
inlinestatic

Reset the priority of a single SGI or PPI to 0 for the given PE.

Clears the priority byte in the appropriate GICR_IPRIORITYR register for the given INTID, leaving other INTIDs in the same register unaffected.

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to unconfigure (0-31).
Returns
true if successful, false if intid is out of range.

◆ clear_spi_group()

static bool clear_spi_group ( const uint32_t  intid)
inlinestatic

Reset the Group assignment of a single SPI to Group 0.

Clears the corresponding bits in both GICD_IGROUPR<n> and GICD_IGRPMODR<n>, restoring the reset default of Group 0.

Parameters
intidSPI INTID to unconfigure (must be >= 32).
Returns
true if successful, false if intid is out of SPI range.

◆ clear_spi_priority()

static bool clear_spi_priority ( const uint32_t  intid)
inlinestatic

Reset the priority of a single SPI to 0.

Clears the priority byte in the appropriate GICD_IPRIORITYR register for the given SPI INTID, leaving other INTIDs unaffected.

Parameters
intidSPI INTID to unconfigure (must be >= 32).
Returns
true if successful, false if intid is out of SPI range.

◆ clear_spi_route()

static bool clear_spi_route ( const uint32_t  intid)
inlinestatic

Reset the affinity routing of a single SPI to PE 0.0.0.0.

Clears GICD_IROUTER<intid> to zero, which routes the SPI to PE 0.0.0.0 using affinity routing mode (IRM=0).

Parameters
intidSPI INTID to unconfigure (must be >= 32).
Returns
true if successful, false if intid is out of SPI range.

◆ configure_sgi_ppi()

static bool configure_sgi_ppi ( const uint32_t  cpu_num,
const uint32_t  intid,
const uint8_t  priority 
)
inlinestatic

Configure a single SGI or PPI for Group 1 NS delivery.

Convenience wrapper that calls all three configuration steps for a single SGI or PPI INTID in the correct order:

  1. Set Group 1 Non-secure assignment (GICR_IGROUPR0 / GICR_IGRPMODR0)
  2. Set priority (GICR_IPRIORITYR)
  3. Enable forwarding (GICR_ISENABLER0)

After this call the INTID is fully configured and will be delivered to the CPU interface as a Group 1 NS interrupt provided the GIC distributor, redistributor, and CPU interface are also enabled.

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to configure (0-31).
priorityPriority value to assign (e.g. 0xA0).
Returns
true if all steps succeeded, false if intid is out of range.

◆ configure_spi()

static bool configure_spi ( const uint32_t  intid,
const uint8_t  priority,
const uint32_t  aff0,
const uint32_t  aff1,
const uint32_t  aff2,
const uint32_t  aff3 
)
inlinestatic

Configure a single SPI for Group 1 NS delivery to a specific PE.

Convenience wrapper that calls all four configuration steps for a single SPI INTID in the correct order:

  1. Set Group 1 Non-secure assignment (GICD_IGROUPR / GICD_IGRPMODR)
  2. Set priority (GICD_IPRIORITYR)
  3. Set affinity routing (GICD_IROUTER)
  4. Enable forwarding (GICD_ISENABLER)
Parameters
intidSPI INTID to configure (must be >= 32).
priorityPriority value to assign (e.g. 0xA0).
aff0Target PE Aff0.
aff1Target PE Aff1.
aff2Target PE Aff2.
aff3Target PE Aff3.
Returns
true if all steps succeeded, false if intid is out of SPI range.

◆ disable_sgi_ppi()

static bool disable_sgi_ppi ( const uint32_t  cpu_num,
const uint32_t  intid 
)
inlinestatic

Disable forwarding of a single SGI or PPI for the given PE.

Sets the corresponding bit in GICR_ICENABLER0 for the given INTID. Writing 1 disables the interrupt. Writing 0 has no effect.

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to disable (0-31).
Returns
true if successful, false if intid is out of range.

◆ disable_spi()

static bool disable_spi ( const uint32_t  intid)
inlinestatic

Disable forwarding of a single SPI.

Sets the corresponding bit in GICD_ICENABLER<n> for the given SPI INTID. Writing 1 disables the interrupt. Writing 0 has no effect.

Parameters
intidSPI INTID to disable (must be >= 32).
Returns
true if successful, false if intid is out of SPI range.

◆ enable_grp1_interrupts()

static void enable_grp1_interrupts ( void  )
inlinestatic

Enable Group 1 interrupt forwarding on the current PE.

Sets ICC_IGRPEN1_EL1.Enable = 1, which allows Group 1 interrupts to be signaled to this PE by the CPU interface.

◆ enable_sgi_ppi()

static bool enable_sgi_ppi ( const uint32_t  cpu_num,
const uint32_t  intid 
)
inlinestatic

Enable forwarding of a single SGI or PPI for the given PE.

Sets the corresponding bit in GICR_ISENABLER0 for the given INTID. Writing 0 has no effect — this is a set-enable register.

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to enable (0-31).
Returns
true if successful, false if intid is out of range.

◆ enable_spi()

static bool enable_spi ( const uint32_t  intid)
inlinestatic

Enable forwarding of a single SPI for delivery.

Sets the corresponding bit in GICD_ISENABLER<n> for the given SPI INTID. Writing 0 has no effect — this is a set-enable register.

Parameters
intidSPI INTID to enable (must be >= 32).
Returns
true if successful, false if intid is out of SPI range.

◆ get_gicd_ctlr()

static volatile gicd_ctlr_t * get_gicd_ctlr ( void  )
inlinestatic

Get GICD_CTLR register.

Returns
Volatile pointer to GICD_CTLR.

◆ get_gicd_icenabler()

static volatile gicd_icenabler_t * get_gicd_icenabler ( const uint32_t  n)
inlinestatic

Get GICD_ICENABLER<n> (offset 0x0180 + 4n, RW). Clear-Enable register for INTIDs [32n+31:32n].

Parameters
nRegister index (0 = INTIDs 0-31, 1 = INTIDs 32-63, ...).
Returns
Volatile pointer to GICD_ICENABLER<n>.

◆ get_gicd_igroupr()

static volatile gicd_igroupr_t * get_gicd_igroupr ( const uint32_t  n)
inlinestatic

Get GICD_IGROUPR<n> (offset 0x0080 + 4n, RW). Group assignment register for INTIDs [32n+31:32n].

Parameters
nRegister index.
Returns
Volatile pointer to GICD_IGROUPR<n>.

◆ get_gicd_igrpmodr()

static volatile gicd_igrpmodr_t * get_gicd_igrpmodr ( const uint32_t  n)
inlinestatic

Get GICD_IGRPMODR<n> (offset 0x0D00 + 4n, RW). Group modifier register for INTIDs [32n+31:32n].

Parameters
nRegister index.
Returns
Volatile pointer to GICD_IGRPMODR<n>.

◆ get_gicd_iidr()

static volatile gicd_iidr_t * get_gicd_iidr ( void  )
inlinestatic

Get GICD_IIDR register.

Returns
Volatile pointer to GICD_IIDR.

◆ get_gicd_ipriorityr()

static volatile gicd_ipriorityr_t * get_gicd_ipriorityr ( const uint32_t  n)
inlinestatic

Get GICD_IPRIORITYR<n> (offset 0x0400 + 4n, RW). Priority register covering INTIDs [4n+3:4n].

Parameters
nRegister index.
Returns
Volatile pointer to GICD_IPRIORITYR<n>.

◆ get_gicd_irouter()

static volatile gicd_irouter_t * get_gicd_irouter ( const uint32_t  intid)
inlinestatic

Get GICD_IROUTER<n> (offset 0x6000 + 8n, RW). Affinity routing register for SPI INTID n (n >= 32).

Parameters
intidSPI INTID (must be >= 32).
Returns
Volatile pointer to GICD_IROUTER<n>.

◆ get_gicd_isenabler()

static volatile gicd_isenabler_t * get_gicd_isenabler ( const uint32_t  n)
inlinestatic

Get GICD_ISENABLER<n> (offset 0x0100 + 4n, RW). Set-Enable register for INTIDs [32n+31:32n].

Parameters
nRegister index (0 = INTIDs 0-31, 1 = INTIDs 32-63, ...).
Returns
Volatile pointer to GICD_ISENABLER<n>.

◆ get_gicd_typer()

static volatile gicd_typer_t * get_gicd_typer ( void  )
inlinestatic

Get GICD_TYPER register.

Returns
Volatile pointer to GICD_TYPER.

◆ get_gicr_icenabler0()

static volatile gicr_isenabler0_t * get_gicr_icenabler0 ( const uint32_t  cpu_num)
inlinestatic

Get GICR_ICENABLER0 register (SGI frame, offset 0x0180, RW).

Clear-Enable register controlling SGI and PPI interrupt forwarding for this PE. Writing 1 to a bit disables the corresponding INTID; writing 0 has no effect.

Parameters
cpu_numThe redistributor index (0-based PE number).
Returns
Volatile pointer to GICR_ICENABLER0 for this PE.

◆ get_gicr_igroupr0()

static volatile gicr_igroupr0_t * get_gicr_igroupr0 ( const uint32_t  cpu_num)
inlinestatic

Get GICR_IGROUPR0 register (SGI frame, offset 0x0080, RW).

Controls Group 0 vs Group 1 assignment for all SGIs and PPIs. Must be used in conjunction with GICR_IGRPMODR0 to select between Group 1 Secure and Group 1 Non-secure.

Parameters
cpu_numThe redistributor index (0-based PE number).
Returns
Volatile pointer to GICR_IGROUPR0 for this PE.

◆ get_gicr_igrpmodr0()

static volatile gicr_igrpmodr0_t * get_gicr_igrpmodr0 ( const uint32_t  cpu_num)
inlinestatic

Get GICR_IGRPMODR0 register (SGI frame, offset 0x0D00, RW).

Modifier bits selecting between Group 1 Secure and Group 1 Non-secure for each SGI and PPI. Works in conjunction with GICR_IGROUPR0.

Parameters
cpu_numThe redistributor index (0-based PE number).
Returns
Volatile pointer to GICR_IGRPMODR0 for this PE.

◆ get_gicr_ipriorityr()

static volatile gicr_ipriorityr_t * get_gicr_ipriorityr ( const uint32_t  cpu_num,
const uint32_t  n 
)
inlinestatic

Get a GICR_IPRIORITYR register (SGI frame, offset 0x0400+n*4, RW).

Returns a pointer to the priority register covering INTIDs [4n+3:4n]. Valid indices are 0-7, covering all 32 SGIs and PPIs.

Parameters
cpu_numThe redistributor index (0-based PE number).
nRegister index (0-7).
Returns
Volatile pointer to GICR_IPRIORITYR[n] for this PE.

◆ get_gicr_isenabler0()

static volatile gicr_isenabler0_t * get_gicr_isenabler0 ( const uint32_t  cpu_num)
inlinestatic

Get GICR_ISENABLER0 register (SGI frame, offset 0x0100, RW).

Set-Enable register controlling SGI and PPI interrupt forwarding for this PE. Writing 1 to a bit enables the corresponding INTID; writing 0 has no effect. Use GICR_ICENABLER0 to disable individual interrupts.

Bit layout: [15:0] SGIs (INTIDs 0-15) : RAO/WI — permanently enabled [31:16] PPIs (INTIDs 16-31) : RW — write 1 to enable

Parameters
cpu_numThe redistributor index (0-based PE number).
Returns
Volatile pointer to GICR_ISENABLER0 for this PE.

◆ get_gicr_sgi_base()

static virt_addr get_gicr_sgi_base ( const uint32_t  cpu_num)
static

Get the SGI frame base address for the given Redistributor.

Each Redistributor has two 64KB frames:

  • RD frame (offset 0x00000): GICR_CTLR, GICR_TYPER, GICR_WAKER, etc.
  • SGI frame (offset 0x10000): GICR_IGROUPR0, GICR_ISENABLER0, etc.

This function returns the base of the SGI frame for the given PE, which is always 64KB above the RD frame base.

Parameters
cpu_numThe redistributor index (0-based PE number).
Returns
Virtual address of the SGI frame base for this PE.

◆ get_gicr_waker()

static volatile gicr_waker_t * get_gicr_waker ( const uint32_t  cpu_num)
inlinestatic

Get GICR_WAKER register (RD frame, offset 0x0014). Controls Redistributor wake state. Clear ProcessorSleep then poll ChildrenAsleep == 0 before enabling interrupts.

Parameters
cpu_numThe redistributor index (0-based PE number).
Returns
Volatile pointer to GICR_WAKER for this PE.

◆ get_redist_base()

static virt_addr get_redist_base ( const uint32_t  cpu_num)
static

Get Re-disturbutor base.

Parameters
cpu_numthe core number.
Returns
the virtual address of the base

◆ gicv3_handle_irq()

void gicv3_handle_irq ( void  )

EL1 IRQ handler.

Acknowledges the interrupt by reading ICC_IAR1_EL1, dispatches based on INTID, then signals EOI via ICC_EOIR1_EL1.

Must be called with IRQs already masked (hardware does this automatically on exception entry). IRQs are re-enabled on exception return (ERET).

◆ gicv3_init()

void gicv3_init ( const void *  fdt)

Initialize the ARM GICv3 interrupt controller.

Parameters
fdtPointer to the Flattened Device Tree blob used to discover the interrupt controller configuration.

◆ gicv3_register_irq()

bool gicv3_register_irq ( uint32_t  irq_num,
handler_data_t  handler_data 
)

Register a handler for a hardware interrupt source and enable it.

Installs the given handler and private data into the dispatch table for the specified INTID, then configures and enables the interrupt in the GIC. The handler will be invoked with private_data on every subsequent assertion of this interrupt.

Parameters
irq_numPhysical interrupt INTID to register (0-1019).
handler_dataHandler function and private data to register.
Returns
true if the handler was registered and the interrupt enabled successfully, false if the INTID is out of range or GIC configuration failed.

◆ gicv3_unregister_irq()

void gicv3_unregister_irq ( uint32_t  irq_num)

Unregister a handler for a hardware interrupt source and disable it.

Disables the interrupt in the GIC and clears the corresponding entry in the dispatch table. After this call the INTID will no longer fire and any previously registered handler will not be invoked.

Parameters
irq_numPhysical interrupt INTID to unregister (0-1019).

◆ map_continuous()

static bool map_continuous ( phy_addr  p_base,
virt_addr  v_base,
size_t  size,
page_permissions_t  perms,
mem_type_t  mem_type 
)
inlinestatic

Map a contiguous physical memory region to a virtual address range.

Maps every 4KB page in [p_base, p_base+size) to the corresponding virtual address starting at v_base, applying the specified permissions to every page.

For identity mapping, pass p_base == v_base. For high-memory mapping, pass v_base = pa_to_va(p_base).

Parameters
p_basePhysical base address (must be 4KB aligned).
v_baseVirtual base address to map to (must be 4KB aligned).
sizeSize in bytes (must be non-zero; rounded up to 4KB if needed).
permsPage permissions to apply to every mapped page.
mem_typeMemory type index (mem_type_t) written into AttrIndx[2:0] of the leaf descriptor, selecting the MAIR_EL1 attribute byte (e.g. DEVICE → 0x00 Device-nGnRnE, NORMAL → 0xFF Normal WB-RWA Cacheable).
Returns
true on success, false if alignment checks fail or any page mapping fails.

◆ mask_all_core_interrupts()

static void mask_all_core_interrupts ( void  )
inlinestatic

Mask all interrupts on the current PE.

Sets ICC_PMR_EL1 to 0x00, the highest possible priority threshold. No interrupt priority can be numerically less than 0, so nothing is delivered to this PE regardless of other GIC configuration.

Note
This only masks interrupt delivery to this PE via the priority threshold mechanism. It does not affect the pending state of interrupts in the Distributor or Redistributor.

◆ mask_all_exceptions()

static void mask_all_exceptions ( void  )
inlinestatic

Mask all exceptions on the current PE.

Sets all four bits (D, A, I, F) in DAIF simultaneously. Used to enter a fully non-interruptible critical section.

◆ print_gicd_ctlr()

static void print_gicd_ctlr ( void  )
inlinestatic

Dump and decode the GICD_CTLR register for debugging.

The GICD_CTLR register controls the global enable state of the GIC distributor and the routing of Group 0, Secure Group 1, and Non-secure Group 1 interrupts. This function decodes and prints it in a human-readable format for bring-up and diagnostics.

Fields (GICv3, with two security states):

  • EnableGrp0 : Enable Group 0 interrupts
  • EnableGrp1NS : Enable Non-secure Group 1 interrupts
  • EnableGrp1S : Enable Secure Group 1 interrupts (RES0 if ARE_S == 0)
  • ARE_S : Affinity Routing Enable (Secure state)
  • ARE_NS : Affinity Routing Enable (Non-secure state)
  • DS : Disable Security (RAO/WI in single security state)
  • E1NWF : Enable 1-of-N Wakeup Functionality
  • RWP : Register Write Pending (read-only status bit)

◆ print_gicd_iidr()

static void print_gicd_iidr ( void  )
inlinestatic

Dump and decode the GICD_IIDR register for debugging.

The GICD_IIDR register identifies the GIC implementation vendor and versioning information. This function decodes and prints it in a human-readable format for bring-up and diagnostics.

Fields:

  • Implementer : JEP106 vendor ID
  • Revision : Implementation revision
  • Variant : Major implementation variant
  • Product ID : Vendor-defined product identifier

◆ print_gicd_typer()

static void print_gicd_typer ( void  )
inlinestatic

Print decoded GICD_TYPER register for debugging.

This function is intended purely for bring-up/debugging and prints human-readable interpretation of the GICD_TYPER register fields.

◆ print_gicr_igroup()

static void print_gicr_igroup ( const uint32_t  cpu_num)
inlinestatic

Dump and decode GICR_IGROUPR0 and GICR_IGRPMODR0 together.

Decodes the combined group assignment for every SGI and PPI by reading both registers and resolving the group for each INTID.

Parameters
cpu_numThe redistributor index (0-based PE number).

◆ print_gicr_ipriorityr()

static void print_gicr_ipriorityr ( const uint32_t  cpu_num)
inlinestatic

Dump and decode all GICR_IPRIORITYR registers for the given PE.

Prints the configured priority value for every SGI and PPI (INTIDs 0-31).

Parameters
cpu_numThe redistributor index (0-based PE number).

◆ print_gicr_isenabler0()

static void print_gicr_isenabler0 ( const uint32_t  cpu_num)
inlinestatic

Dump and decode GICR_ISENABLER0 for the given PE.

Prints the enable state of all 32 SGI and PPI INTIDs. SGI bits [15:0] should always read as 1 (RAO). PPI bits [31:16] reflect the current software-configured enable state.

Parameters
cpu_numThe redistributor index (0-based PE number).

◆ print_gicr_waker()

static void print_gicr_waker ( const uint32_t  cpu_num)
inlinestatic

Dump and decode the GICR_WAKER register for debugging.

The critical register for Redistributor bring-up. During boot you must clear ProcessorSleep and poll until ChildrenAsleep reads 0 before the PE can receive any interrupts.

Fields:

  • ProcessorSleep : RW — software signals the PE is sleeping
  • ChildrenAsleep : RO — hardware confirms all children are quiescent
Parameters
cpu_numThe redistributor index (0-based PE number).

◆ print_mpidr_el1()

static void print_mpidr_el1 ( void  )
inlinestatic

Dump and decode MPIDR_EL1 for the current PE.

Decodes the affinity hierarchy and flags. The AffinityValue field (Aff3.Aff2.Aff1.Aff0) can be compared directly against GICR_TYPER.AffinityValue to locate this PE's Redistributor frame.

Fields:

  • Aff0 : Thread or core ID within a cluster
  • Aff1 : Cluster ID
  • Aff2 : Higher-level cluster / socket ID
  • Aff3 : Highest-level affinity (NUMA node etc.)
  • MT : Multithreading — Aff0 is thread ID when set
  • U : Uniprocessor — single PE, no affinity structure

◆ set_combined_eoi_mode()

static void set_combined_eoi_mode ( void  )
inlinestatic

Enable combined EOI mode on the current PE.

Sets ICC_CTLR_EL1.EOImode = 0, which means a single write to ICC_EOIR1_EL1 performs both priority drop AND deactivation atomically.

This is the default and simplest EOI mode, suitable for bare-metal kernels that do not require re-enabling preemption between priority drop and deactivation.

Note
If split EOI mode (EOImode = 1) is needed, use enable_split_eoi() instead, and pair ICC_EOIR1_EL1 writes with separate ICC_DIR_EL1 deactivation writes.

◆ set_core_binary_point()

static void set_core_binary_point ( uint8_t  binary_point)
inlinestatic

Configure ICC_BPR1_EL1 for the current PE.

Sets the binary point register for Group 1 interrupts, which controls the split between the preemption group priority and subpriority fields.

The split is defined as:

  • Priority[7:(BinaryPoint+1)] = group priority (controls preemption)
  • Priority[BinaryPoint:0] = subpriority (no preemption effect)

A value of 0 means Priority[7:1] is the group priority and Priority[0] is subpriority — giving near-maximum preemption granularity. This is the correct setting for a simple bare-metal kernel.

Parameters
binary_pointThe binary point split value (0–7). 0 = Priority[7:1] group, Priority[0] subpriority. 7 = all bits are subpriority (no preemption at all). Minimum value is implementation-defined; read ICC_CTLR_EL1.PRIbits to determine the floor.

◆ set_core_min_binary_point()

static void set_core_min_binary_point ( void  )
inlinestatic

Configure ICC_BPR1_EL1 to the minimum allowed value for this PE.

The GICv3 spec mandates a minimum binary point value of (7 - PRIbits), where PRIbits is the number of implemented priority bits read from ICC_CTLR_EL1. Writing any value below this minimum is silently clamped by hardware back up to the minimum.

◆ set_core_priority_threshold()

static void set_core_priority_threshold ( uint8_t  threshold)
inlinestatic

Set the priority mask threshold for the current PE.

Only interrupts with a priority numerically LESS THAN this value will be delivered to the PE.

Parameters
threshold0x00 = mask all interrupts. 0xFF = allow all interrupts through (lowest threshold).

◆ set_gicr_waker()

static void set_gicr_waker ( uint32_t  cpu_num)
inlinestatic

Wake the redistributor for a PE and wait until it acknowledges.

Clears ProcessorSleep in GICR_WAKER and polls ChildrenAsleep until the hardware reports the CPU interface is awake.

Parameters
cpu_numThe redistributor index (0-based PE number).

◆ set_sgi_ppi_group1_ns()

static bool set_sgi_ppi_group1_ns ( const uint32_t  cpu_num,
const uint32_t  intid 
)
inlinestatic

Assign a single SGI or PPI to Group 1 Non-secure for the given PE.

Sets the corresponding bit in GICR_IGROUPR0 and clears the corresponding bit in GICR_IGRPMODR0, configuring the INTID as Group 1 Non-secure.

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to configure (0-31).
Returns
true if successful, false if intid is out of range.

◆ set_sgi_ppi_priority()

static bool set_sgi_ppi_priority ( const uint32_t  cpu_num,
const uint32_t  intid,
const uint8_t  priority 
)
inlinestatic

Set the priority of a single SGI or PPI for the given PE.

Writes the priority byte into the correct byte lane of the appropriate GICR_IPRIORITYR register for the given INTID, leaving other INTIDs in the same register unaffected.

The priority must be numerically less than ICC_PMR_EL1 for the interrupt to be delivered. Only the high bits are implemented (determined by ICC_CTLR_EL1.PRIbits); unimplemented low bits are RAZ/WI and will be masked by hardware.

Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to configure (0-31).
priorityPriority value to assign (e.g. 0xA0).
Returns
true if successful, false if intid is out of range.

◆ set_spi_group1_ns()

static bool set_spi_group1_ns ( const uint32_t  intid)
inlinestatic

Assign a single SPI to Group 1 Non-secure.

Sets the corresponding bit in GICD_IGROUPR<n> and clears the corresponding bit in GICD_IGRPMODR<n>, configuring the SPI as Group 1 Non-secure so it can be received via ICC_IAR1_EL1.

Parameters
intidSPI INTID to configure (must be >= 32).
Returns
true if successful, false if intid is out of SPI range.

◆ set_spi_priority()

static bool set_spi_priority ( const uint32_t  intid,
const uint8_t  priority 
)
inlinestatic

Set the priority of a single SPI.

Writes the priority byte into the correct byte lane of the appropriate GICD_IPRIORITYR register for the given SPI INTID, leaving other INTIDs in the same register unaffected.

Parameters
intidSPI INTID to configure (must be >= 32).
priorityPriority value to assign (e.g. 0xA0).
Returns
true if successful, false if intid is out of SPI range.

◆ set_spi_route()

static bool set_spi_route ( const uint32_t  intid,
const uint32_t  aff0,
const uint32_t  aff1,
const uint32_t  aff2,
const uint32_t  aff3 
)
inlinestatic

Route a single SPI to a specific PE via affinity.

Writes GICD_IROUTER<intid> to route the SPI to the PE identified by the given affinity values. On a single-core system pass all zeros to route to PE 0.0.0.0.

Parameters
intidSPI INTID to route (must be >= 32).
aff0Target Aff0 value.
aff1Target Aff1 value.
aff2Target Aff2 value.
aff3Target Aff3 value.
Returns
true if successful, false if intid is out of SPI range.

◆ unconfigure_sgi_ppi()

static bool unconfigure_sgi_ppi ( const uint32_t  cpu_num,
const uint32_t  intid 
)
inlinestatic

Fully unconfigure a single SGI or PPI for the given PE.

Reverses configure_sgi_ppi() by performing all teardown steps in the correct order:

  1. Disable forwarding (GICR_ICENABLER0)
  2. Reset priority to 0 (GICR_IPRIORITYR)
  3. Reset group to 0 (GICR_IGROUPR0 / GICR_IGRPMODR0)
Parameters
cpu_numThe redistributor index (0-based PE number).
intidSGI or PPI INTID to unconfigure (0-31).
Returns
true if all steps succeeded, false if intid is out of range.

◆ unconfigure_spi()

static bool unconfigure_spi ( const uint32_t  intid)
inlinestatic

Fully unconfigure a single SPI.

Reverses configure_spi() by performing all teardown steps in the correct order:

  1. Disable forwarding (GICD_ICENABLER)
  2. Reset priority to 0 (GICD_IPRIORITYR)
  3. Reset routing (GICD_IROUTER)
  4. Reset group to 0 (GICD_IGROUPR / GICD_IGRPMODR)
Parameters
intidSPI INTID to unconfigure (must be >= 32).
Returns
true if all steps succeeded, false if intid is out of SPI range.

◆ unmask_all_core_interrupts()

static void unmask_all_core_interrupts ( void  )
inlinestatic

Unmask all interrupts on the current PE.

Sets ICC_PMR_EL1 to 0xFF, the lowest possible priority threshold, allowing interrupts of any priority to be delivered to this PE.

Note
The GIC Distributor (GICD_CTLR) and Redistributor (GICR_CTLR) group enables must also be configured for interrupts to actually arrive. This is a necessary but not sufficient condition.

◆ unmask_all_exceptions()

static void unmask_all_exceptions ( void  )
inlinestatic

Unmask all exceptions on the current PE.

Clears all four bits (D, A, I, F) in DAIF simultaneously. Only call this once valid handlers are installed for all exception types in the vector table.

Variable Documentation

◆ dispatch_table

handler_data_t dispatch_table[MAX_INT_ID]
static

Global interrupt dispatch table indexed by INTID.

Each entry holds the handler and private data for the corresponding INTID. Entries are zeroed on startup (handler == NULL means unregistered).