feat: add support for aarch64 timer/interrupts, port MontaukOS userspace

This commit is contained in:
daniel committed 2026-10-25 08:27:09 +01:00
1 parent 8b6379fb7e
commit 8c09ccef66
101 files changed
+1720 -629

No files matched your search

+57 -6
View File
@@ -7,6 +7,8 @@
#include <Arch/Platform.hpp>
#include <Arch/Cpu.hpp>
#include <Arch/Smp.hpp>
#include <Arch/aarch64/Gic.hpp>
#include <ACPI/FADT.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
@@ -18,6 +20,42 @@ namespace Arch {
// SCTLR_EL1.WXN: writable memory is execute-never
static constexpr uint64_t SctlrWxn = 1ULL << 19;
// SCTLR_EL1.UCT/UCI: EL0 may read CTR_EL0 and clean/invalidate caches
// by address (what __builtin___clear_cache needs for generated code).
static constexpr uint64_t SctlrUct = 1ULL << 15;
static constexpr uint64_t SctlrUci = 1ULL << 26;
// PSCI 0.2+ function IDs (SMC32 calling convention)
static constexpr uint64_t PsciSystemOff = 0x84000008;
static constexpr uint64_t PsciSystemReset = 0x84000009;
// How the firmware takes PSCI calls, from the FADT's ARM_BOOT_ARCH.
enum class PsciConduit { None, Smc, Hvc };
static PsciConduit g_psci = PsciConduit::None;
static uint64_t PsciCall(uint64_t function) {
register uint64_t x0 asm("x0") = function;
register uint64_t x1 asm("x1") = 0;
register uint64_t x2 asm("x2") = 0;
register uint64_t x3 asm("x3") = 0;
if (g_psci == PsciConduit::Hvc) {
asm volatile("hvc #0" : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3) :: "memory");
} else if (g_psci == PsciConduit::Smc) {
asm volatile("smc #0" : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3) :: "memory");
}
return x0;
}
static void InitializePsci(Hal::ACPI::CommonSDTHeader* xsdt) {
Hal::FADT::ParsedFADT fadt{};
if (!Hal::FADT::Parse(xsdt, fadt) || !fadt.Valid) return;
if (!(fadt.ArmBootArchFlags & Hal::FADT::ArmBootPsciCompliant)) {
KernelLogStream(WARNING, "PSCI") << "Firmware is not PSCI compliant: no reset or power-off";
return;
}
g_psci = (fadt.ArmBootArchFlags & Hal::FADT::ArmBootPsciUseHvc) ? PsciConduit::Hvc : PsciConduit::Smc;
KernelLogStream(OK, "PSCI") << "PSCI through " << (g_psci == PsciConduit::Hvc ? "HVC" : "SMC");
}
void EarlyInitialize() {
// No per-CPU data yet: Smp::TryGetCurrentCpuData must see null.
@@ -32,10 +70,11 @@ namespace Arch {
asm volatile("msr vbar_el1, %0\n\tisb" :: "r"(ArchExceptionVectors) : "memory");
// Kernel mappings are RWX (Paging.cpp), so writable must not
// imply execute-never.
// imply execute-never; user code may maintain its own caches.
uint64_t sctlr;
asm volatile("mrs %0, sctlr_el1" : "=r"(sctlr));
sctlr &= ~SctlrWxn;
sctlr |= SctlrUct | SctlrUci;
asm volatile("msr sctlr_el1, %0\n\tisb" :: "r"(sctlr));
// CPACR_EL1.FPEN = 0b11: FP/SIMD usable at EL0 and EL1 (the kernel
@@ -57,10 +96,12 @@ namespace Arch {
void InitializeMemoryAttributes() {
}
// TODO(aarch64): GIC distributor/redistributor from the ACPI MADT.
void InitializeInterrupts(Hal::ACPI::CommonSDTHeader*) {
void InitializeInterrupts(Hal::ACPI::CommonSDTHeader* xsdt) {
Smp::InitBsp();
KernelLogStream(WARNING, "Arch") << "aarch64: no interrupt controller driver";
if (!Gic::Initialize(xsdt)) {
KernelLogStream(ERROR, "Arch") << "aarch64: no interrupt controller, running without IRQs";
}
InitializePsci(xsdt);
}
void InitializePlatformDevices() {
@@ -73,12 +114,22 @@ namespace Arch {
void LateInitialize() {
}
void ListPlatformDevices(PlatformDeviceSink, void*) {
void ListPlatformDevices(PlatformDeviceSink sink, void* context) {
if (Gic::IsInitialized()) {
sink(context, 1, "GICv2", "ARM Generic Interrupt Controller");
sink(context, 2, "Generic Timer", "ARM architected timer (EL1 virtual)");
}
}
// TODO(aarch64): PSCI SYSTEM_RESET through the conduit the FADT names.
void Reboot() {
PsciCall(PsciSystemReset);
HaltForever();
}
void PowerOff() {
if (g_psci != PsciConduit::None) {
PsciCall(PsciSystemOff);
}
}
}