fix: improve scheduling, memory, timer implementations
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)));
|
||||
|
||||
Reference in New Issue
Block a user