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 volatile ULONG KiRawTicks
= 0;
21 ULONG KeMaximumIncrement
;
22 ULONG KeMinimumIncrement
;
23 ULONG KeTimeAdjustment
;
24 ULONG KeTimeIncrement
;
25 LONG KiTickOffset
= 0;
27 /* PRIVATE FUNCTIONS *********************************************************/
31 KeSetSystemTime(IN PLARGE_INTEGER NewTime
,
32 OUT PLARGE_INTEGER OldTime
,
33 IN BOOLEAN FixInterruptTime
,
34 IN PLARGE_INTEGER HalTime OPTIONAL
)
36 TIME_FIELDS TimeFields
;
37 KIRQL OldIrql
, OldIrql2
;
38 LARGE_INTEGER DeltaTime
;
39 PLIST_ENTRY ListHead
, NextEntry
;
41 PKSPIN_LOCK_QUEUE LockQueue
;
42 LIST_ENTRY TempList
, TempList2
;
44 PKTIMER_TABLE_ENTRY TimerEntry
;
47 ASSERT((NewTime
->HighPart
& 0xF0000000) == 0);
48 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
50 /* Check if this is for the HAL */
51 if (HalTime
) RtlTimeToTimeFields(HalTime
, &TimeFields
);
53 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
54 KeSetSystemAffinityThread(1);
55 OldIrql
= KiAcquireDispatcherLock();
56 KeRaiseIrql(HIGH_LEVEL
, &OldIrql2
);
58 /* Query the system time now */
59 KeQuerySystemTime(OldTime
);
61 /* Set the new system time */
62 SharedUserData
->SystemTime
.LowPart
= NewTime
->LowPart
;
63 SharedUserData
->SystemTime
.High1Time
= NewTime
->HighPart
;
64 SharedUserData
->SystemTime
.High2Time
= NewTime
->HighPart
;
66 /* Check if this was for the HAL and set the RTC time */
67 if (HalTime
) ExCmosClockIsSane
= HalSetRealTimeClock(&TimeFields
);
69 /* Calculate the difference between the new and the old time */
70 DeltaTime
.QuadPart
= NewTime
->QuadPart
- OldTime
->QuadPart
;
72 /* Update system boot time */
73 KeBootTime
.QuadPart
+= DeltaTime
.QuadPart
;
74 KeBootTimeBias
= KeBootTimeBias
+ DeltaTime
.QuadPart
;
77 KeLowerIrql(OldIrql2
);
79 /* Check if we need to adjust interrupt time */
80 if (FixInterruptTime
) KEBUGCHECK(0);
82 /* Setup a temporary list of absolute timers */
83 InitializeListHead(&TempList
);
85 /* Loop current timers */
86 for (i
= 0; i
< TIMER_TABLE_SIZE
; i
++)
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
)
95 Timer
= CONTAINING_RECORD(NextEntry
, KTIMER
, TimerListEntry
);
96 NextEntry
= NextEntry
->Flink
;
99 if (Timer
->Header
.Absolute
)
101 /* Remove it from the timer list */
102 if (RemoveEntryList(&Timer
->TimerListEntry
))
104 /* Get the entry and check if it's empty */
105 TimerEntry
= &KiTimerTableListHead
[Timer
->Header
.Hand
];
106 if (IsListEmpty(&TimerEntry
->Entry
))
108 /* Clear the time then */
109 TimerEntry
->Time
.HighPart
= 0xFFFFFFFF;
113 /* Insert it into our temporary list */
114 InsertTailList(&TempList
, &Timer
->TimerListEntry
);
118 /* Release the lock */
119 KiReleaseTimerLock(LockQueue
);
122 /* Setup a temporary list of expired timers */
123 InitializeListHead(&TempList2
);
125 /* Loop absolute timers */
126 while (TempList
.Flink
!= &TempList
)
129 Timer
= CONTAINING_RECORD(TempList
.Flink
, KTIMER
, TimerListEntry
);
130 RemoveEntryList(&Timer
->TimerListEntry
);
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
;
137 /* Lock the timer and re-insert it */
138 LockQueue
= KiAcquireTimerLock(Hand
);
139 if (KiInsertTimerTable(Timer
, Hand
))
141 /* Remove it from the timer list */
142 if (RemoveEntryList(&Timer
->TimerListEntry
))
144 /* Get the entry and check if it's empty */
145 TimerEntry
= &KiTimerTableListHead
[Timer
->Header
.Hand
];
146 if (IsListEmpty(&TimerEntry
->Entry
))
148 /* Clear the time then */
149 TimerEntry
->Time
.HighPart
= 0xFFFFFFFF;
153 /* Insert it into our temporary list */
154 InsertTailList(&TempList2
, &Timer
->TimerListEntry
);
157 /* Release the lock */
158 KiReleaseTimerLock(LockQueue
);
161 /* FIXME: Process expired timers! */
162 KiReleaseDispatcherLock(OldIrql
);
164 /* Revert affinity */
165 KeRevertToUserAffinityThread();
168 /* PUBLIC FUNCTIONS **********************************************************/
175 KeQueryTimeIncrement(VOID
)
177 /* Return the increment */
178 return KeMaximumIncrement
;
184 #undef KeQueryTickCount
187 KeQueryTickCount(IN PLARGE_INTEGER TickCount
)
189 /* Loop until we get a perfect match */
192 /* Read the tick count value */
193 TickCount
->HighPart
= KeTickCount
.High1Time
;
194 TickCount
->LowPart
= KeTickCount
.LowPart
;
195 if (TickCount
->HighPart
== KeTickCount
.High2Time
) break;
206 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime
)
208 /* Loop until we get a perfect match */
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;
225 KeQueryInterruptTime(VOID
)
227 LARGE_INTEGER CurrentTime
;
229 /* Loop until we get a perfect match */
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;
240 /* Return the time value */
241 return CurrentTime
.QuadPart
;
250 KeSetTimeIncrement(IN ULONG MaxIncrement
,
251 IN ULONG MinIncrement
)
253 /* Set some Internal Variables */
254 KeMaximumIncrement
= MaxIncrement
;
255 KeMinimumIncrement
= max(MinIncrement
, 10000);
256 KeTimeAdjustment
= MaxIncrement
;
257 KeTimeIncrement
= MaxIncrement
;
258 KiTickOffset
= MaxIncrement
;
263 NtQueryTimerResolution(OUT PULONG MinimumResolution
,
264 OUT PULONG MaximumResolution
,
265 OUT PULONG ActualResolution
)
268 return STATUS_NOT_IMPLEMENTED
;
273 NtSetTimerResolution(IN ULONG DesiredResolution
,
274 IN BOOLEAN SetResolution
,
275 OUT PULONG CurrentResolution
)
278 return STATUS_NOT_IMPLEMENTED
;