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, 0, 0 };
20 ULONG KeMaximumIncrement
;
21 ULONG KeMinimumIncrement
;
22 ULONG KeTimeIncrement
;
24 /* PRIVATE FUNCTIONS *********************************************************/
28 KeSetSystemTime(IN PLARGE_INTEGER NewTime
,
29 OUT PLARGE_INTEGER OldTime
,
30 IN BOOLEAN FixInterruptTime
,
31 IN PLARGE_INTEGER HalTime OPTIONAL
)
33 TIME_FIELDS TimeFields
;
34 KIRQL OldIrql
, OldIrql2
;
35 LARGE_INTEGER DeltaTime
;
36 PLIST_ENTRY ListHead
, NextEntry
;
38 PKSPIN_LOCK_QUEUE LockQueue
;
39 LIST_ENTRY TempList
, TempList2
;
43 ASSERT((NewTime
->HighPart
& 0xF0000000) == 0);
44 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
46 /* Check if this is for the HAL */
47 if (HalTime
) RtlTimeToTimeFields(HalTime
, &TimeFields
);
49 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
50 KeSetSystemAffinityThread(1);
51 OldIrql
= KiAcquireDispatcherLock();
52 KeRaiseIrql(HIGH_LEVEL
, &OldIrql2
);
54 /* Query the system time now */
55 KeQuerySystemTime(OldTime
);
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
;
62 /* Check if this was for the HAL and set the RTC time */
63 if (HalTime
) ExCmosClockIsSane
= HalSetRealTimeClock(&TimeFields
);
65 /* Calculate the difference between the new and the old time */
66 DeltaTime
.QuadPart
= NewTime
->QuadPart
- OldTime
->QuadPart
;
68 /* Update system boot time */
69 KeBootTime
.QuadPart
+= DeltaTime
.QuadPart
;
70 KeBootTimeBias
= KeBootTimeBias
+ DeltaTime
.QuadPart
;
73 KeLowerIrql(OldIrql2
);
75 /* Check if we need to adjust interrupt time */
76 if (FixInterruptTime
) ASSERT(FALSE
);
78 /* Setup a temporary list of absolute timers */
79 InitializeListHead(&TempList
);
81 /* Loop current timers */
82 for (i
= 0; i
< TIMER_TABLE_SIZE
; i
++)
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
)
91 Timer
= CONTAINING_RECORD(NextEntry
, KTIMER
, TimerListEntry
);
92 NextEntry
= NextEntry
->Flink
;
95 if (Timer
->Header
.Absolute
)
97 /* Remove it from the timer list */
98 KiRemoveEntryTimer(Timer
);
100 /* Insert it into our temporary list */
101 InsertTailList(&TempList
, &Timer
->TimerListEntry
);
105 /* Release the lock */
106 KiReleaseTimerLock(LockQueue
);
109 /* Setup a temporary list of expired timers */
110 InitializeListHead(&TempList2
);
112 /* Loop absolute timers */
113 while (TempList
.Flink
!= &TempList
)
116 Timer
= CONTAINING_RECORD(TempList
.Flink
, KTIMER
, TimerListEntry
);
117 RemoveEntryList(&Timer
->TimerListEntry
);
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
;
124 /* Lock the timer and re-insert it */
125 LockQueue
= KiAcquireTimerLock(Hand
);
126 if (KiInsertTimerTable(Timer
, Hand
))
128 /* Remove it from the timer list */
129 KiRemoveEntryTimer(Timer
);
131 /* Insert it into our temporary list */
132 InsertTailList(&TempList2
, &Timer
->TimerListEntry
);
135 /* Release the lock */
136 KiReleaseTimerLock(LockQueue
);
139 /* Process expired timers. This releases the dispatcher lock. */
140 KiTimerListExpire(&TempList2
, OldIrql
);
142 /* Revert affinity */
143 KeRevertToUserAffinityThread();
146 /* PUBLIC FUNCTIONS **********************************************************/
153 KeQueryTimeIncrement(VOID
)
155 /* Return the increment */
156 return KeMaximumIncrement
;
162 #undef KeQueryTickCount
165 KeQueryTickCount(IN PLARGE_INTEGER TickCount
)
167 /* Loop until we get a perfect match */
170 /* Read the tick count value */
171 TickCount
->HighPart
= KeTickCount
.High1Time
;
172 TickCount
->LowPart
= KeTickCount
.LowPart
;
173 if (TickCount
->HighPart
== KeTickCount
.High2Time
) break;
184 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime
)
186 /* Loop until we get a perfect match */
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;
203 KeQueryInterruptTime(VOID
)
205 LARGE_INTEGER CurrentTime
;
207 /* Loop until we get a perfect match */
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;
218 /* Return the time value */
219 return CurrentTime
.QuadPart
;
228 KeSetTimeIncrement(IN ULONG MaxIncrement
,
229 IN ULONG MinIncrement
)
231 /* Set some Internal Variables */
232 KeMaximumIncrement
= MaxIncrement
;
233 KeMinimumIncrement
= max(MinIncrement
, 10000);
234 KeTimeAdjustment
= MaxIncrement
;
235 KeTimeIncrement
= MaxIncrement
;
236 KiTickOffset
= MaxIncrement
;
241 NtQueryTimerResolution(OUT PULONG MinimumResolution
,
242 OUT PULONG MaximumResolution
,
243 OUT PULONG ActualResolution
)
246 return STATUS_NOT_IMPLEMENTED
;
251 NtSetTimerResolution(IN ULONG DesiredResolution
,
252 IN BOOLEAN SetResolution
,
253 OUT PULONG CurrentResolution
)
256 return STATUS_NOT_IMPLEMENTED
;