Merge pull request #16 from 0xKSor/feat/gic

feat: GICv2 and timer
This commit is contained in:
hwachakarter
2026-04-29 14:00:21 +09:00
committed by GitHub
10 changed files with 181 additions and 5 deletions
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <Types.h>
#include <Arch/IO.h>
#include <Arch/Exceptions.h>
enum {
kGICDBaseAddress = 0x08000000,
kGICCBaseAddress = kGICDBaseAddress + 0x10000,
// GIC Distributor (GICD), offsets from GICD base
kGICDCTLR = 0x000, // control
kGICDTYPER = 0x004, // controller type
kGICDISENABLER = 0x100, // interrupt set-enable
kGICDICENABLER = 0x180, // interrupt clear-enable
kGICDICPENDR = 0x280, // interrupt clear-pending
kGICDIPRIORITYR = 0x400, // interrupt priority
kGICDITARGETSR = 0x800, // interrupt processor targets
// GIC CPU interface (GICC), offsets from CPU interface base
kGICCCTLR = 0x000, // CPU interface control
kGICCPMR = 0x004, // priority mask
kGICCIAR = 0x00C, // interrupt acknowledge
kGICCEOIR = 0x010, // end of interrupt
};
void GICInitialize(Pointer gicdVirtBase, Pointer giccVirtBase);
void GICEnableInterrupt(UInt32 irqID);
void GICDispatch(ExceptionsType type);
+8
View File
@@ -0,0 +1,8 @@
#pragma once
#include <Types.h>
static const UInt64 kTimerFrequency = 1000; // 1ms
static const UInt8 kTimerIRQ = 27;
void TimerInitialize();
void TimerReset(UInt64 interval);
+6
View File
@@ -13,12 +13,18 @@ typedef struct {
Size size;
} VMMemoryRegion;
typedef struct {
VMMemoryRegion GICD;
VMMemoryRegion GICC;
} GICRegion;
typedef struct {
VMMemoryRegion totalRAM;
VMMemoryRegion reserved[kVMMaxReservedRegions];
UInt32 reservedCount;
VMMemoryRegion UART;
GICRegion GIC;
} VMBootMemoryMap;
void PMMInitialize(VMBootMemoryMap* bootMap);
+9
View File
@@ -77,6 +77,15 @@ void DTBParse(Pointer dtb, VMBootMemoryMap* bootMap) {
bootMap->UART.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0]));
bootMap->UART.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2]));
}
else if (StringStartsWith(currentNode, "intc")) {
UInt32* cells = (UInt32*)structs;
bootMap->GIC.GICD.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0]));
bootMap->GIC.GICD.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2]));
bootMap->GIC.GICC.base = Merge32To64(BytesSwap32(cells[5]), BytesSwap32(cells[4]));
bootMap->GIC.GICC.size = Merge32To64(BytesSwap32(cells[7]), BytesSwap32(cells[6]));
}
}
structs += propertyLength;
+4 -1
View File
@@ -1,8 +1,11 @@
#include <Arch/Exceptions.h>
#include <Arch/CPU.h>
#include <Arch/GIC.h>
#include <IO/Serial.h>
#include <OS/Panic.h>
void ExceptionsHandler(ExceptionsContext* frame, [[maybe_unused]]ExceptionsType type) {
void ExceptionsHandler(ExceptionsContext* frame, ExceptionsType type) {
if (type == ExceptionsIRQEl1h || type == ExceptionsIRQEl064) return GICDispatch(type);
OSPanicException(frame);
}
+65
View File
@@ -0,0 +1,65 @@
#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) {
if (type != ExceptionsIRQEl1h && type != ExceptionsIRQEl064) return;
UInt32 irqID = GICCReadIAR() & 0x3FF;
if (irqID == 1023) return; // spurious interrupt
if (irqID == kTimerIRQ) {
TimerReset(kTimerFrequency);
}
GICCWriteEOIR(irqID);
}
+14
View File
@@ -0,0 +1,14 @@
#include <Arch/Timer.h>
#include <Arch/GIC.h>
void TimerInitialize() {
GICEnableInterrupt(kTimerIRQ);
TimerReset(kTimerFrequency);
}
void TimerReset(UInt64 interval) {
UInt64 frequency;
__asm__ volatile ("mrs %0, cntfrq_el0" : "=r"(frequency));
__asm__ volatile ("msr cntv_tval_el0, %0" :: "r"(frequency /interval));
__asm__ volatile ("msr cntv_ctl_el0, %0" :: "r" (1));
}
+11
View File
@@ -1,5 +1,8 @@
#include "../Common/bootinfo.h"
#include <Arch/DTB.h>
#include <Arch/Timer.h>
#include <Arch/CPU.h>
#include <Arch/GIC.h>
#include <VM/PMM.h>
#include <VM/VMM.h>
#include <VM/Heap.h>
@@ -15,9 +18,17 @@ void KernelMain(Bootinfo* bootinfo) {
VMBootMemoryMap bootMap = {0};
bootMap.reservedCount = 0;
DTBParse(bootinfo->dtb, &bootMap);
PMMInitialize(&bootMap);
VMMInitialize(&bootMap, bootinfo);
HeapInitialize();
GICInitialize(
(Pointer)VMPhysToHHDM(bootMap.GIC.GICD.base),
(Pointer)VMPhysToHHDM(bootMap.GIC.GICC.base)
);
TimerInitialize();
CPUEnableInterrupts();
OSLog("Kernel initialized.\n");
}
+33 -1
View File
@@ -197,7 +197,39 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) {
);
OSLog("UART mapped\n");
info->framebuffer.base = (BIUInt32*)kVMFbVirtBase;;
Address gicdPhys = bootMap->GIC.GICD.base;
Size gicdSize = bootMap->GIC.GICD.size;
if (!gicdPhys) {
gicdPhys = 0x08000000; // QEMU fallback
gicdSize = 0x10000;
}
for (Address offset = 0; offset < gicdSize; offset += kVMPageSize) {
VMMMapPage(
gVMKernelL0Table, gicdPhys + offset,
VMPhysToHHDM(gicdPhys + offset),
kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX
);
}
OSLog("GICD mapped\n");
Address giccPhys = bootMap->GIC.GICC.base;
Size giccSize = bootMap->GIC.GICC.size;
if (!giccPhys) {
giccPhys = 0x08001000; // QEMU fallback
giccSize = 0x10000;
}
for (Address offset = 0; offset < giccSize; offset += kVMPageSize) {
VMMMapPage(
gVMKernelL0Table, giccPhys + offset,
VMPhysToHHDM(giccPhys + offset),
kPTEDeviceMem | kPTEAccessRW | kPTEUserNX | kPTEPrivNX
);
}
OSLog("GICC mapped\n");
info->framebuffer.base = (BIUInt32*)kVMFbVirtBase;
OSLog("Enabling MMU...\n");
CPUEnableMMU(gVMKernelL0Physical);
isInitialized = true;