fix: improve scheduling, memory, timer implementations

This commit is contained in:
2026-03-24 07:40:37 +01:00
parent 195028d994
commit f902ab48a1
14 changed files with 239 additions and 94 deletions
+19
View File
@@ -12,6 +12,25 @@ namespace Hal {
// Enable SSE/SSE2 — required for userspace programs compiled with SSE.
// CR0: clear EM (bit 2), set MP (bit 1)
// CR4: set OSFXSR (bit 9) and OSXMMEXCPT (bit 10)
// Check if MONITOR/MWAIT is supported (CPUID.01H:ECX bit 3)
inline bool HasMwait() {
uint32_t ecx;
asm volatile("cpuid" : "=c"(ecx) : "a"(1) : "ebx", "edx");
return (ecx & (1 << 3)) != 0;
}
// Idle using MWAIT if available, otherwise HLT.
// MWAIT can enter deeper C-states (C1E/C3/C6) for better
// power and thermal efficiency than HLT (C1 only).
// The monitored address is arbitrary -- we just need MONITOR
// to arm the wake trigger; any interrupt wakes MWAIT.
inline void IdleWait(volatile uint64_t* monitorAddr) {
// MONITOR: set up the address monitoring range
asm volatile("monitor" :: "a"(monitorAddr), "c"(0), "d"(0));
// MWAIT: hint=0x00 (C1 state, platform-dependent deeper states)
asm volatile("mwait" :: "a"(0x00), "c"(0));
}
inline void EnableSSE() {
uint64_t cr0;
asm volatile("mov %%cr0, %0" : "=r"(cr0));
+6 -3
View File
@@ -118,7 +118,7 @@ namespace Hal {
return result;
}
void IDTEncodeInterrupt(size_t i, void* handler, uint8_t type_attr) {
void IDTEncodeInterrupt(size_t i, void* handler, uint8_t type_attr, uint8_t ist) {
uint64_t offset = (uint64_t)handler;
auto ptr = GetInterruptDescriptor(i);
@@ -126,7 +126,7 @@ namespace Hal {
.Offset1 = (uint16_t)(offset & 0x000000000000ffff),
.Selector = 0x08,
.IST = 0x00,
.IST = ist,
.TypeAttributes = type_attr,
.Offset2 = (uint16_t)((offset & 0x00000000ffff0000) >> 16),
@@ -139,7 +139,10 @@ namespace Hal {
template<int I, int N>
struct SetHandler {
static void run() {
IDTEncodeInterrupt(I, (void*)ExceptionHandler<I>, TrapGate);
// Use IST1 for NMI (2) and Double Fault (8) so they get a
// known-good stack even if the kernel stack has overflowed.
uint8_t ist = (I == 2 || I == 8) ? 1 : 0;
IDTEncodeInterrupt(I, (void*)ExceptionHandler<I>, TrapGate, ist);
SetHandler<I+1,N>::run();
}
};
+1 -1
View File
@@ -25,6 +25,6 @@ namespace Hal {
}__attribute__((packed));
void IDTInitialize();
void IDTEncodeInterrupt(std::size_t i, void* handler, uint8_t type_attr);
void IDTEncodeInterrupt(std::size_t i, void* handler, uint8_t type_attr, uint8_t ist = 0);
void IDTReload();
};
+29 -2
View File
@@ -11,6 +11,7 @@
#include <Hal/MSR.hpp>
#include <Hal/Cpu.hpp>
#include <Memory/Paging.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include <Memory/HHDM.hpp>
#include <Terminal/Terminal.hpp>
#include <CppLib/Stream.hpp>
@@ -60,6 +61,14 @@ namespace Smp {
memset(&cpu.cpuTss, 0, sizeof(Hal::TSS64));
cpu.cpuTss.iopbOffset = sizeof(Hal::TSS64);
// Allocate a 4KB IST1 stack for Double Fault and NMI.
// These exceptions need a known-good stack to avoid triple
// faults when the normal kernel stack overflows.
void* istPage = Memory::g_pfa->AllocateZeroed();
if (istPage) {
cpu.cpuTss.ist1 = (uint64_t)istPage + 0x1000; // top of stack
}
// Copy the standard GDT layout
cpu.cpuGdt = {
{0xFFFF, 0, 0, 0x00, 0x00, 0}, // 0x00 Null
@@ -122,10 +131,17 @@ namespace Smp {
bsp.lapicId = Hal::LocalApic::GetId();
bsp.currentSlot = -1;
bsp.started = true;
bsp.hasMwait = Hal::HasMwait();
// BSP uses the global TSS (already set up in PrepareGDT)
bsp.tss = &Hal::g_tss;
// Allocate IST1 stack for the BSP (for Double Fault / NMI)
void* bspIstPage = Memory::g_pfa->AllocateZeroed();
if (bspIstPage) {
Hal::g_tss.ist1 = (uint64_t)bspIstPage + 0x1000;
}
// Set GS base for BSP
SetGSBase(&bsp);
@@ -187,14 +203,25 @@ namespace Smp {
// --- Calibrate and start APIC timer ---
Timekeeping::ApicTimerInitializeAP();
// --- Check MWAIT support ---
cpu->hasMwait = Hal::HasMwait();
// --- Signal that we are online ---
cpu->started = true;
// --- Enable interrupts and enter idle loop ---
asm volatile("sti");
for (;;) {
asm volatile("hlt");
// Use MWAIT for deeper C-states if available, otherwise HLT.
static volatile uint64_t s_idleMonitor = 0;
if (cpu->hasMwait) {
for (;;) {
Hal::IdleWait(&s_idleMonitor);
}
} else {
for (;;) {
asm volatile("hlt");
}
}
}
+1
View File
@@ -37,6 +37,7 @@ namespace Smp {
volatile bool started; // set by AP after init is complete
Hal::TSS64* tss; // pointer to this CPU's TSS
bool hasMwait; // CPU supports MONITOR/MWAIT
// Per-CPU GDT and TSS (APs use these; BSP uses globals)
Hal::BasicGDT cpuGdt __attribute__((aligned(16)));