// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (c) 2026 0xKSor #include #include #include #include static volatile UInt32* GICD = nullptr; static volatile UInt32* GICC = nullptr; void GICInitialize(Pointer gicdVirtBase, Pointer giccVirtBase) { GICD = (volatile UInt32*)gicdVirtBase; GICC = (volatile UInt32*)giccVirtBase; GICD[kGICDCTLR / 4] = 0; // disable Distributor (gicd) UInt32 typer = GICD[kGICDTYPER / 4]; // how many interrupts are supported UInt32 maxIRQS = 32 * ((typer & 0x1F) + 1); // total number of interrupts OSLog("GIC: maxIRQS: %d\n", maxIRQS); for (UInt32 i = 0; i < maxIRQS / 32; i++) { GICD[kGICDICENABLER / 4 + i] = 0xFFFFFFFF; // clear enable GICD[kGICDICPENDR / 4 + i] = 0xFFFFFFFF; // clear pending } for (UInt32 i = 0; i < maxIRQS / 4; i++) { GICD[kGICDIPRIORITYR / 4 + i] = 0xA0A0A0A0; // set priority 0xA0 for all interrupts } for (UInt32 i = 8; i < maxIRQS / 4; i++) { GICD[kGICDITARGETSR / 4 + i] = 0x01010101; // set interrupts id >= 32 for CPU 0 } GICD[kGICDCTLR / 4] = 1; // enable Distributor (gicd) GICC[kGICCCTLR / 4] = 0; // disable cpu interface GICC[kGICCPMR / 4] = 0xFF; // set lowest priority (accept all interrupts) GICC[kGICCCTLR / 4] = 1; // enable CPU interface (gicc) OSLog("GICv2 initialized.\n"); } void GICEnableInterrupt(UInt32 irqID) { UInt32 regOffset = irqID / 32; UInt32 bitMask = 1 << (irqID % 32); GICD[kGICDISENABLER / 4 + regOffset] = bitMask; } UInt32 GICCReadIAR(void) { return GICC[kGICCIAR / 4]; } void GICCWriteEOIR(UInt32 irqID) { GICC[kGICCEOIR / 4] = irqID; } Address GICDispatch(ExceptionsContext* frame, ExceptionsType type) { if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return (Address)frame; UInt32 irqID = GICCReadIAR() & 0x3FF; if (irqID == 1023) return (Address)frame; // spurious interrupt Address newStackPointer = (Address)frame; if (irqID == kTimerIRQ) { newStackPointer = TimerHandler(frame); } GICCWriteEOIR(irqID); return newStackPointer; }