68 lines
2.0 KiB
C
68 lines
2.0 KiB
C
#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;
|
|
}
|
|
|
|
void GICDispatch(ExceptionsType type) {
|
|
OSLog("GICDispatch: %d\n", type);
|
|
if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return;
|
|
UInt32 irqID = GICCReadIAR() & 0x3FF;
|
|
if (irqID == 1023) return; // spurious interrupt
|
|
|
|
if (irqID == kTimerIRQ) {
|
|
OSLog("Timer IRQ\n");
|
|
TimerReset(kTimerFrequency);
|
|
}
|
|
|
|
GICCWriteEOIR(irqID);
|
|
}
|