Skip to content

Commit

Permalink
Completly reworked how the interrupt handler works
Browse files Browse the repository at this point in the history
Also changed how the thread context gets initialized and switched (we can now have a PsYieldExecution that doesn't depend on a dispatch event)
WIth the changes to the scheduler, a massive bug on the thread stealing code was also fixed (it was using the current Processor pointer instead of HalpProcessorList[i])
The `#include <x86intrin.h>` in context.h seemingly didn't go in the last commit, so here it goes again (together with letting the compiler use the SSE registers too)
  • Loading branch information
ilmmatias committed Jan 26, 2025
1 parent c1156f8 commit 3095dc2
Show file tree
Hide file tree
Showing 33 changed files with 1,184 additions and 768 deletions.
9 changes: 5 additions & 4 deletions src/kernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ if(ARCH STREQUAL "amd64")
set(SOURCES
hal/${ARCH}/apic.c
hal/${ARCH}/context.c
hal/${ARCH}/context.S
hal/${ARCH}/gdt.c
hal/${ARCH}/gdt.S
hal/${ARCH}/hpet.c
Expand All @@ -25,11 +26,11 @@ endif()
add_executable(kernel "kernel" YES
${SOURCES}

ev/clock.c
ev/dispatch.c
ev/dpc.c
ev/types.c
ev/object.c
ev/timer.c

hal/interrupt.c
hal/timer.c

io/device.c
Expand Down Expand Up @@ -67,5 +68,5 @@ execute_process(
target_include_directories(kernel PRIVATE include/private PUBLIC include/public)
target_compile_options(kernel PRIVATE $<$<COMPILE_LANGUAGE:C>:-ffreestanding>)
target_compile_definitions(kernel PRIVATE "-DKE_GIT_HASH=\"${GIT_HASH}\"" PRIVATE "-DKE_ARCH=\"${ARCH_STR}\"")
target_link_options(kernel PRIVATE -Wl,--subsystem=native,--entry=KiBspEntry)
target_link_options(kernel PRIVATE -Wl,--subsystem=native,--entry=KiSystemStartup)
set_target_properties(kernel PROPERTIES ENABLE_EXPORTS TRUE)
59 changes: 59 additions & 0 deletions src/kernel/ev/dpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,62 @@ void EvDispatchDpc(EvDpc *Dpc) {
RtAppendDList(&HalGetCurrentProcessor()->DpcQueue, &Dpc->ListHeader);
HalpLeaveCriticalSection(Context);
}

/*-------------------------------------------------------------------------------------------------
* PURPOSE:
* This function handles dispatching any pending events in the processor queue. We expect to
* already be at the DISPATCH IRQL.
*
* PARAMETERS:
* None that we make use of.
*
* RETURN VALUE:
* None.
*-----------------------------------------------------------------------------------------------*/
void EvpProcessQueue(HalInterruptFrame *) {
KeProcessor *Processor = HalGetCurrentProcessor();
uint64_t CurrentTicks = HalGetTimerTicks();

if (KeGetIrql() != KE_IRQL_DISPATCH) {
KeFatalError(KE_PANIC_IRQL_NOT_DISPATCH);
}

/* Process any pending events (they might enqueue DPCs, so we need to process them
* first). */
RtDList *ListHeader = Processor->EventQueue.Next;
while (ListHeader != &Processor->EventQueue) {
EvHeader *Header = CONTAINING_RECORD(ListHeader, EvHeader, ListHeader);
ListHeader = ListHeader->Next;

/* Out of the deadline, for anything but timers, this will make WaitObject return an
error. */
if (Header->DeadlineTicks &&
HalCheckTimerExpiration(
CurrentTicks, Header->DeadlineReference, Header->DeadlineTicks)) {
Header->Finished = 1;
}

if (Header->Finished) {
Header->Dispatched = 0;
RtUnlinkDList(&Header->ListHeader);

if (Header->Source) {
/* Boost the priority of the waiting task, and insert it back. */
KeIrql OldIrql = KeAcquireSpinLock(&Processor->ThreadQueueLock);
RtPushDList(&Processor->ThreadQueue, &Header->Source->ListHeader);
__atomic_add_fetch(&Processor->ThreadQueueSize, 1, __ATOMIC_SEQ_CST);
KeReleaseSpinLock(&Processor->ThreadQueueLock, OldIrql);
}

if (Header->Dpc) {
RtAppendDList(&Processor->DpcQueue, &Header->Dpc->ListHeader);
}
}
}

/* Process any pending DPCs. */
while (Processor->DpcQueue.Next != &Processor->DpcQueue) {
EvDpc *Dpc = CONTAINING_RECORD(RtPopDList(&Processor->DpcQueue), EvDpc, ListHeader);
Dpc->Routine(Dpc->Context);
}
}
77 changes: 9 additions & 68 deletions src/kernel/ev/dispatch.c → src/kernel/ev/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
void EvpDispatchObject(void *Object, uint64_t Timeout, int Yield) {
KeProcessor *Processor = HalGetCurrentProcessor();
uint64_t CurrentTicks = HalGetTimerTicks();
EvHeader *Header = (EvHeader *)Object;
EvHeader *Header = Object;

/* Enter critical section (can't let any scheduling happen here), and update the event
queue. */
Expand All @@ -41,23 +41,22 @@ void EvpDispatchObject(void *Object, uint64_t Timeout, int Yield) {
Header->DeadlineReference = CurrentTicks;
Header->DeadlineTicks = Timeout / HalGetTimerPeriod();
}
}

if (!Header->Dispatched) {
RtAppendDList(&HalGetCurrentProcessor()->EventQueue, &Header->ListHeader);
Header->Dispatched = 1;
}

HalpLeaveCriticalSection(Context);

if (Yield) {
Processor->ForceYield = PSP_YIELD_EVENT;
Header->Source = Processor->CurrentThread;
}
PsYieldExecution();

if (Yield) {
HalpNotifyProcessor(Processor, 1);
/* Idle loop to make sure we won't return too early. */
while (!Header->Finished) {
HalpStopProcessor();
}
}

HalpLeaveCriticalSection(Context);
}

/*-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -89,7 +88,7 @@ void EvWaitObject(void *Object, uint64_t Timeout) {
*-----------------------------------------------------------------------------------------------*/
void EvCancelObject(void *Object) {
void *Context = HalpEnterCriticalSection();
EvHeader *Header = (EvHeader *)Object;
EvHeader *Header = Object;

if (!Header->Dispatched) {
HalpLeaveCriticalSection(Context);
Expand All @@ -105,61 +104,3 @@ void EvCancelObject(void *Object) {

HalpLeaveCriticalSection(Context);
}

/*-------------------------------------------------------------------------------------------------
* PURPOSE:
* This function handles any pending kernel events.
*
* PARAMETERS:
* Context - Current processor state.
*
* RETURN VALUE:
* None.
*-----------------------------------------------------------------------------------------------*/
void EvpHandleEvents(HalRegisterState *Context) {
KeProcessor *Processor = HalGetCurrentProcessor();
uint64_t CurrentTicks = HalGetTimerTicks();

/* Process any pending events (they might enqueue DPCs, so we need to process them
* first). */
RtDList *ListHeader = Processor->EventQueue.Next;
while (ListHeader != &Processor->EventQueue) {
EvHeader *Header = CONTAINING_RECORD(ListHeader, EvHeader, ListHeader);
ListHeader = ListHeader->Next;

/* Out of the deadline, for anything but timers, this will make WaitObject return an
error. */
if (Header->DeadlineTicks &&
HalCheckTimerExpiration(
CurrentTicks, Header->DeadlineReference, Header->DeadlineTicks)) {
Header->Finished = 1;
}

if (Header->Finished) {
Header->Dispatched = 0;
RtUnlinkDList(&Header->ListHeader);

if (Header->Source) {
/* Boost the priority of the waiting task, and insert it back. */
KeIrql OldIrql = KeAcquireSpinLock(&Processor->ThreadQueueLock);
__atomic_add_fetch(&Processor->ThreadQueueSize, 1, __ATOMIC_SEQ_CST);
RtPushDList(&Processor->ThreadQueue, &Header->Source->ListHeader);
KeReleaseSpinLock(&Processor->ThreadQueueLock, OldIrql);
}

if (Header->Dpc) {
RtAppendDList(&Processor->DpcQueue, &Header->Dpc->ListHeader);
}
}
}

/* Process any pending DPCs. */
while (Processor->DpcQueue.Next != &Processor->DpcQueue) {
EvDpc *Dpc = CONTAINING_RECORD(RtPopDList(&Processor->DpcQueue), EvDpc, ListHeader);
Dpc->Routine(Dpc->Context);
}

/* Wrap up by calling the scheduler; It should handle initialization+retriggering the event
handler if required. */
PspScheduleNext(Context);
}
44 changes: 37 additions & 7 deletions src/kernel/ev/clock.c → src/kernel/ev/timer.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,50 @@
/* SPDX-FileCopyrightText: (C) 2025 ilmmatias
* SPDX-License-Identifier: GPL-3.0-or-later */

#include <evp.h>
#include <halp.h>
#include <string.h>

/*-------------------------------------------------------------------------------------------------
* PURPOSE:
* This function initializes the given timer event, setting its deadline relative to the
* current time.
*
* PARAMETERS:
* Timer - Pointer to the timer struct.
* Timeout - How many nanoseconds to sleep for.
* Dpc - Optional DPC to be executed/enqueued when we finish.
*
* RETURN VALUE:
* None.
*-----------------------------------------------------------------------------------------------*/
void EvInitializeTimer(EvTimer *Timer, uint64_t Timeout, EvDpc *Dpc) {
memset(Timer, 0, sizeof(EvTimer));
Timer->Type = EV_TYPE_TIMER;
Timer->Dpc = Dpc;

/* Dispatch the DPC if this is 0-timeout event, and don't bother with the event dispatcher
(just set us as finished). */
if (!Timeout) {
Timer->Finished = 1;
EvDispatchDpc(Dpc);
return;
}

EvpDispatchObject(Timer, Timeout, 0);
}

/*-------------------------------------------------------------------------------------------------
* PURPOSE:
* This function handles a clock event (triggers a dispatch event if neessary).
*
* PARAMETERS:
* Context - Current processor state.
* None that we make use of.
*
* RETURN VALUE:
* None.
*-----------------------------------------------------------------------------------------------*/
void EvpHandleClock(HalRegisterState *) {
void EvpHandleTimer(HalInterruptFrame *) {
KeProcessor *Processor = HalGetCurrentProcessor();
uint64_t CurrentTicks = HalGetTimerTicks();
int TriggerEvent = 0;
Expand All @@ -37,12 +68,11 @@ void EvpHandleClock(HalRegisterState *) {
TriggerEvent = 1;
}

/* At last, check for anything that would swap out the thread. */
if (Processor->InitialThread) {
/* At last, check for a quantum expiration (thread swap). */
if (Processor->CurrentThread) {
PsThread *CurrentThread = Processor->CurrentThread;
int QuantaExpired = HalCheckTimerExpiration(
CurrentTicks, CurrentThread->ExpirationReference, CurrentThread->ExpirationTicks);
if (CurrentThread->Terminated || QuantaExpired || Processor->ForceYield) {
if (HalCheckTimerExpiration(
CurrentTicks, CurrentThread->ExpirationReference, CurrentThread->ExpirationTicks)) {
TriggerEvent = 1;
}
}
Expand Down
34 changes: 0 additions & 34 deletions src/kernel/ev/types.c

This file was deleted.

Loading

0 comments on commit 3095dc2

Please sign in to comment.