|
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.
|
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>
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... | |
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_t * | get_gicd_ctlr (void) |
| Get GICD_CTLR register. | |
| static volatile gicd_typer_t * | get_gicd_typer (void) |
| Get GICD_TYPER register. | |
| static volatile gicd_iidr_t * | get_gicd_iidr (void) |
| Get GICD_IIDR register. | |
| static volatile gicd_igroupr_t * | get_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_t * | get_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_t * | get_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_t * | get_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_t * | get_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_t * | get_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_t * | get_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_t * | get_gicr_isenabler0 (const uint32_t cpu_num) |
| Get GICR_ISENABLER0 register (SGI frame, offset 0x0100, RW). | |
| static volatile gicr_igroupr0_t * | get_gicr_igroupr0 (const uint32_t cpu_num) |
| Get GICR_IGROUPR0 register (SGI frame, offset 0x0080, RW). | |
| static volatile gicr_igrpmodr0_t * | get_gicr_igrpmodr0 (const uint32_t cpu_num) |
| Get GICR_IGRPMODR0 register (SGI frame, offset 0x0D00, RW). | |
| static volatile gicr_ipriorityr_t * | get_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_t * | get_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. | |
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.
| 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.
| typedef gicd_isenabler_t 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.
| typedef union gicd_igroupr_t 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).
| typedef union gicd_igrpmodr_t 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.
| 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.
| typedef union gicd_ipriorityr_t 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.
| 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.
| typedef union gicd_irouter_t 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.
| typedef union gicd_isenabler_t 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.
| 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.
| typedef union gicr_igroupr0_t 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).
| typedef union gicr_igrpmodr0_t 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.
| typedef union gicr_ipriorityr_t 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.
| typedef union gicr_isenabler0_t 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
| 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.
| typedef union icc_bpr1_el1_t 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:
Setting BinaryPoint=0 gives the finest preemption granularity (all priority bits participate in preemption). Higher values reduce preemption sensitivity.
| typedef union icc_ctlr_el1_t 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).
| typedef union icc_eoir1_el1_t 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.
| typedef union icc_iar1_el1_t 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:
| typedef union icc_igrpen1_el1_t 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.
| typedef union icc_pmr_el1_t 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).
| typedef union icc_sre_el1_t 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.
| 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.
|
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).
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to unconfigure (0-31). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to unconfigure (0-31). |
|
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.
| intid | SPI INTID to unconfigure (must be >= 32). |
|
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.
| intid | SPI INTID to unconfigure (must be >= 32). |
|
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).
| intid | SPI INTID to unconfigure (must be >= 32). |
|
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:
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.
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to configure (0-31). |
| priority | Priority value to assign (e.g. 0xA0). |
|
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:
| intid | SPI INTID to configure (must be >= 32). |
| priority | Priority value to assign (e.g. 0xA0). |
| aff0 | Target PE Aff0. |
| aff1 | Target PE Aff1. |
| aff2 | Target PE Aff2. |
| aff3 | Target PE Aff3. |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to disable (0-31). |
|
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.
| intid | SPI INTID to disable (must be >= 32). |
|
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.
|
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.
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to enable (0-31). |
|
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.
| intid | SPI INTID to enable (must be >= 32). |
|
inlinestatic |
Get GICD_CTLR register.
|
inlinestatic |
Get GICD_ICENABLER<n> (offset 0x0180 + 4n, RW). Clear-Enable register for INTIDs [32n+31:32n].
| n | Register index (0 = INTIDs 0-31, 1 = INTIDs 32-63, ...). |
|
inlinestatic |
Get GICD_IGROUPR<n> (offset 0x0080 + 4n, RW). Group assignment register for INTIDs [32n+31:32n].
| n | Register index. |
|
inlinestatic |
Get GICD_IGRPMODR<n> (offset 0x0D00 + 4n, RW). Group modifier register for INTIDs [32n+31:32n].
| n | Register index. |
|
inlinestatic |
Get GICD_IIDR register.
|
inlinestatic |
Get GICD_IPRIORITYR<n> (offset 0x0400 + 4n, RW). Priority register covering INTIDs [4n+3:4n].
| n | Register index. |
|
inlinestatic |
Get GICD_IROUTER<n> (offset 0x6000 + 8n, RW). Affinity routing register for SPI INTID n (n >= 32).
| intid | SPI INTID (must be >= 32). |
|
inlinestatic |
Get GICD_ISENABLER<n> (offset 0x0100 + 4n, RW). Set-Enable register for INTIDs [32n+31:32n].
| n | Register index (0 = INTIDs 0-31, 1 = INTIDs 32-63, ...). |
|
inlinestatic |
Get GICD_TYPER register.
|
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.
| cpu_num | The redistributor index (0-based PE number). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
| n | Register index (0-7). |
|
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
| cpu_num | The redistributor index (0-based PE number). |
|
static |
Get the SGI frame base address for the given Redistributor.
Each Redistributor has two 64KB frames:
This function returns the base of the SGI frame for the given PE, which is always 64KB above the RD frame base.
| cpu_num | The redistributor index (0-based PE number). |
|
inlinestatic |
Get GICR_WAKER register (RD frame, offset 0x0014). Controls Redistributor wake state. Clear ProcessorSleep then poll ChildrenAsleep == 0 before enabling interrupts.
| cpu_num | The redistributor index (0-based PE number). |
|
static |
Get Re-disturbutor base.
| cpu_num | the core number. |
| 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).
| void gicv3_init | ( | const void * | fdt | ) |
Initialize the ARM GICv3 interrupt controller.
| fdt | Pointer to the Flattened Device Tree blob used to discover the interrupt controller configuration. |
| 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.
| irq_num | Physical interrupt INTID to register (0-1019). |
| handler_data | Handler function and private data to register. |
| 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.
| irq_num | Physical interrupt INTID to unregister (0-1019). |
|
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).
| p_base | Physical base address (must be 4KB aligned). |
| v_base | Virtual base address to map to (must be 4KB aligned). |
| size | Size in bytes (must be non-zero; rounded up to 4KB if needed). |
| perms | Page permissions to apply to every mapped page. |
| mem_type | Memory 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). |
|
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.
|
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.
|
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):
|
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:
|
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.
|
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.
| cpu_num | The redistributor index (0-based PE number). |
|
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).
| cpu_num | The redistributor index (0-based PE number). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
|
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:
| cpu_num | The redistributor index (0-based PE number). |
|
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:
|
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.
|
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:
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.
| binary_point | The 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. |
|
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.
|
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.
| threshold | 0x00 = mask all interrupts. 0xFF = allow all interrupts through (lowest threshold). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to configure (0-31). |
|
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.
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to configure (0-31). |
| priority | Priority value to assign (e.g. 0xA0). |
|
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.
| intid | SPI INTID to configure (must be >= 32). |
|
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.
| intid | SPI INTID to configure (must be >= 32). |
| priority | Priority value to assign (e.g. 0xA0). |
|
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.
| intid | SPI INTID to route (must be >= 32). |
| aff0 | Target Aff0 value. |
| aff1 | Target Aff1 value. |
| aff2 | Target Aff2 value. |
| aff3 | Target Aff3 value. |
|
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:
| cpu_num | The redistributor index (0-based PE number). |
| intid | SGI or PPI INTID to unconfigure (0-31). |
|
inlinestatic |
Fully unconfigure a single SPI.
Reverses configure_spi() by performing all teardown steps in the correct order:
| intid | SPI INTID to unconfigure (must be >= 32). |
|
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.
|
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.
|
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).