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
KeSetSystemTime(IN PLARGE_INTEGER NewTime,OUT PLARGE_INTEGER OldTime,IN BOOLEAN FixInterruptTime,IN PLARGE_INTEGER HalTime OPTIONAL)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
KeQueryTimeIncrement(VOID)153 KeQueryTimeIncrement(VOID)
154 {
155 /* Return the increment */
156 return KeMaximumIncrement;
157 }
158
159 /*
160 * @implemented
161 */
162 #undef KeQueryTickCount
163 VOID
164 NTAPI
KeQueryTickCount(IN PLARGE_INTEGER TickCount)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
KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)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
KeQueryInterruptTime(VOID)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
KeSetTimeIncrement(IN ULONG MaxIncrement,IN ULONG MinIncrement)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