@@ -72,4 +72,4 @@ static inline void CPUEnableMMU(Address l0PhysicalAddress) {
|
|||||||
"isb\n"
|
"isb\n"
|
||||||
: "=r"(sctlr) : "r"(sctlr_flags) : "memory"
|
: "=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;
|
Size size;
|
||||||
} VMMemoryRegion;
|
} VMMemoryRegion;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
VMMemoryRegion GICD;
|
||||||
|
VMMemoryRegion GICC;
|
||||||
|
} GICRegion;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VMMemoryRegion totalRAM;
|
VMMemoryRegion totalRAM;
|
||||||
VMMemoryRegion reserved[kVMMaxReservedRegions];
|
VMMemoryRegion reserved[kVMMaxReservedRegions];
|
||||||
UInt32 reservedCount;
|
UInt32 reservedCount;
|
||||||
VMMemoryRegion UART;
|
VMMemoryRegion UART;
|
||||||
|
GICRegion GIC;
|
||||||
} VMBootMemoryMap;
|
} VMBootMemoryMap;
|
||||||
|
|
||||||
void PMMInitialize(VMBootMemoryMap* bootMap);
|
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.base = Merge32To64(BytesSwap32(cells[1]), BytesSwap32(cells[0]));
|
||||||
bootMap->UART.size = Merge32To64(BytesSwap32(cells[3]), BytesSwap32(cells[2]));
|
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;
|
structs += propertyLength;
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#include <Arch/Exceptions.h>
|
#include <Arch/Exceptions.h>
|
||||||
#include <Arch/CPU.h>
|
#include <Arch/CPU.h>
|
||||||
|
#include <Arch/GIC.h>
|
||||||
#include <IO/Serial.h>
|
#include <IO/Serial.h>
|
||||||
#include <OS/Panic.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);
|
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 "../Common/bootinfo.h"
|
||||||
#include <Arch/DTB.h>
|
#include <Arch/DTB.h>
|
||||||
|
#include <Arch/Timer.h>
|
||||||
|
#include <Arch/CPU.h>
|
||||||
|
#include <Arch/GIC.h>
|
||||||
#include <VM/PMM.h>
|
#include <VM/PMM.h>
|
||||||
#include <VM/VMM.h>
|
#include <VM/VMM.h>
|
||||||
#include <VM/Heap.h>
|
#include <VM/Heap.h>
|
||||||
@@ -15,9 +18,17 @@ void KernelMain(Bootinfo* bootinfo) {
|
|||||||
VMBootMemoryMap bootMap = {0};
|
VMBootMemoryMap bootMap = {0};
|
||||||
bootMap.reservedCount = 0;
|
bootMap.reservedCount = 0;
|
||||||
DTBParse(bootinfo->dtb, &bootMap);
|
DTBParse(bootinfo->dtb, &bootMap);
|
||||||
|
|
||||||
PMMInitialize(&bootMap);
|
PMMInitialize(&bootMap);
|
||||||
VMMInitialize(&bootMap, bootinfo);
|
VMMInitialize(&bootMap, bootinfo);
|
||||||
HeapInitialize();
|
HeapInitialize();
|
||||||
|
|
||||||
|
GICInitialize(
|
||||||
|
(Pointer)VMPhysToHHDM(bootMap.GIC.GICD.base),
|
||||||
|
(Pointer)VMPhysToHHDM(bootMap.GIC.GICC.base)
|
||||||
|
);
|
||||||
|
TimerInitialize();
|
||||||
|
CPUEnableInterrupts();
|
||||||
|
|
||||||
OSLog("Kernel initialized.\n");
|
OSLog("Kernel initialized.\n");
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-1
@@ -197,7 +197,39 @@ void VMMInitialize(VMBootMemoryMap* bootMap, Bootinfo* info) {
|
|||||||
);
|
);
|
||||||
OSLog("UART mapped\n");
|
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");
|
OSLog("Enabling MMU...\n");
|
||||||
CPUEnableMMU(gVMKernelL0Physical);
|
CPUEnableMMU(gVMKernelL0Physical);
|
||||||
isInitialized = true;
|
isInitialized = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user