feat: make kernel architecture-agnostic; primitive work on arm port
This commit is contained in:
1 parent
dab7d5427b
commit
1bae77ec84
164 files changed
+3664
-1641
No files matched your search
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Cpu.hpp
|
||||
* aarch64 implementation of the Arch/Cpu.hpp primitives
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
namespace Arch {
|
||||
|
||||
// PSTATE.I in the DAIF view
|
||||
static constexpr uint64_t DaifIrqMask = 1ULL << 7;
|
||||
|
||||
inline void Pause() {
|
||||
asm volatile("yield" ::: "memory");
|
||||
}
|
||||
|
||||
// Device-nGnRE / Normal-NC (write-combining) stores complete in order
|
||||
// once a DSB has been issued.
|
||||
inline void StoreFence() {
|
||||
asm volatile("dsb st" ::: "memory");
|
||||
}
|
||||
|
||||
inline void MemoryFence() {
|
||||
asm volatile("dsb sy" ::: "memory");
|
||||
}
|
||||
|
||||
inline void EnableInterrupts() {
|
||||
asm volatile("msr daifclr, #2" ::: "memory");
|
||||
}
|
||||
|
||||
inline void DisableInterrupts() {
|
||||
asm volatile("msr daifset, #2" ::: "memory");
|
||||
}
|
||||
|
||||
inline bool InterruptsEnabled() {
|
||||
uint64_t daif;
|
||||
asm volatile("mrs %0, daif" : "=r"(daif));
|
||||
return (daif & DaifIrqMask) == 0;
|
||||
}
|
||||
|
||||
inline IrqFlags SaveAndDisableInterrupts() {
|
||||
uint64_t daif;
|
||||
asm volatile("mrs %0, daif\n\tmsr daifset, #2" : "=r"(daif) :: "memory");
|
||||
return daif;
|
||||
}
|
||||
|
||||
inline void RestoreInterrupts(IrqFlags flags) {
|
||||
asm volatile("msr daif, %0" :: "r"(flags) : "memory");
|
||||
}
|
||||
|
||||
inline void Halt() {
|
||||
asm volatile("wfi" ::: "memory");
|
||||
}
|
||||
|
||||
// WFI wakes on a pending interrupt even while PSTATE.I masks it, so
|
||||
// checking for work and then waiting with IRQs masked cannot lose a
|
||||
// wakeup. Unmask briefly afterwards so the pending IRQ is taken.
|
||||
inline void HaltWithInterruptsDisabled() {
|
||||
asm volatile("wfi\n\tmsr daifclr, #2\n\tisb\n\tmsr daifset, #2" ::: "memory");
|
||||
}
|
||||
|
||||
[[noreturn]] inline void HaltForever() {
|
||||
for (;;) {
|
||||
asm volatile("msr daifset, #0xf\n\twfi" ::: "memory");
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t ReadTimestamp() {
|
||||
uint64_t value;
|
||||
asm volatile("isb\n\tmrs %0, cntvct_el0" : "=r"(value) :: "memory");
|
||||
return value;
|
||||
}
|
||||
|
||||
// The generic timer runs from boot at CNTFRQ_EL0 Hz, so it times short
|
||||
// delays without calibration.
|
||||
inline void IoDelay() {
|
||||
uint64_t frequency;
|
||||
asm volatile("mrs %0, cntfrq_el0" : "=r"(frequency));
|
||||
uint64_t ticks = frequency / 1000000 + 1;
|
||||
uint64_t start = ReadTimestamp();
|
||||
while (ReadTimestamp() - start < ticks) {
|
||||
Pause();
|
||||
}
|
||||
}
|
||||
|
||||
// ARMv8 has no "clean the whole cache" instruction: set/way maintenance
|
||||
// is only safe from firmware, which PSCI performs on power transitions.
|
||||
// Order outstanding accesses so the firmware call sees them.
|
||||
inline void WritebackInvalidateCaches() {
|
||||
asm volatile("dsb sy\n\tisb" ::: "memory");
|
||||
}
|
||||
|
||||
inline void FlushTlbPage(uint64_t virtualAddress) {
|
||||
asm volatile("dsb ishst\n\ttlbi vaae1is, %0\n\tdsb ish\n\tisb"
|
||||
:: "r"(virtualAddress >> 12) : "memory");
|
||||
}
|
||||
|
||||
inline void FlushTlbAll() {
|
||||
asm volatile("dsb ishst\n\ttlbi vmalle1is\n\tdsb ish\n\tisb" ::: "memory");
|
||||
}
|
||||
|
||||
// The process (lower) half of the address space is translated through
|
||||
// TTBR0_EL1; the kernel half through TTBR1_EL1, which never changes.
|
||||
static constexpr uint64_t TtbrAddressMask = 0x0000FFFFFFFFFFFEULL;
|
||||
|
||||
inline uint64_t ReadPageTableRoot() {
|
||||
uint64_t ttbr;
|
||||
asm volatile("mrs %0, ttbr0_el1" : "=r"(ttbr));
|
||||
return ttbr & TtbrAddressMask;
|
||||
}
|
||||
|
||||
// No ASIDs yet: every switch invalidates the old process's entries.
|
||||
inline void WritePageTableRoot(uint64_t rootPhys) {
|
||||
asm volatile("dsb ishst\n\tmsr ttbr0_el1, %0\n\tisb\n\ttlbi vmalle1\n\tdsb nsh\n\tisb"
|
||||
:: "r"(rootPhys) : "memory");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user