Update KIPCR, KPRCB, KTRAP_FRAME, KDESCRIPTOR, all based on vista x64 symbol files...
[reactos.git] / reactos / ntoskrnl / ke / clock.c
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};
20 volatile ULONG KiRawTicks = 0;
21 ULONG KeMaximumIncrement;
22 ULONG KeMinimumIncrement;
23 ULONG KeTimeAdjustment;
24 ULONG KeTimeIncrement;
25 LONG KiTickOffset = 0;
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 VOID
30 NTAPI
31 KeSetSystemTime(IN PLARGE_INTEGER NewTime,
32 OUT PLARGE_INTEGER OldTime,
33 IN BOOLEAN FixInterruptTime,
34 IN PLARGE_INTEGER HalTime OPTIONAL)
35 {
36 TIME_FIELDS TimeFields;
37 KIRQL OldIrql, OldIrql2;
38 LARGE_INTEGER DeltaTime;
39 PLIST_ENTRY ListHead, NextEntry;
40 PKTIMER Timer;
41 PKSPIN_LOCK_QUEUE LockQueue;
42 LIST_ENTRY TempList, TempList2;
43 ULONG Hand, i;
44 PKTIMER_TABLE_ENTRY TimerEntry;
45
46 /* Sanity checks */
47 ASSERT((NewTime->HighPart & 0xF0000000) == 0);
48 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
49
50 /* Check if this is for the HAL */
51 if (HalTime) RtlTimeToTimeFields(HalTime, &TimeFields);
52
53 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
54 KeSetSystemAffinityThread(1);
55 OldIrql = KiAcquireDispatcherLock();
56 KeRaiseIrql(HIGH_LEVEL, &OldIrql2);
57
58 /* Query the system time now */
59 KeQuerySystemTime(OldTime);
60
61 /* Set the new system time */
62 SharedUserData->SystemTime.LowPart = NewTime->LowPart;
63 SharedUserData->SystemTime.High1Time = NewTime->HighPart;
64 SharedUserData->SystemTime.High2Time = NewTime->HighPart;
65
66 /* Check if this was for the HAL and set the RTC time */
67 if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
68
69 /* Calculate the difference between the new and the old time */
70 DeltaTime.QuadPart = NewTime->QuadPart - OldTime->QuadPart;
71
72 /* Update system boot time */
73 KeBootTime.QuadPart += DeltaTime.QuadPart;
74 KeBootTimeBias = KeBootTimeBias + DeltaTime.QuadPart;
75
76 /* Lower IRQL back */
77 KeLowerIrql(OldIrql2);
78
79 /* Check if we need to adjust interrupt time */
80 if (FixInterruptTime) KEBUGCHECK(0);
81
82 /* Setup a temporary list of absolute timers */
83 InitializeListHead(&TempList);
84
85 /* Loop current timers */
86 for (i = 0; i < TIMER_TABLE_SIZE; i++)
87 {
88 /* Loop the entries in this table and lock the timers */
89 ListHead = &KiTimerTableListHead[i].Entry;
90 LockQueue = KiAcquireTimerLock(i);
91 NextEntry = ListHead->Flink;
92 while (NextEntry != ListHead)
93 {
94 /* Get the timer */
95 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
96 NextEntry = NextEntry->Flink;
97
98 /* Is is absolute? */
99 if (Timer->Header.Absolute)
100 {
101 /* Remove it from the timer list */
102 if (RemoveEntryList(&Timer->TimerListEntry))
103 {
104 /* Get the entry and check if it's empty */
105 TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
106 if (IsListEmpty(&TimerEntry->Entry))
107 {
108 /* Clear the time then */
109 TimerEntry->Time.HighPart = 0xFFFFFFFF;
110 }
111 }
112
113 /* Insert it into our temporary list */
114 InsertTailList(&TempList, &Timer->TimerListEntry);
115 }
116 }
117
118 /* Release the lock */
119 KiReleaseTimerLock(LockQueue);
120 }
121
122 /* Setup a temporary list of expired timers */
123 InitializeListHead(&TempList2);
124
125 /* Loop absolute timers */
126 while (TempList.Flink != &TempList)
127 {
128 /* Get the timer */
129 Timer = CONTAINING_RECORD(TempList.Flink, KTIMER, TimerListEntry);
130 RemoveEntryList(&Timer->TimerListEntry);
131
132 /* Update the due time and handle */
133 Timer->DueTime.QuadPart -= DeltaTime.QuadPart;
134 Hand = KiComputeTimerTableIndex(Timer->DueTime.QuadPart);
135 Timer->Header.Hand = (UCHAR)Hand;
136
137 /* Lock the timer and re-insert it */
138 LockQueue = KiAcquireTimerLock(Hand);
139 if (KiInsertTimerTable(Timer, Hand))
140 {
141 /* Remove it from the timer list */
142 if (RemoveEntryList(&Timer->TimerListEntry))
143 {
144 /* Get the entry and check if it's empty */
145 TimerEntry = &KiTimerTableListHead[Timer->Header.Hand];
146 if (IsListEmpty(&TimerEntry->Entry))
147 {
148 /* Clear the time then */
149 TimerEntry->Time.HighPart = 0xFFFFFFFF;
150 }
151 }
152
153 /* Insert it into our temporary list */
154 InsertTailList(&TempList2, &Timer->TimerListEntry);
155 }
156
157 /* Release the lock */
158 KiReleaseTimerLock(LockQueue);
159 }
160
161 /* FIXME: Process expired timers! */
162 KiReleaseDispatcherLock(OldIrql);
163
164 /* Revert affinity */
165 KeRevertToUserAffinityThread();
166 }
167
168 /* PUBLIC FUNCTIONS **********************************************************/
169
170 /*
171 * @implemented
172 */
173 ULONG
174 NTAPI
175 KeQueryTimeIncrement(VOID)
176 {
177 /* Return the increment */
178 return KeMaximumIncrement;
179 }
180
181 /*
182 * @implemented
183 */
184 #undef KeQueryTickCount
185 VOID
186 NTAPI
187 KeQueryTickCount(IN PLARGE_INTEGER TickCount)
188 {
189 /* Loop until we get a perfect match */
190 for (;;)
191 {
192 /* Read the tick count value */
193 TickCount->HighPart = KeTickCount.High1Time;
194 TickCount->LowPart = KeTickCount.LowPart;
195 if (TickCount->HighPart == KeTickCount.High2Time) break;
196 YieldProcessor();
197 }
198 }
199
200 #ifndef _M_AMD64
201 /*
202 * @implemented
203 */
204 VOID
205 NTAPI
206 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime)
207 {
208 /* Loop until we get a perfect match */
209 for (;;)
210 {
211 /* Read the time value */
212 CurrentTime->HighPart = SharedUserData->SystemTime.High1Time;
213 CurrentTime->LowPart = SharedUserData->SystemTime.LowPart;
214 if (CurrentTime->HighPart ==
215 SharedUserData->SystemTime.High2Time) break;
216 YieldProcessor();
217 }
218 }
219
220 /*
221 * @implemented
222 */
223 ULONGLONG
224 NTAPI
225 KeQueryInterruptTime(VOID)
226 {
227 LARGE_INTEGER CurrentTime;
228
229 /* Loop until we get a perfect match */
230 for (;;)
231 {
232 /* Read the time value */
233 CurrentTime.HighPart = SharedUserData->InterruptTime.High1Time;
234 CurrentTime.LowPart = SharedUserData->InterruptTime.LowPart;
235 if (CurrentTime.HighPart ==
236 SharedUserData->InterruptTime.High2Time) break;
237 YieldProcessor();
238 }
239
240 /* Return the time value */
241 return CurrentTime.QuadPart;
242 }
243 #endif
244
245 /*
246 * @implemented
247 */
248 VOID
249 NTAPI
250 KeSetTimeIncrement(IN ULONG MaxIncrement,
251 IN ULONG MinIncrement)
252 {
253 /* Set some Internal Variables */
254 KeMaximumIncrement = MaxIncrement;
255 KeMinimumIncrement = max(MinIncrement, 10000);
256 KeTimeAdjustment = MaxIncrement;
257 KeTimeIncrement = MaxIncrement;
258 KiTickOffset = MaxIncrement;
259 }
260
261 NTSTATUS
262 NTAPI
263 NtQueryTimerResolution(OUT PULONG MinimumResolution,
264 OUT PULONG MaximumResolution,
265 OUT PULONG ActualResolution)
266 {
267 UNIMPLEMENTED;
268 return STATUS_NOT_IMPLEMENTED;
269 }
270
271 NTSTATUS
272 NTAPI
273 NtSetTimerResolution(IN ULONG DesiredResolution,
274 IN BOOLEAN SetResolution,
275 OUT PULONG CurrentResolution)
276 {
277 UNIMPLEMENTED;
278 return STATUS_NOT_IMPLEMENTED;
279 }
280
281 /* EOF */