73 lines
2.1 KiB
C
73 lines
2.1 KiB
C
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Copyright (c) 2026 0xKSor
|
|
|
|
#include <Arch/GIC.h>
|
|
#include <Arch/Exceptions.h>
|
|
#include <Arch/Timer.h>
|
|
#include <OS/Log.h>
|
|
|
|
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;
|
|
}
|