1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/clock.c 5 * PURPOSE: System Clock Support 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* GLOBALS *******************************************************************/ 16 17 LARGE_INTEGER KeBootTime; 18 ULONGLONG KeBootTimeBias; 19 volatile KSYSTEM_TIME KeTickCount = { 0, 0, 0 }; 20 ULONG KeMaximumIncrement; 21 ULONG KeMinimumIncrement; 22 ULONG KeTimeIncrement; 23 24 /* PRIVATE FUNCTIONS *********************************************************/ 25 26 VOID 27 NTAPI 28 KeSetSystemTime(IN PLARGE_INTEGER NewTime, 29 OUT PLARGE_INTEGER OldTime, 30 IN BOOLEAN FixInterruptTime, 31 IN PLARGE_INTEGER HalTime OPTIONAL) 32 { 33 TIME_FIELDS TimeFields; 34 KIRQL OldIrql, OldIrql2; 35 LARGE_INTEGER DeltaTime; 36 PLIST_ENTRY ListHead, NextEntry; 37 PKTIMER Timer; 38 PKSPIN_LOCK_QUEUE LockQueue; 39 LIST_ENTRY TempList, TempList2; 40 ULONG Hand, i; 41 42 /* Sanity checks */ 43 ASSERT((NewTime->HighPart & 0xF0000000) == 0); 44 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 45 46 /* Check if this is for the HAL */ 47 if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields); 48 49 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */ 50 KeSetSystemAffinityThread(1); 51 OldIrql = KiAcquireDispatcherLock(); 52 KeRaiseIrql(HIGH_LEVEL, &OldIrql2); 53 54 /* Query the system time now */ 55 KeQuerySystemTime(OldTime); 56 57 /* Set the new system time (ordering of these operations is critical) */ 58 SharedUserData->SystemTime.High2Time = NewTime->HighPart; 59 SharedUserData->SystemTime.LowPart = NewTime->LowPart; 60 SharedUserData->SystemTime.High1Time = NewTime->HighPart; 61 62 /* Check if this was for the HAL and set the RTC time */ 63 if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields); 64 65 /* Calculate the difference between the new and the old time */ 66 DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart; 67 68 /* Update system boot time */ 69 KeBootTime.QuadPart += DeltaTime.QuadPart; 70 KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart; 71 72 /* Lower IRQL back */ 73 KeLowerIrql(OldIrql2); 74 75 /* Check if we need to adjust interrupt time */ 76 if (FixInterruptTime) ASSERT(FALSE); 77 78 /* Setup a temporary list of absolute timers */ 79 InitializeListHead(&TempList); 80 81 /* Loop current timers */ 82 for (i = 0; i < TIMER_TABLE_SIZE; i++) 83 { 84 /* Loop the entries in this table and lock the timers */ 85 ListHead = &KiTimerTableListHead[i].Entry; 86 LockQueue = KiAcquireTimerLock(i); 87 NextEntry = ListHead->Flink; 88 while (NextEntry != ListHead) 89 { 90 /* Get the timer */ 91 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); 92 NextEntry = NextEntry->Flink; 93 94 /* Is it absolute? */ 95 if (Timer->Header.Absolute) 96 { 97 /* Remove it from the timer list */ 98 KiRemoveEntryTimer(Timer); 99 100 /* Insert it into our temporary list */ 101 InsertTailList(&TempList, &Timer->TimerListEntry); 102 } 103 } 104 105 /* Release the lock */ 106 KiReleaseTimerLock(LockQueue); 107 } 108 109 /* Setup a temporary list of expired timers */ 110 InitializeListHead(&TempList2); 111 112 /* Loop absolute timers */ 113 while (TempList.Flink != &TempList) 114 { 115 /* Get the timer */ 116 Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry); 117 RemoveEntryList(&Timer->TimerListEntry); 118 119 /* Update the due time and handle */ 120 Timer->DueTime.QuadPart -= DeltaTime.QuadPart; 121 Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart); 122 Timer->Header.Hand = (UCHAR)Hand; 123 124 /* Lock the timer and re-insert it */ 125 LockQueue = KiAcquireTimerLock(Hand); 126 if (KiInsertTimerTable(Timer, Hand)) 127 { 128 /* Remove it from the timer list */ 129 KiRemoveEntryTimer(Timer); 130 131 /* Insert it into our temporary list */ 132 InsertTailList(&TempList2, &Timer->TimerListEntry); 133 } 134 135 /* Release the lock */ 136 KiReleaseTimerLock(LockQueue); 137 } 138 139 /* Process expired timers. This releases the dispatcher lock. */ 140 KiTimerListExpire(&TempList2, OldIrql); 141 142 /* Revert affinity */ 143 KeRevertToUserAffinityThread(); 144 } 145 146 /* PUBLIC FUNCTIONS **********************************************************/ 147 148 /* 149 * @implemented 150 */ 151 ULONG 152 NTAPI 153 KeQueryTimeIncrement(VOID) 154 { 155 /* Return the increment */ 156 return KeMaximumIncrement; 157 } 158 159 /* 160 * @implemented 161 */ 162 #undef KeQueryTickCount 163 VOID 164 NTAPI 165 KeQueryTickCount(IN PLARGE_INTEGER TickCount) 166 { 167 /* Loop until we get a perfect match */ 168 for (;;) 169 { 170 /* Read the tick count value */ 171 TickCount->HighPart = KeTickCount.High1Time; 172 TickCount->LowPart = KeTickCount.LowPart; 173 if (TickCount->HighPart == KeTickCount.High2Time) break; 174 YieldProcessor(); 175 } 176 } 177 178 #ifndef _M_AMD64 179 /* 180 * @implemented 181 */ 182 VOID 183 NTAPI 184 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime) 185 { 186 /* Loop until we get a perfect match */ 187 for (;;) 188 { 189 /* Read the time value */ 190 CurrentTime->HighPart = SharedUserData->SystemTime.High1Time; 191 CurrentTime->LowPart = SharedUserData->SystemTime.LowPart; 192 if (CurrentTime->HighPart == 193 SharedUserData->SystemTime.High2Time) break; 194 YieldProcessor(); 195 } 196 } 197 198 /* 199 * @implemented 200 */ 201 ULONGLONG 202 NTAPI 203 KeQueryInterruptTime(VOID) 204 { 205 LARGE_INTEGER CurrentTime; 206 207 /* Loop until we get a perfect match */ 208 for (;;) 209 { 210 /* Read the time value */ 211 CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time; 212 CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart; 213 if (CurrentTime.HighPart == 214 SharedUserData->InterruptTime.High2Time) break; 215 YieldProcessor(); 216 } 217 218 /* Return the time value */ 219 return CurrentTime.QuadPart; 220 } 221 #endif 222 223 /* 224 * @implemented 225 */ 226 VOID 227 NTAPI 228 KeSetTimeIncrement(IN ULONG MaxIncrement, 229 IN ULONG MinIncrement) 230 { 231 /* Set some Internal Variables */ 232 KeMaximumIncrement = MaxIncrement; 233 KeMinimumIncrement = max(MinIncrement, 10000); 234 KeTimeAdjustment = MaxIncrement; 235 KeTimeIncrement = MaxIncrement; 236 KiTickOffset = MaxIncrement; 237 } 238 239 /* EOF */ 240