diff --git a/xtoskrnl/includes/ke/systime.hh b/xtoskrnl/includes/ke/systime.hh index c37ba75..a804331 100644 --- a/xtoskrnl/includes/ke/systime.hh +++ b/xtoskrnl/includes/ke/systime.hh @@ -19,6 +19,10 @@ namespace KE { private: STATIC LARGE_INTEGER BootTime; + STATIC ULONG MaximumIncrement; + STATIC ULONG MinimumIncrement; + STATIC LONG TickOffset; + STATIC ULONG TimeAdjustment; public: STATIC XTAPI VOID GetSystemTime(OUT PLARGE_INTEGER SystemTime); @@ -26,6 +30,11 @@ namespace KE OUT PLARGE_INTEGER OldTime, IN BOOLEAN AdjustInterruptTime, IN BOOLEAN WriteToRtc); + STATIC XTAPI VOID SetTimeIncrement(IN ULONG MinIncrement, + IN ULONG MaxIncrement); + STATIC XTFASTCALL VOID UpdateSystemTime(IN PKTRAP_FRAME TrapFrame, + IN ULONG Increment, + IN KRUNLEVEL RunLevel); }; } diff --git a/xtoskrnl/ke/data.cc b/xtoskrnl/ke/data.cc index dffa0bd..1b2852c 100644 --- a/xtoskrnl/ke/data.cc +++ b/xtoskrnl/ke/data.cc @@ -77,3 +77,15 @@ KSPIN_LOCK KE::SystemResources::ResourcesLock; /* Kernel boot time */ LARGE_INTEGER KE::SystemTime::BootTime; + +/* The maximum interval between system clock interrupts */ +ULONG KE::SystemTime::MaximumIncrement; + +/* The minimum interval between system clock interrupts */ +ULONG KE::SystemTime::MinimumIncrement; + +/* Accumulator tracking fractional ticks, decremented until a full tick elapses */ +LONG KE::SystemTime::TickOffset; + +/* The runtime adjustment value applied to the system clock at each interrupt */ +ULONG KE::SystemTime::TimeAdjustment; diff --git a/xtoskrnl/ke/systime.cc b/xtoskrnl/ke/systime.cc index 8b2285a..0c965e9 100644 --- a/xtoskrnl/ke/systime.cc +++ b/xtoskrnl/ke/systime.cc @@ -9,6 +9,7 @@ #include + /** * Returns the current system time. * @@ -97,3 +98,85 @@ KE::SystemTime::SetSystemTime(IN PLARGE_INTEGER NewTime, UNIMPLEMENTED; } } + +/** + * Sets the maximum and minimum time increment values in 100ns units. + * + * @param MinIncrement + * Supplies the minimum time increment. + * + * @param MaxIncrement + * Supplies the maximum time increment. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +KE::SystemTime::SetTimeIncrement(IN ULONG MinIncrement, + IN ULONG MaxIncrement) +{ + /* Store resolution boundaries while enforcing a 1ms architectural floor */ + MaximumIncrement = MaxIncrement; + MinimumIncrement = MAX(MinIncrement, 10000); + + /* Set the tick offset to the maximum increment */ + TickOffset = (LONG)MaxIncrement; + + /* Set the default time adjustment to the full tick period */ + TimeAdjustment = MaxIncrement; +} + +/** + * Services the periodic clock interrupt by advancing the global interrupt time, detecting full + * system tick boundaries via the tick offset accumulator, and advancing the wall-clock system time. + * + * @param TrapFrame + * Supplies a pointer to the hardware trap frame representing the interrupted execution context. + * + * @param Increment + * Supplies the calibrated time delta for this hardware interrupt in 100-nanosecond units. + * + * @param RunLevel + * Supplies the system run level at which the interrupt was taken. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +KE::SystemTime::UpdateSystemTime(IN PKTRAP_FRAME TrapFrame, + IN ULONG Increment, + IN KRUNLEVEL RunLevel) +{ + LARGE_INTEGER InterruptTime, SystemTime; + LONG CurrentTickOffset; + + /* Advance the global interrupt time on every hardware tick */ + InterruptTime = KE::SharedData::GetInterruptTime(); + InterruptTime.QuadPart += Increment; + KE::SharedData::SetInterruptTime(InterruptTime); + + /* Atomically consume the current tick budget and retrieve the pre-decrement value */ + CurrentTickOffset = RTL::Atomic::ExchangeAdd32((PLONG)&TickOffset, -(LONG)Increment); + + /* Determine whether the accumulated increments have crossed the full tick boundary */ + if(CurrentTickOffset <= (LONG)Increment) + { + /* A full system tick has elapsed, advance the wall-clock time by the configured adjustment */ + SystemTime = KE::SharedData::GetSystemTime(); + SystemTime.QuadPart += TimeAdjustment; + KE::SharedData::SetSystemTime(SystemTime); + + /* Update the tick count */ + KE::SharedData::IncrementTickCount(); + + /* Reload the tick offset accumulator for the next full tick period */ + TickOffset += MaximumIncrement; + + /* Update processor and thread runtime accounting */ + KE::Dispatcher::UpdateRunTime(TrapFrame, RunLevel); + } +}