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)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 LARGE_INTEGER KeBootTime
;
18 ULONGLONG KeBootTimeBias
;
19 volatile KSYSTEM_TIME KeTickCount
= {0};
20 ULONG KeMaximumIncrement
;
21 ULONG KeMinimumIncrement
;
22 ULONG KeTimeAdjustment
;
23 ULONG KeTimeIncrement
;
24 LONG KiTickOffset
= 0;
26 /* PRIVATE FUNCTIONS *********************************************************/
30 KeSetSystemTime(IN PLARGE_INTEGER NewTime
,
31 OUT PLARGE_INTEGER OldTime
,
32 IN BOOLEAN FixInterruptTime
,
33 IN PLARGE_INTEGER HalTime OPTIONAL
)
35 TIME_FIELDS TimeFields
;
36 KIRQL OldIrql
, OldIrql2
;
37 LARGE_INTEGER DeltaTime
;
38 PLIST_ENTRY ListHead
, NextEntry
;
40 PKSPIN_LOCK_QUEUE LockQueue
;
41 LIST_ENTRY TempList
, TempList2
;
45 ASSERT((NewTime
->HighPart
& 0xF0000000) == 0);
46 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
48 /* Check if this is for the HAL */
49 if (HalTime
) RtlTimeToTimeFields(HalTime
, &TimeFields
);
51 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
52 KeSetSystemAffinityThread(1);
53 OldIrql
= KiAcquireDispatcherLock();
54 KeRaiseIrql(HIGH_LEVEL
, &OldIrql2
);
56 /* Query the system time now */
57 KeQuerySystemTime(OldTime
);
59 /* Set the new system time (ordering of these operations is critical) */
60 SharedUserData
->SystemTime
.High2Time
= NewTime
->HighPart
;
61 SharedUserData
->SystemTime
.LowPart
= NewTime
->LowPart
;
62 SharedUserData
->SystemTime
.High1Time
= NewTime
->HighPart
;
64 /* Check if this was for the HAL and set the RTC time */
65 if (HalTime
) ExCmosClockIsSane
= HalSetRealTimeClock(&TimeFields
);
67 /* Calculate the difference between the new and the old time */
68 DeltaTime
.QuadPart
= NewTime
->QuadPart
- OldTime
->QuadPart
;
70 /* Update system boot time */
71 KeBootTime
.QuadPart
+= DeltaTime
.QuadPart
;
72 KeBootTimeBias
= KeBootTimeBias
+ DeltaTime
.QuadPart
;
75 KeLowerIrql(OldIrql2
);
77 /* Check if we need to adjust interrupt time */
78 if (FixInterruptTime
) ASSERT(FALSE
);
80 /* Setup a temporary list of absolute timers */
81 InitializeListHead(&TempList
);
83 /* Loop current timers */
84 for (i
= 0; i
< TIMER_TABLE_SIZE
; i
++)
86 /* Loop the entries in this table and lock the timers */
87 ListHead
= &KiTimerTableListHead
[i
].Entry
;
88 LockQueue
= KiAcquireTimerLock(i
);
89 NextEntry
= ListHead
->Flink
;
90 while (NextEntry
!= ListHead
)
93 Timer
= CONTAINING_RECORD(NextEntry
, KTIMER
, TimerListEntry
);
94 NextEntry
= NextEntry
->Flink
;
97 if (Timer
->Header
.Absolute
)
99 /* Remove it from the timer list */
100 KiRemoveEntryTimer(Timer
);
102 /* Insert it into our temporary list */
103 InsertTailList(&TempList
, &Timer
->TimerListEntry
);
107 /* Release the lock */
108 KiReleaseTimerLock(LockQueue
);
111 /* Setup a temporary list of expired timers */
112 InitializeListHead(&TempList2
);
114 /* Loop absolute timers */
115 while (TempList
.Flink
!= &TempList
)
118 Timer
= CONTAINING_RECORD(TempList
.Flink
, KTIMER
, TimerListEntry
);
119 RemoveEntryList(&Timer
->TimerListEntry
);
121 /* Update the due time and handle */
122 Timer
->DueTime
.QuadPart
-= DeltaTime
.QuadPart
;
123 Hand
= KiComputeTimerTableIndex(Timer
->DueTime
.QuadPart
);
124 Timer
->Header
.Hand
= (UCHAR
)Hand
;
126 /* Lock the timer and re-insert it */
127 LockQueue
= KiAcquireTimerLock(Hand
);
128 if (KiInsertTimerTable(Timer
, Hand
))
130 /* Remove it from the timer list */
131 KiRemoveEntryTimer(Timer
);
133 /* Insert it into our temporary list */
134 InsertTailList(&TempList2
, &Timer
->TimerListEntry
);
137 /* Release the lock */
138 KiReleaseTimerLock(LockQueue
);
141 /* Process expired timers. This releases the dispatcher lock. */
142 KiTimerListExpire(&TempList2
, OldIrql
);
144 /* Revert affinity */
145 KeRevertToUserAffinityThread();
148 /* PUBLIC FUNCTIONS **********************************************************/
155 KeQueryTimeIncrement(VOID
)
157 /* Return the increment */
158 return KeMaximumIncrement
;
164 #undef KeQueryTickCount
167 KeQueryTickCount(IN PLARGE_INTEGER TickCount
)
169 /* Loop until we get a perfect match */
172 /* Read the tick count value */
173 TickCount
->HighPart
= KeTickCount
.High1Time
;
174 TickCount
->LowPart
= KeTickCount
.LowPart
;
175 if (TickCount
->HighPart
== KeTickCount
.High2Time
) break;
186 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime
)
188 /* Loop until we get a perfect match */
191 /* Read the time value */
192 CurrentTime
->HighPart
= SharedUserData
->SystemTime
.High1Time
;
193 CurrentTime
->LowPart
= SharedUserData
->SystemTime
.LowPart
;
194 if (CurrentTime
->HighPart
==
195 SharedUserData
->SystemTime
.High2Time
) break;
205 KeQueryInterruptTime(VOID
)
207 LARGE_INTEGER CurrentTime
;
209 /* Loop until we get a perfect match */
212 /* Read the time value */
213 CurrentTime
.HighPart
= SharedUserData
->InterruptTime
.High1Time
;
214 CurrentTime
.LowPart
= SharedUserData
->InterruptTime
.LowPart
;
215 if (CurrentTime
.HighPart
==
216 SharedUserData
->InterruptTime
.High2Time
) break;
220 /* Return the time value */
221 return CurrentTime
.QuadPart
;
230 KeSetTimeIncrement(IN ULONG MaxIncrement
,
231 IN ULONG MinIncrement
)
233 /* Set some Internal Variables */
234 KeMaximumIncrement
= MaxIncrement
;
235 KeMinimumIncrement
= max(MinIncrement
, 10000);
236 KeTimeAdjustment
= MaxIncrement
;
237 KeTimeIncrement
= MaxIncrement
;
238 KiTickOffset
= MaxIncrement
;
243 NtQueryTimerResolution(OUT PULONG MinimumResolution
,
244 OUT PULONG MaximumResolution
,
245 OUT PULONG ActualResolution
)
248 return STATUS_NOT_IMPLEMENTED
;
253 NtSetTimerResolution(IN ULONG DesiredResolution
,
254 IN BOOLEAN SetResolution
,
255 OUT PULONG CurrentResolution
)
258 return STATUS_NOT_IMPLEMENTED
;