Files
reactos/ntoskrnl/ke/clock.c
Timo Kreuzer 77b88c48a4 [NDK][NTOS][NTDLL][KRNEL32] Fix read/write of KSYSTEM_TIME
Fix KiWriteSystemTime and move it to NDK. The previous implementation of KiWriteSystemTime was broken and updated the fields in the wrong order. Before that it was right for SystemTime and wrong for InterruptTime. ExpSetTimeZoneInformation had it wrong for the TimeZoneBias.
Add KiReadSystemTime to read KSYSTEM_TIME values correctly, instead of doing it manually (and partly wrongly) all over the place.
2026-04-23 11:58:15 +00:00

230 lines
6.0 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/clock.c
* PURPOSE: System Clock Support
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
LARGE_INTEGER KeBootTime;
ULONGLONG KeBootTimeBias;
volatile KSYSTEM_TIME KeTickCount = { 0, 0, 0 };
ULONG KeMaximumIncrement;
ULONG KeMinimumIncrement;
ULONG KeTimeIncrement;
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
KeSetSystemTime(IN PLARGE_INTEGER NewTime,
OUT PLARGE_INTEGER OldTime,
IN BOOLEAN FixInterruptTime,
IN PLARGE_INTEGER HalTime OPTIONAL)
{
TIME_FIELDS TimeFields;
KIRQL OldIrql, OldIrql2;
LARGE_INTEGER DeltaTime;
PLIST_ENTRY ListHead, NextEntry;
PKTIMER Timer;
PKSPIN_LOCK_QUEUE LockQueue;
LIST_ENTRY TempList, TempList2;
ULONG Hand, i;
/* Sanity checks */
ASSERT((NewTime->HighPart & 0xF0000000) == 0);
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
/* Check if this is for the HAL */
if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);
/* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
KeSetSystemAffinityThread(1);
OldIrql = KiAcquireDispatcherLock();
KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
/* Query the system time now */
KeQuerySystemTime(OldTime);
/* Set the new system time (ordering of these operations is critical) */
KiWriteSystemTime(&SharedUserData->SystemTime, *NewTime);
/* Check if this was for the HAL and set the RTC time */
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
/* Calculate the difference between the new and the old time */
DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
/* Update system boot time */
KeBootTime.QuadPart += DeltaTime.QuadPart;
KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;
/* Lower IRQL back */
KeLowerIrql(OldIrql2);
/* Check if we need to adjust interrupt time */
if (FixInterruptTime) ASSERT(FALSE);
/* Setup a temporary list of absolute timers */
InitializeListHead(&TempList);
/* Loop current timers */
for (i = 0; i < TIMER_TABLE_SIZE; i++)
{
/* Loop the entries in this table and lock the timers */
ListHead = &KiTimerTableListHead[i].Entry;
LockQueue = KiAcquireTimerLock(i);
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the timer */
Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
NextEntry = NextEntry->Flink;
/* Is it absolute? */
if (Timer->Header.Absolute)
{
/* Remove it from the timer list */
KiRemoveEntryTimer(Timer);
/* Insert it into our temporary list */
InsertTailList(&TempList, &Timer->TimerListEntry);
}
}
/* Release the lock */
KiReleaseTimerLock(LockQueue);
}
/* Setup a temporary list of expired timers */
InitializeListHead(&TempList2);
/* Loop absolute timers */
while (TempList.Flink != &TempList)
{
/* Get the timer */
Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
RemoveEntryList(&Timer->TimerListEntry);
/* Update the due time and handle */
Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
Timer->Header.Hand = (UCHAR)Hand;
/* Lock the timer and re-insert it */
LockQueue = KiAcquireTimerLock(Hand);
if (KiInsertTimerTable(Timer, Hand))
{
/* Remove it from the timer list */
KiRemoveEntryTimer(Timer);
/* Insert it into our temporary list */
InsertTailList(&TempList2, &Timer->TimerListEntry);
}
/* Release the lock */
KiReleaseTimerLock(LockQueue);
}
/* Process expired timers. This releases the dispatcher lock. */
KiTimerListExpire(&TempList2, OldIrql);
/* Revert affinity */
KeRevertToUserAffinityThread();
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
ULONG
NTAPI
KeQueryTimeIncrement(VOID)
{
/* Return the increment */
return KeMaximumIncrement;
}
/*
* @implemented
*/
#undef KeQueryTickCount
VOID
NTAPI
KeQueryTickCount(_Out_ PLARGE_INTEGER TickCount)
{
*TickCount = KiReadSystemTime(&KeTickCount);
}
#ifndef _M_AMD64
/*
* @implemented
*/
VOID
NTAPI
KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
{
/* Loop until we get a perfect match */
for (;;)
{
/* Read the time value */
CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
if (CurrentTime->HighPart ==
SharedUserData->SystemTime.High2Time) break;
YieldProcessor();
}
}
/*
* @implemented
*/
ULONGLONG
NTAPI
KeQueryInterruptTime(VOID)
{
LARGE_INTEGER CurrentTime;
/* Loop until we get a perfect match */
for (;;)
{
/* Read the time value */
CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
if (CurrentTime.HighPart ==
SharedUserData->InterruptTime.High2Time) break;
YieldProcessor();
}
/* Return the time value */
return CurrentTime.QuadPart;
}
#endif
/*
* @implemented
*/
VOID
NTAPI
KeSetTimeIncrement(IN ULONG MaxIncrement,
IN ULONG MinIncrement)
{
/* Set some Internal Variables */
KeMaximumIncrement = MaxIncrement;
KeMinimumIncrement = max(MinIncrement, 10000);
KeTimeAdjustment = MaxIncrement;
KeTimeIncrement = MaxIncrement;
KiTickOffset = MaxIncrement;
}
/* EOF */