@@ -72,4 +72,4 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) {
|
||||
"isb\n"
|
||||
: "=r"(sctlr) : "r"(sctlr_flags) : "memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user