/* * 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 #define NDEBUG #include /* 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) */ SharedUserData->SystemTime.High2Time = NewTime->HighPart; SharedUserData->SystemTime.LowPart = NewTime->LowPart; SharedUserData->SystemTime.High1Time = NewTime->HighPart; /* 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(IN PLARGE_INTEGER TickCount) { /* Loop until we get a perfect match */ for (;;) { /* Read the tick count value */ TickCount->HighPart = KeTickCount.High1Time; TickCount->LowPart = KeTickCount.LowPart; if (TickCount->HighPart == KeTickCount.High2Time) break; YieldProcessor(); } } #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 */