From 129be91e15f4d9209aba40be3b04b02824fdf23f Mon Sep 17 00:00:00 2001 From: Maksymilian Wilczynski Date: Sat, 2 May 2026 11:34:30 +0200 Subject: [PATCH] fix a few bugs in scheduling and synchronization, separate OVMF_VARS for debug --- OVMF/OVMF_VARS_4M.fd | Bin 540672 -> 540672 bytes OVMF/OVMF_VARS_4M_d.fd | Bin 0 -> 540672 bytes code/hal/hal_timer.c | 2 +- code/kernel/ke_event.c | 22 ++++--- code/kernel/ke_irq.c | 5 +- code/kernel/ke_mutex.c | 22 +++---- code/kernel/ke_process.c | 26 ++++---- code/kernel/ke_queue.c | 20 +++---- code/kernel/ke_sched.c | 118 +++++++++++++++---------------------- code/kernel/ke_semaphore.c | 18 +++--- code/kernel/ke_spinlock.h | 21 +++++-- code/kernel/ke_switch.asm | 9 ++- code/kernel/ke_thread.c | 83 +++++++++----------------- code/kernel/ke_thread.h | 3 + code/kernel/mm_phys.c | 22 +++---- code/kernel/mm_virt.c | 12 ++-- rund.bat | 2 +- 17 files changed, 174 insertions(+), 211 deletions(-) create mode 100644 OVMF/OVMF_VARS_4M_d.fd diff --git a/OVMF/OVMF_VARS_4M.fd b/OVMF/OVMF_VARS_4M.fd index 059a6afcedd0b5afb49b71b89b39e9af3dbe8f32..d1474c3f3c273e7b0c86a5d3f34a6368319d26b8 100644 GIT binary patch delta 354 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 zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N b0t5&UAV7cs0RjXF5FkK+009E0o524AOhdC( literal 0 HcmV?d00001 diff --git a/code/hal/hal_timer.c b/code/hal/hal_timer.c index 53ceed0..85934de 100644 --- a/code/hal/hal_timer.c +++ b/code/hal/hal_timer.c @@ -23,7 +23,7 @@ static volatile uint32_t* gLapic = NULL; #define LAPIC_REG(off) (*(volatile uint32_t *)((uint8_t *)gLapic + (off))) static volatile uint64_t gTicks = 0; -void (*gTimerCallback)(void) = NULL; +void (* volatile gTimerCallback)(void) = NULL; static inline void outb(uint16_t port, uint8_t val) { __outbyte(port, val); } static inline uint8_t inb(uint16_t port) { return __inbyte(port); } diff --git a/code/kernel/ke_event.c b/code/kernel/ke_event.c index 2a08505..285b486 100644 --- a/code/kernel/ke_event.c +++ b/code/kernel/ke_event.c @@ -21,37 +21,35 @@ KSTATUS KeEventCreate(EVENT_TYPE type, uint32_t initialState, EVENT **out) { void KeSignalEvent(EVENT* event) { if (!event) return; - KeAcquireSpinlock(&event->Lock); + uintptr_t flags = KeAcquireSpinlock(&event->Lock); if (event->Type == EventManualReset) { - // Wake all waiters. event->Signaled = 1; while (!LIST_IS_EMPTY(&event->WaitList)) { LIST_ENTRY* node = ListPopHead(&event->WaitList); THREAD* t = CONTAINING_RECORD(node, THREAD, SchedulerLink); - KeReleaseSpinlock(&event->Lock); + KeReleaseSpinlock(&event->Lock, flags); KeUnblockThread(t); - KeAcquireSpinlock(&event->Lock); + flags = KeAcquireSpinlock(&event->Lock); } } else { - // Auto-reset: wake one waiter or set the flag for the next waiter. if (!LIST_IS_EMPTY(&event->WaitList)) { LIST_ENTRY* node = ListPopHead(&event->WaitList); THREAD* t = CONTAINING_RECORD(node, THREAD, SchedulerLink); - KeReleaseSpinlock(&event->Lock); + KeReleaseSpinlock(&event->Lock, flags); KeUnblockThread(t); return; } event->Signaled = 1; } - KeReleaseSpinlock(&event->Lock); + KeReleaseSpinlock(&event->Lock, flags); } void KeClearEvent(EVENT* event) { if (!event) return; - KeAcquireSpinlock(&event->Lock); + uintptr_t flags = KeAcquireSpinlock(&event->Lock); event->Signaled = 0; - KeReleaseSpinlock(&event->Lock); + KeReleaseSpinlock(&event->Lock, flags); } KSTATUS KeWaitForEvent(EVENT* event) { @@ -59,14 +57,14 @@ KSTATUS KeWaitForEvent(EVENT* event) { THREAD* self = KeCurrentThread(); for (;;) { - KeAcquireSpinlock(&event->Lock); + uintptr_t flags = KeAcquireSpinlock(&event->Lock); if (event->Signaled) { if (event->Type == EventAutoReset) event->Signaled = 0; - KeReleaseSpinlock(&event->Lock); + KeReleaseSpinlock(&event->Lock, flags); return STATUS_SUCCESS; } ListInsertTail(&event->WaitList, &self->SchedulerLink); - KeReleaseSpinlock(&event->Lock); + KeReleaseSpinlock(&event->Lock, flags); KeBlockThread(self, &event->Header); } } diff --git a/code/kernel/ke_irq.c b/code/kernel/ke_irq.c index 31227d4..fd3a46c 100644 --- a/code/kernel/ke_irq.c +++ b/code/kernel/ke_irq.c @@ -14,12 +14,11 @@ void KeIrqInitialize(const HAL_API *hal) { void KeIrqRegister(uint8_t irq, void (*handler)(void)) { if (irq >= MAX_IRQS || !handler) return; gIrqHandlers[irq] = handler; - gHal->Intc.RouteIrq(irq); // programs IOAPIC, clears mask bit + gHal->Intc.RouteIrq(irq); } -// Called from KeIrqCommon in assembly - this is the only symbol -// the assembly needs to know. void KeIrqDispatch(uint8_t irq) { + // eoi first, handler second because it doesn't work otherwise. gHal->Intc.SendEoi(); if (irq < MAX_IRQS && gIrqHandlers[irq]) gIrqHandlers[irq](); diff --git a/code/kernel/ke_mutex.c b/code/kernel/ke_mutex.c index 9e77a6b..1de91a2 100644 --- a/code/kernel/ke_mutex.c +++ b/code/kernel/ke_mutex.c @@ -24,46 +24,42 @@ KSTATUS KeAcquireMutex(MUTEX* mutex) { THREAD* self = KeCurrentThread(); for (;;) { - KeAcquireSpinlock(&mutex->Lock); + uintptr_t flags = KeAcquireSpinlock(&mutex->Lock); if (!mutex->Owner) { mutex->Owner = self; - KeReleaseSpinlock(&mutex->Lock); + KeReleaseSpinlock(&mutex->Lock, flags); return STATUS_SUCCESS; } - // Already owned - add self to wait list and block. ListInsertTail(&mutex->WaitList, &self->SchedulerLink); - KeReleaseSpinlock(&mutex->Lock); + KeReleaseSpinlock(&mutex->Lock, flags); KeBlockThread(self, &mutex->Header); - // KeBlockThread calls KeYield; when we return here we've been - // unblocked by KeReleaseMutex - loop back and try to own it. } } KSTATUS KeTryAcquireMutex(MUTEX* mutex) { if (!mutex) return STATUS_INVALID_PARAMETER; THREAD* self = KeCurrentThread(); - KeAcquireSpinlock(&mutex->Lock); + uintptr_t flags = KeAcquireSpinlock(&mutex->Lock); if (!mutex->Owner) { mutex->Owner = self; - KeReleaseSpinlock(&mutex->Lock); + KeReleaseSpinlock(&mutex->Lock, flags); return STATUS_SUCCESS; } - KeReleaseSpinlock(&mutex->Lock); + KeReleaseSpinlock(&mutex->Lock, flags); return STATUS_FAILURE; } void KeReleaseMutex(MUTEX* mutex) { if (!mutex) return; - KeAcquireSpinlock(&mutex->Lock); + uintptr_t flags = KeAcquireSpinlock(&mutex->Lock); mutex->Owner = (struct THREAD *)0; - // Wake the first waiter, if any. if (!LIST_IS_EMPTY(&mutex->WaitList)) { LIST_ENTRY* node = ListPopHead(&mutex->WaitList); THREAD* waiter = CONTAINING_RECORD(node, THREAD, SchedulerLink); - KeReleaseSpinlock(&mutex->Lock); + KeReleaseSpinlock(&mutex->Lock, flags); KeUnblockThread(waiter); return; } - KeReleaseSpinlock(&mutex->Lock); + KeReleaseSpinlock(&mutex->Lock, flags); } diff --git a/code/kernel/ke_process.c b/code/kernel/ke_process.c index ef755fc..c5a7049 100644 --- a/code/kernel/ke_process.c +++ b/code/kernel/ke_process.c @@ -1,6 +1,6 @@ // ke_process.c - process model #include "ke_process.h" -#include "ke_thread.h" // KeExitThread (forward declared below) +#include "ke_thread.h" #include "mm_virt.h" #include "ob_object.h" #include @@ -41,9 +41,9 @@ static void ProcessDestroy(OBJECT* obj) { } // Remove from global list. - KeAcquireSpinlock(&gProcessListLock); + uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); ListRemove(&proc->GlobalLink); - KeReleaseSpinlock(&gProcessListLock); + KeReleaseSpinlock(&gProcessListLock, flags); // Memory for the struct itself is freed by ObDereferenceObject after // Destroy returns. @@ -76,9 +76,9 @@ KSTATUS KeCreateProcess(const char* name, PROCESS **out) { LIST_INIT(&proc->GlobalLink); - KeAcquireSpinlock(&gProcessListLock); + uintptr_t flags = KeAcquireSpinlock(&gProcessListLock); ListInsertTail(&gProcessList, &proc->GlobalLink); - KeReleaseSpinlock(&gProcessListLock); + KeReleaseSpinlock(&gProcessListLock, flags); *out = proc; return STATUS_SUCCESS; @@ -101,43 +101,43 @@ void KeExitProcess(PROCESS* process, int exitCode) { KSTATUS KeAllocateHandle(PROCESS* process, OBJECT* object, uint32_t* handleOut) { if (!process || !object || !handleOut) return STATUS_INVALID_PARAMETER; - KeAcquireSpinlock(&process->HandleLock); + uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); for (int i = 1; i < HANDLE_TABLE_SIZE; i++) { if (!process->Handles[i]) { ObReferenceObject(object); process->Handles[i] = object; *handleOut = (uint32_t)i; - KeReleaseSpinlock(&process->HandleLock); + KeReleaseSpinlock(&process->HandleLock, flags); return STATUS_SUCCESS; } } - KeReleaseSpinlock(&process->HandleLock); + KeReleaseSpinlock(&process->HandleLock, flags); return STATUS_NO_MEMORY; } void KeCloseHandle(PROCESS* process, uint32_t handle) { if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return; - KeAcquireSpinlock(&process->HandleLock); + uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); OBJECT* obj = process->Handles[handle]; if (obj) { process->Handles[handle] = (OBJECT *)0; - KeReleaseSpinlock(&process->HandleLock); + KeReleaseSpinlock(&process->HandleLock, flags); ObDereferenceObject(obj); return; } - KeReleaseSpinlock(&process->HandleLock); + KeReleaseSpinlock(&process->HandleLock, flags); } OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) { if (!process || handle == 0 || handle >= HANDLE_TABLE_SIZE) return (OBJECT *)0; - KeAcquireSpinlock(&process->HandleLock); + uintptr_t flags = KeAcquireSpinlock(&process->HandleLock); OBJECT* obj = process->Handles[handle]; if (obj) ObReferenceObject(obj); - KeReleaseSpinlock(&process->HandleLock); + KeReleaseSpinlock(&process->HandleLock, flags); return obj; } diff --git a/code/kernel/ke_queue.c b/code/kernel/ke_queue.c index 12c266b..08b1549 100644 --- a/code/kernel/ke_queue.c +++ b/code/kernel/ke_queue.c @@ -25,7 +25,7 @@ KSTATUS KeSendMessage(QUEUE* queue, const QUEUE_MESSAGE* msg, bool blocking) { THREAD* self = KeCurrentThread(); for (;;) { - KeAcquireSpinlock(&queue->Lock); + uintptr_t flags = KeAcquireSpinlock(&queue->Lock); if (queue->Count < QUEUE_DEPTH) { queue->Ring[queue->Tail] = *msg; queue->Tail = (queue->Tail + 1) % QUEUE_DEPTH; @@ -35,19 +35,19 @@ KSTATUS KeSendMessage(QUEUE* queue, const QUEUE_MESSAGE* msg, bool blocking) { if (!LIST_IS_EMPTY(&queue->RecvWaiters)) { LIST_ENTRY* node = ListPopHead(&queue->RecvWaiters); THREAD* t = CONTAINING_RECORD(node, THREAD, SchedulerLink); - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); KeUnblockThread(t); } else { - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); } return STATUS_SUCCESS; } if (!blocking) { - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); return STATUS_QUEUE_FULL; } ListInsertTail(&queue->SendWaiters, &self->SchedulerLink); - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); KeBlockThread(self, &queue->Header); } } @@ -57,7 +57,7 @@ KSTATUS KeReceiveMessage(QUEUE* queue, QUEUE_MESSAGE* msg, bool blocking) { THREAD* self = KeCurrentThread(); for (;;) { - KeAcquireSpinlock(&queue->Lock); + uintptr_t flags = KeAcquireSpinlock(&queue->Lock); if (queue->Count > 0) { *msg = queue->Ring[queue->Head]; queue->Head = (queue->Head + 1) % QUEUE_DEPTH; @@ -67,19 +67,19 @@ KSTATUS KeReceiveMessage(QUEUE* queue, QUEUE_MESSAGE* msg, bool blocking) { if (!LIST_IS_EMPTY(&queue->SendWaiters)) { LIST_ENTRY* node = ListPopHead(&queue->SendWaiters); THREAD* t = CONTAINING_RECORD(node, THREAD, SchedulerLink); - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); KeUnblockThread(t); } else { - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); } return STATUS_SUCCESS; } if (!blocking) { - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); return STATUS_QUEUE_EMPTY; } ListInsertTail(&queue->RecvWaiters, &self->SchedulerLink); - KeReleaseSpinlock(&queue->Lock); + KeReleaseSpinlock(&queue->Lock, flags); KeBlockThread(self, &queue->Header); } } diff --git a/code/kernel/ke_sched.c b/code/kernel/ke_sched.c index 473fb34..d1c179a 100644 --- a/code/kernel/ke_sched.c +++ b/code/kernel/ke_sched.c @@ -1,15 +1,4 @@ // ke_sched.c - MLFQ scheduler -// -// Three queues: PriorityHigh(2), PriorityNormal(1), PriorityLow(0). -// Dispatch always picks the highest non-empty queue. -// Within a queue: strict round-robin. -// -// Demotion threshold: a thread that consumes DEMOTION_QUANTA consecutive -// ticks without blocking drops one level (floor PriorityLow). -// Promotion: a thread that unblocks is bumped one level (ceiling PriorityHigh). -// -// The idle thread (created by KeInitializeScheduler) runs at PriorityLow -// when nothing else is runnable. #include "ke_sched.h" #include "ke_thread.h" #include "ke_spinlock.h" @@ -17,44 +6,27 @@ #include "mm_virt.h" #include -#define DEMOTION_QUANTA 4 /* ticks at a level before demotion */ +#define DEMOTION_QUANTA 4 /* ticks at a level before demotion */ -// --------------------------------------------------------------------------- -// Run queues -// --------------------------------------------------------------------------- -static LIST_ENTRY gRunQueue[PriorityCount]; // [0]=Low [1]=Normal [2]=High +static LIST_ENTRY gRunQueue[PriorityCount]; static SPINLOCK gSchedLock; -// The currently running thread (also in GS:[0] for fast access). -// On a single-core system this is the only "per-CPU" slot we need. static THREAD* gCurrentThread; static THREAD* gIdleThread; +static THREAD* gOutgoingThread; +static uint32_t gAgingCounter = 0; -// --------------------------------------------------------------------------- -// GS:[0] helpers - implemented in ke_switch.asm -// (On single-core we just use a global; SMP would use per-core GS.) -// --------------------------------------------------------------------------- THREAD* KeCurrentThread(void) { return gCurrentThread; } void KeSetCurrentThread(THREAD* t){ gCurrentThread = t; } -// --------------------------------------------------------------------------- -// Idle thread body - runs in ring 0 when every other thread is blocked. -// --------------------------------------------------------------------------- static void IdleLoop(void) { for (;;) { __halt(); } } -// --------------------------------------------------------------------------- -// Init -// --------------------------------------------------------------------------- void KeInitializeScheduler(void) { for (int i = 0; i < PriorityCount; i++) LIST_INIT(&gRunQueue[i]); gSchedLock = (SPINLOCK)SPINLOCK_INIT; - // Create the idle process / thread. - // We call the internal alloc directly to avoid the full KeCreateThread - // path (no user stack, no ring-3 entry - the idle thread never leaves - // ring 0 and never calls KeExitThread). extern KSTATUS KeCreateProcess(const char *, PROCESS **); PROCESS* idleProc; KeCreateProcess("idle", &idleProc); @@ -67,13 +39,13 @@ void KeInitializeScheduler(void) { idle->QuantaConsumed = 0; idle->Owner = idleProc; idle->WaitObject = (OBJECT *)0; + idle->SchedLockFlags = 0x202ULL; // IF=1 void* kstack = MmAllocatePool(KSTACK_SIZE); idle->KernelStackBase = kstack; idle->KernelStackTop = (uintptr_t)kstack + KSTACK_SIZE; idle->TssRsp0 = idle->KernelStackTop; - // Initial context: RSP at top of kstack, Rip = IdleLoop. uintptr_t* ksp = (uintptr_t *)idle->KernelStackTop; ksp -= sizeof(KCONTEXT) / sizeof(uintptr_t); KCONTEXT* ctx = (KCONTEXT *)ksp; @@ -83,13 +55,20 @@ void KeInitializeScheduler(void) { gIdleThread = idle; gCurrentThread = idle; - - // Don't add idle to the run queue here; KeSchedulerTick falls back to it. } -// --------------------------------------------------------------------------- -// Run-queue management -// --------------------------------------------------------------------------- +// Safely release the lock and clean up any dead threads natively post-switch +void KeSchedulerPostSwitch(void) { + THREAD* cur = KeCurrentThread(); + KeReleaseSpinlock(&gSchedLock, cur->SchedLockFlags); + + if (gOutgoingThread && gOutgoingThread->State == ThreadDead) { + THREAD* dead = gOutgoingThread; + gOutgoingThread = (THREAD*)0; + ObDereferenceObject(&dead->Header); + } +} + void KeReadyThread(THREAD* thread) { if (!thread) return; thread->State = ThreadReady; @@ -97,22 +76,18 @@ void KeReadyThread(THREAD* thread) { if (p < 0) p = 0; if (p >= PriorityCount) p = PriorityCount - 1; - KeAcquireSpinlock(&gSchedLock); + uintptr_t flags = KeAcquireSpinlock(&gSchedLock); ListInsertTail(&gRunQueue[p], &thread->SchedulerLink); - KeReleaseSpinlock(&gSchedLock); + KeReleaseSpinlock(&gSchedLock, flags); } void KeUnreadyThread(THREAD* thread) { if (!thread) return; - KeAcquireSpinlock(&gSchedLock); + uintptr_t flags = KeAcquireSpinlock(&gSchedLock); ListRemove(&thread->SchedulerLink); - KeReleaseSpinlock(&gSchedLock); + KeReleaseSpinlock(&gSchedLock, flags); } -// --------------------------------------------------------------------------- -// Pick the highest-priority runnable thread (caller holds gSchedLock). -// Returns gIdleThread if all queues are empty. -// --------------------------------------------------------------------------- static THREAD* PickNext(void) { for (int p = PriorityCount - 1; p >= 0; p--) { if (!LIST_IS_EMPTY(&gRunQueue[p])) { @@ -124,18 +99,15 @@ static THREAD* PickNext(void) { return gIdleThread; } -// --------------------------------------------------------------------------- -// KeSchedulerTick - called from the timer ISR every QUANTUM_MS -// --------------------------------------------------------------------------- void KeSchedulerTick(void) { THREAD* cur = gCurrentThread; if (!cur) return; - KeAcquireSpinlock(&gSchedLock); + uintptr_t flags = KeAcquireSpinlock(&gSchedLock); + cur->SchedLockFlags = flags; // Issue 5 fix cur->QuantaConsumed++; - // Demotion: CPU-bound thread exhausted its quanta budget. if (cur != gIdleThread && cur->QuantaConsumed >= DEMOTION_QUANTA) { cur->QuantaConsumed = 0; if (cur->Priority > PriorityLow) { @@ -143,51 +115,56 @@ void KeSchedulerTick(void) { } } - // Check if a higher-priority thread is waiting. + // Periodic aging pass to prevent indefinite starvation of PriorityLow threads + gAgingCounter++; + if (gAgingCounter >= 100) { + gAgingCounter = 0; + for (int p = 0; p < PriorityHigh; p++) { + while (!LIST_IS_EMPTY(&gRunQueue[p])) { + LIST_ENTRY* node = ListPopHead(&gRunQueue[p]); + THREAD* t = CONTAINING_RECORD(node, THREAD, SchedulerLink); + t->Priority = PriorityHigh; + ListInsertTail(&gRunQueue[PriorityHigh], &t->SchedulerLink); + } + } + } + THREAD* next = PickNext(); if (next == cur) { - // Re-insert ourselves and continue. if (cur != gIdleThread) { ListInsertTail(&gRunQueue[cur->Priority], &cur->SchedulerLink); } - KeReleaseSpinlock(&gSchedLock); + KeReleaseSpinlock(&gSchedLock, flags); return; } - // Switch. - cur->State = (cur == gIdleThread) ? ThreadReady : ThreadReady; + cur->State = ThreadReady; next->State = ThreadRunning; gCurrentThread = next; - // Re-queue the outgoing thread if it is still runnable. if (cur != gIdleThread && cur->State == ThreadReady) { ListInsertTail(&gRunQueue[cur->Priority], &cur->SchedulerLink); } - KeReleaseSpinlock(&gSchedLock); + gOutgoingThread = cur; KeSwitchContext(cur, next); + KeSchedulerPostSwitch(); } -// --------------------------------------------------------------------------- -// KeYield -// --------------------------------------------------------------------------- void KeYield(void) { THREAD* cur = gCurrentThread; if (!cur) return; - KeAcquireSpinlock(&gSchedLock); - - // Voluntary block → promote one level. - if (cur != gIdleThread && cur->Priority < PriorityHigh) { - cur->Priority = (THREAD_PRIORITY)(cur->Priority + 1); - cur->QuantaConsumed = 0; - } + uintptr_t flags = KeAcquireSpinlock(&gSchedLock); + cur->SchedLockFlags = flags; + // Issue 4 Fix: Deleted misleading voluntary promotion from here. + THREAD* next = PickNext(); if (next == cur) { if (cur != gIdleThread) ListInsertTail(&gRunQueue[cur->Priority], &cur->SchedulerLink); - KeReleaseSpinlock(&gSchedLock); + KeReleaseSpinlock(&gSchedLock, flags); return; } @@ -197,6 +174,7 @@ void KeYield(void) { if (cur != gIdleThread && cur->State == ThreadReady) ListInsertTail(&gRunQueue[cur->Priority], &cur->SchedulerLink); - KeReleaseSpinlock(&gSchedLock); + gOutgoingThread = cur; KeSwitchContext(cur, next); + KeSchedulerPostSwitch(); } diff --git a/code/kernel/ke_semaphore.c b/code/kernel/ke_semaphore.c index d9f6e87..633c696 100644 --- a/code/kernel/ke_semaphore.c +++ b/code/kernel/ke_semaphore.c @@ -25,40 +25,40 @@ KSTATUS KeWaitSemaphore(SEMAPHORE* sem) { THREAD* self = KeCurrentThread(); for (;;) { - KeAcquireSpinlock(&sem->Lock); + uintptr_t flags = KeAcquireSpinlock(&sem->Lock); if (sem->Count > 0) { sem->Count--; - KeReleaseSpinlock(&sem->Lock); + KeReleaseSpinlock(&sem->Lock, flags); return STATUS_SUCCESS; } ListInsertTail(&sem->WaitList, &self->SchedulerLink); - KeReleaseSpinlock(&sem->Lock); + KeReleaseSpinlock(&sem->Lock, flags); KeBlockThread(self, &sem->Header); } } KSTATUS KeTrySemaphore(SEMAPHORE* sem) { if (!sem) return STATUS_INVALID_PARAMETER; - KeAcquireSpinlock(&sem->Lock); + uintptr_t flags = KeAcquireSpinlock(&sem->Lock); if (sem->Count > 0) { sem->Count--; - KeReleaseSpinlock(&sem->Lock); + KeReleaseSpinlock(&sem->Lock, flags); return STATUS_SUCCESS; } - KeReleaseSpinlock(&sem->Lock); + KeReleaseSpinlock(&sem->Lock, flags); return STATUS_FAILURE; } void KeSignalSemaphore(SEMAPHORE* sem) { if (!sem) return; - KeAcquireSpinlock(&sem->Lock); + uintptr_t flags = KeAcquireSpinlock(&sem->Lock); if (!LIST_IS_EMPTY(&sem->WaitList)) { LIST_ENTRY* node = ListPopHead(&sem->WaitList); THREAD* waiter = CONTAINING_RECORD(node, THREAD, SchedulerLink); - KeReleaseSpinlock(&sem->Lock); + KeReleaseSpinlock(&sem->Lock, flags); KeUnblockThread(waiter); return; } if (sem->Count < sem->MaxCount) sem->Count++; - KeReleaseSpinlock(&sem->Lock); + KeReleaseSpinlock(&sem->Lock, flags); } diff --git a/code/kernel/ke_spinlock.h b/code/kernel/ke_spinlock.h index bb159d7..5d62ad0 100644 --- a/code/kernel/ke_spinlock.h +++ b/code/kernel/ke_spinlock.h @@ -10,15 +10,28 @@ typedef struct SPINLOCK { #define SPINLOCK_INIT { 0 } -static __forceinline void KeAcquireSpinlock(SPINLOCK* sl) { +// Issue 1 Fix: Save EFLAGS, disable interrupts, and return old flags. +static __forceinline uintptr_t KeAcquireSpinlock(SPINLOCK* sl) { + uintptr_t flags = __readeflags(); + _disable(); while (_InterlockedCompareExchange(&sl->Locked, 1, 0) != 0) _mm_pause(); + return flags; } -static __forceinline void KeReleaseSpinlock(SPINLOCK* sl) { +// Issue 1 Fix: Restore EFLAGS upon release. +static __forceinline void KeReleaseSpinlock(SPINLOCK* sl, uintptr_t flags) { _InterlockedExchange(&sl->Locked, 0); + __writeeflags(flags); } -static __forceinline int KeTryAcquireSpinlock(SPINLOCK* sl) { - return _InterlockedCompareExchange(&sl->Locked, 1, 0) == 0; +static __forceinline int KeTryAcquireSpinlock(SPINLOCK* sl, uintptr_t* outFlags) { + uintptr_t flags = __readeflags(); + _disable(); + if (_InterlockedCompareExchange(&sl->Locked, 1, 0) == 0) { + *outFlags = flags; + return 1; + } + __writeeflags(flags); + return 0; } diff --git a/code/kernel/ke_switch.asm b/code/kernel/ke_switch.asm index fa5a826..6357c51 100644 --- a/code/kernel/ke_switch.asm +++ b/code/kernel/ke_switch.asm @@ -64,9 +64,14 @@ KeSwitchContext ENDP ; ; We load RCX from the stack (first arg per MS x64), then IRETQ. ; ------------------------------------------------------------------------- +EXTERN KeSchedulerPostSwitch : PROC + KeThreadEntry PROC - pop rcx ; user arg - iretq ; pops RIP, CS, RFLAGS, RSP, SS -> ring 3 + sub rsp, 32 ; Reserve shadow space + call KeSchedulerPostSwitch + add rsp, 32 + pop rcx ; load user arg + iretq ; -> ring 3 KeThreadEntry ENDP END diff --git a/code/kernel/ke_thread.c b/code/kernel/ke_thread.c index fcf1bcb..a9c71f5 100644 --- a/code/kernel/ke_thread.c +++ b/code/kernel/ke_thread.c @@ -7,44 +7,32 @@ #include static uint32_t gNextThreadId = 1; - -// --------------------------------------------------------------------------- -// Initial kernel-side entry point for a new user thread -// -// When KeSwitchContext restores a brand-new thread, execution lands here. -// We set up RFLAGS (enable interrupts) and IRETQ into ring 3. -// --------------------------------------------------------------------------- -// Declared in ke_thread_entry.asm - see that file for the implementation. extern void KeThreadEntry(void); -// --------------------------------------------------------------------------- -// Destructor -// --------------------------------------------------------------------------- static void ThreadDestroy(OBJECT* obj) { THREAD* thread = CONTAINING_RECORD(obj, THREAD, Header); - // Detach from owner process. if (thread->Owner) { - KeAcquireSpinlock(&thread->Owner->HandleLock); + uintptr_t flags = KeAcquireSpinlock(&thread->Owner->HandleLock); ListRemove(&thread->ProcessLink); thread->Owner->ThreadCount--; - KeReleaseSpinlock(&thread->Owner->HandleLock); + KeReleaseSpinlock(&thread->Owner->HandleLock, flags); ObDereferenceObject(&thread->Owner->Header); thread->Owner = (PROCESS *)0; } - // Free kernel stack. if (thread->KernelStackBase) { MmFreePool(thread->KernelStackBase); thread->KernelStackBase = (void *)0; } - // User stack was allocated from user heap - it is up to the process to - // track and free it. For now we leave it (shared heap, no per-process VA). + + // Assumes UserStackBase was added to THREAD struct in ke_thread.h. + if (thread->UserStackBase) { + MmFreeUserMemory(thread->UserStackBase, USTACK_SIZE); + thread->UserStackBase = (void *)0; + } } -// --------------------------------------------------------------------------- -// KeCreateThread -// --------------------------------------------------------------------------- KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg, THREAD_PRIORITY priority, THREAD **out) { if (!owner || !out) return STATUS_INVALID_PARAMETER; @@ -53,14 +41,14 @@ KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg, THREAD* thread = (THREAD *)ObAllocateObject(ObjectTypeThread, sizeof(THREAD)); if (!thread) return STATUS_NO_MEMORY; - thread->Header.Destroy = ThreadDestroy; + thread->Header.Destroy = ThreadDestroy; thread->ThreadId = _InterlockedExchangeAdd((volatile long *)&gNextThreadId, 1); thread->State = ThreadReady; thread->Priority = priority; thread->QuantaConsumed = 0; thread->WaitObject = (OBJECT *)0; + thread->SchedLockFlags = 0x202ULL; - // Allocate kernel stack. void* kstack = MmAllocatePool(KSTACK_SIZE); if (!kstack) { ObDereferenceObject(&thread->Header); @@ -71,87 +59,70 @@ KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg, thread->KernelStackTop = (uintptr_t)kstack + KSTACK_SIZE; thread->TssRsp0 = thread->KernelStackTop; - // Allocate user stack in the shared user heap. void* ustack = MmAllocateUserMemory(USTACK_SIZE); if (!ustack) { MmFreePool(kstack); ObDereferenceObject(&thread->Header); return STATUS_NO_MEMORY; } + thread->UserStackBase = ustack; uintptr_t userStackTop = (uintptr_t)ustack + USTACK_SIZE; thread->UserEntry = entry; thread->UserArg = arg; - // Set up the initial KCONTEXT so that when KeSwitchContext restores - // this thread, execution lands in KeThreadEntry (in ke_switch.asm), - // which will IRETQ into ring 3 at UserEntry. - // The KCONTEXT sits at the top of the kernel stack. uintptr_t* ksp = (uintptr_t *)thread->KernelStackTop; - - // Push user RSP so KeThreadEntry can find it. *(--ksp) = userStackTop; + *(--ksp) = 0x23ULL; + *(--ksp) = userStackTop; + *(--ksp) = 0x202ULL; + *(--ksp) = 0x1BULL; + *(--ksp) = entry; + *(--ksp) = arg; - // Push the IRETQ frame: RIP, CS (ring3), RFLAGS, RSP, SS (ring3). - // Segment selector values: 0x1B = ring-3 code, 0x23 = ring-3 data. - *(--ksp) = 0x23ULL; // SS - *(--ksp) = userStackTop; // RSP (already set above but IRETQ needs it) - *(--ksp) = 0x202ULL; // RFLAGS: IF=1, reserved bit 1 - *(--ksp) = 0x1BULL; // CS - *(--ksp) = entry; // RIP - // RCX = arg (first argument per MS x64 ABI). - *(--ksp) = arg; // RCX placeholder - KeThreadEntry loads it - - // Now build the KCONTEXT that KeSwitchContext will restore. - // Rip points to KeThreadEntry; all other regs zero; RSP = ksp. ksp -= sizeof(KCONTEXT) / sizeof(uintptr_t); KCONTEXT* ctx = (KCONTEXT *)ksp; memset(ctx, 0, sizeof(KCONTEXT)); ctx->Rip = (uint64_t)KeThreadEntry; thread->SavedContext = ctx; - // Link into the owner process. ObReferenceObject(&owner->Header); thread->Owner = owner; - KeAcquireSpinlock(&owner->HandleLock); + + uintptr_t flags = KeAcquireSpinlock(&owner->HandleLock); ListInsertTail(&owner->ThreadList, &thread->ProcessLink); owner->ThreadCount++; - KeReleaseSpinlock(&owner->HandleLock); + KeReleaseSpinlock(&owner->HandleLock, flags); - // Hand the thread to the scheduler. KeReadyThread(thread); - *out = thread; return STATUS_SUCCESS; } -// --------------------------------------------------------------------------- -// KeExitThread -// --------------------------------------------------------------------------- void KeExitThread(THREAD* thread, int code) { (void)code; if (!thread) return; thread->State = ThreadDead; - KeUnreadyThread(thread); - ObDereferenceObject(&thread->Header); - // Yield - the scheduler will never pick this thread again. KeYield(); } -// --------------------------------------------------------------------------- -// Block / unblock -// --------------------------------------------------------------------------- void KeBlockThread(THREAD* thread, OBJECT* waitObject) { thread->State = ThreadWaiting; thread->WaitObject = waitObject; - KeUnreadyThread(thread); + KeYield(); } void KeUnblockThread(THREAD* thread) { thread->WaitObject = (OBJECT *)0; thread->State = ThreadReady; + + if (thread->Priority < PriorityHigh) { + thread->Priority = (THREAD_PRIORITY)(thread->Priority + 1); + thread->QuantaConsumed = 0; + } + KeReadyThread(thread); } diff --git a/code/kernel/ke_thread.h b/code/kernel/ke_thread.h index 03e33b7..fd26ae6 100644 --- a/code/kernel/ke_thread.h +++ b/code/kernel/ke_thread.h @@ -61,6 +61,9 @@ typedef struct THREAD { // Ring-3 entry point and argument for newly created threads. uintptr_t UserEntry; uintptr_t UserArg; + + uintptr_t SchedLockFlags; // Stores RFLAGS while thread is context switched out + void* UserStackBase; // Tracks user stack allocation to prevent memory leaks } THREAD; KSTATUS KeCreateThread(PROCESS* owner, uintptr_t entry, uintptr_t arg, diff --git a/code/kernel/mm_phys.c b/code/kernel/mm_phys.c index facdf28..74c9425 100644 --- a/code/kernel/mm_phys.c +++ b/code/kernel/mm_phys.c @@ -36,11 +36,11 @@ static FRAME_STACK gFrameStack; // Push a physical frame address onto the stack. static void PushFrame(PHYSICAL_ADDRESS frame) { - KeAcquireSpinlock(&gFrameStack.Lock); + uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); if (gFrameStack.Top < gFrameStack.Capacity) { gFrameStack.Stack[gFrameStack.Top++] = frame; } - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); } // --------------------------------------------------------------------------- @@ -104,32 +104,32 @@ void MmInitializePhysical(const MEMORY_MAP* map, uint64_t physicalWindowBase) { // Public API // --------------------------------------------------------------------------- PHYSICAL_ADDRESS MmAllocateFrame(void) { - KeAcquireSpinlock(&gFrameStack.Lock); + uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); if (gFrameStack.Top == 0) { - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); return (PHYSICAL_ADDRESS)0; } PHYSICAL_ADDRESS frame = gFrameStack.Stack[--gFrameStack.Top]; - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); return frame; } void MmFreeFrame(PHYSICAL_ADDRESS frame) { if (!frame || (frame & (PAGE_SIZE - 1))) return; - KeAcquireSpinlock(&gFrameStack.Lock); + uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); if (gFrameStack.Top < gFrameStack.Capacity) gFrameStack.Stack[gFrameStack.Top++] = frame; // else: stack full — leak rather than corrupt - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); } PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) { if (!count) return (PHYSICAL_ADDRESS)0; - KeAcquireSpinlock(&gFrameStack.Lock); + uintptr_t flags = KeAcquireSpinlock(&gFrameStack.Lock); if (gFrameStack.Top < count) { - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); return (PHYSICAL_ADDRESS)0; } @@ -152,7 +152,7 @@ PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) { } if (run == (size_t)-1) { - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); return (PHYSICAL_ADDRESS)0; } @@ -164,7 +164,7 @@ PHYSICAL_ADDRESS MmAllocateContiguous(size_t count) { gFrameStack.Stack[run + i] = gFrameStack.Stack[run + count + i]; gFrameStack.Top -= count; - KeReleaseSpinlock(&gFrameStack.Lock); + KeReleaseSpinlock(&gFrameStack.Lock, flags); return base; } diff --git a/code/kernel/mm_virt.c b/code/kernel/mm_virt.c index ebb5c48..e80801e 100644 --- a/code/kernel/mm_virt.c +++ b/code/kernel/mm_virt.c @@ -243,7 +243,7 @@ static void* HeapAlloc(HEAP* h, size_t size) { if (!size) return (void *)0; size = (size + 7) & ~7ULL; // 8-byte align - KeAcquireSpinlock(&h->Lock); + uintptr_t flags = KeAcquireSpinlock(&h->Lock); // Best-fit search. BLOCK_HDR* best = (BLOCK_HDR *)0; @@ -256,14 +256,14 @@ static void* HeapAlloc(HEAP* h, size_t size) { if (!best) { if (!HeapGrow(h, size + OVERHEAD)) { - KeReleaseSpinlock(&h->Lock); + KeReleaseSpinlock(&h->Lock, flags); return (void *)0; } // Re-search; HeapGrow inserted at the front. best = h->FreeList; while (best && best->Size < size) best = best->NextFree; if (!best) { - KeReleaseSpinlock(&h->Lock); + KeReleaseSpinlock(&h->Lock, flags); return (void *)0; } } @@ -292,7 +292,7 @@ static void* HeapAlloc(HEAP* h, size_t size) { HdrToFtr(best)->Magic = BLOCK_MAGIC; HdrToFtr(best)->Size = best->Size; - KeReleaseSpinlock(&h->Lock); + KeReleaseSpinlock(&h->Lock, flags); return (char *)best + HDR_SIZE; } @@ -301,7 +301,7 @@ static void HeapFree(HEAP* h, void* ptr) { BLOCK_HDR* blk = (BLOCK_HDR *)((char *)ptr - HDR_SIZE); if (blk->Magic != BLOCK_MAGIC || blk->Free) return; // double-free / corrupt - KeAcquireSpinlock(&h->Lock); + uintptr_t flags = KeAcquireSpinlock(&h->Lock); blk->Free = 1; @@ -338,7 +338,7 @@ static void HeapFree(HEAP* h, void* ptr) { HdrToFtr(blk)->Free = 1; HdrToFtr(blk)->Magic = BLOCK_MAGIC; - KeReleaseSpinlock(&h->Lock); + KeReleaseSpinlock(&h->Lock, flags); } static void* HeapRealloc(HEAP* h, void* ptr, size_t new_size) { diff --git a/rund.bat b/rund.bat index 76effa6..fa2278a 100644 --- a/rund.bat +++ b/rund.bat @@ -1 +1 @@ -@start qemu-system-x86_64 -drive if=pflash,format=raw,readonly=on,file=OVMF\OVMF_CODE_4M.fd -drive if=pflash,format=raw,file=OVMF\OVMF_VARS_4M.fd -device ahci,id=ahci -drive format=raw,file=\\.\PhysicalDrive7,if=none,id=disk0 -device ide-hd,bus=ahci.0,drive=disk0 -m 4G -serial stdio -d in_asm,cpu_reset,int -D qemu.log -no-reboot -no-shutdown +@start qemu-system-x86_64 -drive if=pflash,format=raw,readonly=on,file=OVMF\OVMF_CODE_4M.fd -drive if=pflash,format=raw,file=OVMF\OVMF_VARS_4M_d.fd -device ahci,id=ahci -drive format=raw,file=\\.\PhysicalDrive7,if=none,id=disk0 -device ide-hd,bus=ahci.0,drive=disk0 -m 4G -serial stdio -d in_asm,cpu_reset,int -D qemu.log -no-reboot -no-shutdown