diff --git a/sdk/xtdk/amd64/ketypes.h b/sdk/xtdk/amd64/ketypes.h index 62f6b13..1c9b2b5 100644 --- a/sdk/xtdk/amd64/ketypes.h +++ b/sdk/xtdk/amd64/ketypes.h @@ -565,6 +565,7 @@ typedef struct _KPROCESSOR_CONTROL_BLOCK KDPC_DATA DpcData[2]; PVOID DpcStack; VOLATILE BOOLEAN DpcRoutineActive; + VOLATILE ULONG_PTR TimerHand; VOLATILE ULONG_PTR TimerRequest; ULONG_PTR MultiThreadProcessorSet; SINGLE_LIST_ENTRY DeferredReadyListHead; diff --git a/sdk/xtdk/i686/ketypes.h b/sdk/xtdk/i686/ketypes.h index dc8e1b4..8da6b5a 100644 --- a/sdk/xtdk/i686/ketypes.h +++ b/sdk/xtdk/i686/ketypes.h @@ -525,6 +525,7 @@ typedef struct _KPROCESSOR_CONTROL_BLOCK KDPC_DATA DpcData[2]; PVOID DpcStack; VOLATILE BOOLEAN DpcRoutineActive; + VOLATILE ULONG_PTR TimerHand; VOLATILE ULONG_PTR TimerRequest; SINGLE_LIST_ENTRY DeferredReadyListHead; ULONG InterruptCount; diff --git a/sdk/xtdk/ketypes.h b/sdk/xtdk/ketypes.h index fdfa6c8..5ef5100 100644 --- a/sdk/xtdk/ketypes.h +++ b/sdk/xtdk/ketypes.h @@ -30,8 +30,9 @@ /* Kernel service descriptor tables count */ #define KSERVICE_TABLES_COUNT 4 -/* Timer length */ +/* Timer related definitions */ #define KTIMER_LENGTH (FIELD_OFFSET(KTIMER, Period) + sizeof(LONG)) +#define KTIMER_TABLE_SIZE 512 /* Kernel builtin wait blocks */ #define EVENT_WAIT_BLOCK 2 diff --git a/xtoskrnl/includes/ke/timer.hh b/xtoskrnl/includes/ke/timer.hh index 55a5b6f..85647a4 100644 --- a/xtoskrnl/includes/ke/timer.hh +++ b/xtoskrnl/includes/ke/timer.hh @@ -17,6 +17,9 @@ namespace KE { class Timer { + private: + STATIC LIST_ENTRY TimerTableListHead[KTIMER_TABLE_SIZE]; + public: STATIC XTAPI BOOLEAN CancelTimer(IN PKTIMER Timer); STATIC XTAPI VOID ClearTimer(IN PKTIMER Timer); @@ -28,6 +31,9 @@ namespace KE IN LARGE_INTEGER DueTime, IN LONG Period, IN PKDPC Dpc); + STATIC XTAPI VOID VerifySystemTimerExpiration(IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PKTRAP_FRAME TrapFrame, + IN LARGE_INTEGER Time); private: STATIC XTAPI VOID RemoveTimer(IN OUT PKTIMER Timer); diff --git a/xtoskrnl/ke/data.cc b/xtoskrnl/ke/data.cc index 9ae23c1..ff7a2eb 100644 --- a/xtoskrnl/ke/data.cc +++ b/xtoskrnl/ke/data.cc @@ -95,3 +95,6 @@ LONG KE::SystemTime::TickOffset; /* The runtime adjustment value applied to the system clock at each interrupt */ ULONG KE::SystemTime::TimeAdjustment; + +/* Kernel timer table containing a list of active timers */ +LIST_ENTRY KE::Timer::TimerTableListHead[KTIMER_TABLE_SIZE]; diff --git a/xtoskrnl/ke/timer.cc b/xtoskrnl/ke/timer.cc index 73d9d66..d6a3d53 100644 --- a/xtoskrnl/ke/timer.cc +++ b/xtoskrnl/ke/timer.cc @@ -4,6 +4,7 @@ * FILE: xtoskrnl/ke/timer.cc * DESCRIPTION: Kernel timer object support * DEVELOPERS: Rafal Kupiec + * Aiken Harris */ #include @@ -156,6 +157,25 @@ KE::Timer::QueryTimer(IN PKTIMER Timer) return DueTime; } +/** + * Removes a specified timer from the timer list. + * + * @param Timer + * Supplies a pointer to a timer object. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::Timer::RemoveTimer(IN OUT PKTIMER Timer) +{ + /* Remove the timer from the list */ + Timer->Header.Inserted = FALSE; + RTL::LinkedList::RemoveEntryList(&Timer->TimerListEntry); +} + /** * Sets the supplied timer to expire at the specified time. * @@ -186,10 +206,17 @@ KE::Timer::SetTimer(IN PKTIMER Timer, } /** - * Removes a specified timer from the timer list. + * Verifies if any system timers have expired for the current tick and requests a software + * DISPATCH interrupt to process them if necessary. * - * @param Timer - * Supplies a pointer to a timer object. + * @param Prcb + * Supplies a pointer to the current Processor Control Block. + * + * @param TrapFrame + * Supplies a pointer to the trap frame representing the interrupted context. + * + * @param Time + * Supplies the current absolute interrupt time. * * @return This routine does not return any value. * @@ -197,9 +224,37 @@ KE::Timer::SetTimer(IN PKTIMER Timer, */ XTAPI VOID -KE::Timer::RemoveTimer(IN OUT PKTIMER Timer) +KE::Timer::VerifySystemTimerExpiration(IN PKPROCESSOR_CONTROL_BLOCK Prcb, + IN PKTRAP_FRAME TrapFrame, + IN LARGE_INTEGER Time) { - /* Remove the timer from the list */ - Timer->Header.Inserted = FALSE; - RTL::LinkedList::RemoveEntryList(&Timer->TimerListEntry); + LARGE_INTEGER TickCount; + ULONG TimerHand; + PKTIMER Timer; + + /* Retrieve the current system tick count and calculate the index into the timer table */ + TickCount = KE::SharedData::GetTickCount(); + TimerHand = TickCount.LowPart & (KTIMER_TABLE_SIZE - 1); + + /* Check if there are any active timers scheduled */ + if(!RTL::LinkedList::ListEmpty(&TimerTableListHead[TimerHand])) + { + /* Retrieve the first timer object from the list */ + Timer = CONTAIN_RECORD((&TimerTableListHead[TimerHand])->Flink, KTIMER, TimerListEntry); + + /* Check if the timer due time has been reached */ + if(Timer->DueTime.QuadPart <= Time.QuadPart) + { + /* Ensure there is no pending timer expiration request */ + if(!Prcb->TimerRequest) + { + /* Register the timer expiration request and record a timer slot */ + Prcb->TimerRequest = (ULONG_PTR)TrapFrame; + Prcb->TimerHand = TimerHand; + + /* Request a DPC to safely retire the timer */ + HL::Irq::SendSoftwareInterrupt(DISPATCH_LEVEL); + } + } + } }