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
;
43 PKTIMER_TABLE_ENTRY TimerEntry
;
46 ASSERT((NewTime
->HighPart
& 0xF0000000) == 0);
47 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL
);
49 /* Check if this is for the HAL */
50 if (HalTime
) RtlTimeToTimeFields(HalTime
, &TimeFields
);
52 /* Set affinity to this CPU, lock the dispatcher, and raise IRQL */
53 KeSetSystemAffinityThread(1);
54 OldIrql
= KiAcquireDispatcherLock();
55 KeRaiseIrql(HIGH_LEVEL
, &OldIrql2
);
57 /* Query the system time now */
58 KeQuerySystemTime(OldTime
);
60 /* Set the new system time */
61 SharedUserData
->SystemTime
.LowPart
= NewTime
->LowPart
;
62 SharedUserData
->SystemTime
.High1Time
= NewTime
->HighPart
;
63 SharedUserData
->SystemTime
.High2Time
= NewTime
->HighPart
;
65 /* Check if this was for the HAL and set the RTC time */
66 if (HalTime
) ExCmosClockIsSane
= HalSetRealTimeClock(&TimeFields
);
68 /* Calculate the difference between the new and the old time */
69 DeltaTime
.QuadPart
= NewTime
->QuadPart
- OldTime
->QuadPart
;
71 /* Update system boot time */
72 KeBootTime
.QuadPart
+= DeltaTime
.QuadPart
;
73 KeBootTimeBias
= KeBootTimeBias
+ DeltaTime
.QuadPart
;
76 KeLowerIrql(OldIrql2
);
78 /* Check if we need to adjust interrupt time */
79 if (FixInterruptTime
) KEBUGCHECK(0);
81 /* Setup a temporary list of absolute timers */
82 InitializeListHead(&TempList
);
84 /* Loop current timers */
85 for (i
= 0; i
< TIMER_TABLE_SIZE
; i
++)
87 /* Loop the entries in this table and lock the timers */
88 ListHead
= &KiTimerTableListHead
[i
].Entry
;
89 LockQueue
= KiAcquireTimerLock(i
);
90 NextEntry
= ListHead
->Flink
;
91 while (NextEntry
!= ListHead
)
94 Timer
= CONTAINING_RECORD(NextEntry
, KTIMER
, TimerListEntry
);
95 NextEntry
= NextEntry
->Flink
;
98 if (Timer
->Header
.Absolute
)
100 /* Remove it from the timer list */
101 if (RemoveEntryList(&Timer
->TimerListEntry
))
103 /* Get the entry and check if it's empty */
104 TimerEntry
= &KiTimerTableListHead
[Timer
->Header
.Hand
];
105 if (IsListEmpty(&TimerEntry
->Entry
))
107 /* Clear the time then */
108 TimerEntry
->Time
.HighPart
= 0xFFFFFFFF;
112 /* Insert it into our temporary list */
113 InsertTailList(&TempList
, &Timer
->TimerListEntry
);
117 /* Release the lock */
118 KiReleaseTimerLock(LockQueue
);
121 /* Setup a temporary list of expired timers */
122 InitializeListHead(&TempList2
);
124 /* Loop absolute timers */
125 while (TempList
.Flink
!= &TempList
)
128 Timer
= CONTAINING_RECORD(TempList
.Flink
, KTIMER
, TimerListEntry
);
129 RemoveEntryList(&Timer
->TimerListEntry
);
131 /* Update the due time and handle */
132 Timer
->DueTime
.QuadPart
-= DeltaTime
.QuadPart
;
133 Hand
= KiComputeTimerTableIndex(Timer
->DueTime
.QuadPart
);
134 Timer
->Header
.Hand
= (UCHAR
)Hand
;
136 /* Lock the timer and re-insert it */
137 LockQueue
= KiAcquireTimerLock(Hand
);
138 if (KiInsertTimerTable(Timer
, Hand
))
140 /* Remove it from the timer list */
141 if (RemoveEntryList(&Timer
->TimerListEntry
))
143 /* Get the entry and check if it's empty */
144 TimerEntry
= &KiTimerTableListHead
[Timer
->Header
.Hand
];
145 if (IsListEmpty(&TimerEntry
->Entry
))
147 /* Clear the time then */
148 TimerEntry
->Time
.HighPart
= 0xFFFFFFFF;
152 /* Insert it into our temporary list */
153 InsertTailList(&TempList2
, &Timer
->TimerListEntry
);
156 /* Release the lock */
157 KiReleaseTimerLock(LockQueue
);
160 /* FIXME: Process expired timers! */
161 KiReleaseDispatcherLock(OldIrql
);
163 /* Revert affinity */
164 KeRevertToUserAffinityThread();
167 /* PUBLIC FUNCTIONS **********************************************************/
174 KeQueryTimeIncrement(VOID
)
176 /* Return the increment */
177 return KeMaximumIncrement
;
183 #undef KeQueryTickCount
186 KeQueryTickCount(IN PLARGE_INTEGER TickCount
)
188 /* Loop until we get a perfect match */
191 /* Read the tick count value */
192 TickCount
->HighPart
= KeTickCount
.High1Time
;
193 TickCount
->LowPart
= KeTickCount
.LowPart
;
194 if (TickCount
->HighPart
== KeTickCount
.High2Time
) break;
205 KeQuerySystemTime(OUT PLARGE_INTEGER CurrentTime
)
207 /* Loop until we get a perfect match */
210 /* Read the time value */
211 CurrentTime
->HighPart
= SharedUserData
->SystemTime
.High1Time
;
212 CurrentTime
->LowPart
= SharedUserData
->SystemTime
.LowPart
;
213 if (CurrentTime
->HighPart
==
214 SharedUserData
->SystemTime
.High2Time
) break;
224 KeQueryInterruptTime(VOID
)
226 LARGE_INTEGER CurrentTime
;
228 /* Loop until we get a perfect match */
231 /* Read the time value */
232 CurrentTime
.HighPart
= SharedUserData
->InterruptTime
.High1Time
;
233 CurrentTime
.LowPart
= SharedUserData
->InterruptTime
.LowPart
;
234 if (CurrentTime
.HighPart
==
235 SharedUserData
->InterruptTime
.High2Time
) break;
239 /* Return the time value */
240 return CurrentTime
.QuadPart
;
249 KeSetTimeIncrement(IN ULONG MaxIncrement
,
250 IN ULONG MinIncrement
)
252 /* Set some Internal Variables */
253 KeMaximumIncrement
= MaxIncrement
;
254 KeMinimumIncrement
= max(MinIncrement
, 10000);
255 KeTimeAdjustment
= MaxIncrement
;
256 KeTimeIncrement
= MaxIncrement
;
257 KiTickOffset
= MaxIncrement
;
262 NtQueryTimerResolution(OUT PULONG MinimumResolution
,
263 OUT PULONG MaximumResolution
,
264 OUT PULONG ActualResolution
)
267 return STATUS_NOT_IMPLEMENTED
;
272 NtSetTimerResolution(IN ULONG DesiredResolution
,
273 IN BOOLEAN SetResolution
,
274 OUT PULONG CurrentResolution
)
277 return STATUS_NOT_IMPLEMENTED
;