[NTOS]
[reactos.git] / reactos / ntoskrnl / ke / arm / time.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/arm/time.c
5 * PURPOSE: Implements timebase functionality on ARM processors
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 LONG KiTickOffset;
18 ULONG KeTimeAdjustment;
19
20 /* FUNCTIONS ******************************************************************/
21
22 ULONG
23 KiComputeTimerTableIndex(IN LONGLONG DueTime)
24 {
25 ULONG Hand;
26
27 //
28 // Compute the timer table index
29 //
30 Hand = (DueTime / KeMaximumIncrement);
31 Hand %= TIMER_TABLE_SIZE;
32 return Hand;
33 }
34
35 VOID
36 NTAPI
37 KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
38 IN KIRQL Irql,
39 IN ULONG Increment)
40 {
41 PKPRCB Prcb = KeGetPcr()->Prcb;
42 ULARGE_INTEGER SystemTime, InterruptTime;
43 ULONG Hand;
44
45 //
46 // Do nothing if this tick is being skipped
47 //
48 if (Prcb->SkipTick)
49 {
50 //
51 // Handle it next time
52 //
53 Prcb->SkipTick = FALSE;
54 return;
55 }
56
57 //
58 // Add the increment time to the shared data
59 //
60 InterruptTime.HighPart = SharedUserData->InterruptTime.High1Time;
61 InterruptTime.LowPart = SharedUserData->InterruptTime.LowPart;
62 InterruptTime.QuadPart += Increment;
63 SharedUserData->InterruptTime.High1Time = InterruptTime.HighPart;
64 SharedUserData->InterruptTime.LowPart = InterruptTime.LowPart;
65 SharedUserData->InterruptTime.High2Time = InterruptTime.HighPart;
66
67 //
68 // Update tick count
69 //
70 KiTickOffset -= Increment;
71
72 //
73 // Check for incomplete tick
74 //
75 if (KiTickOffset <= 0)
76 {
77 //
78 // Update the system time
79 //
80 SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
81 SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
82 SystemTime.QuadPart += KeTimeAdjustment;
83 SharedUserData->SystemTime.High1Time = SystemTime.HighPart;
84 SharedUserData->SystemTime.LowPart = SystemTime.LowPart;
85 SharedUserData->SystemTime.High2Time = SystemTime.HighPart;
86
87 //
88 // Update the tick count
89 //
90 SystemTime.HighPart = KeTickCount.High1Time;
91 SystemTime.LowPart = KeTickCount.LowPart;
92 SystemTime.QuadPart += 1;
93 KeTickCount.High1Time = SystemTime.HighPart;
94 KeTickCount.LowPart = SystemTime.LowPart;
95 KeTickCount.High2Time = SystemTime.HighPart;
96
97 //
98 // Update it in the shared user data
99 //
100 SharedUserData->TickCount.High1Time = SystemTime.HighPart;
101 SharedUserData->TickCount.LowPart = SystemTime.LowPart;
102 SharedUserData->TickCount.High2Time = SystemTime.HighPart;
103 }
104
105 //
106 // Check for timer expiration
107 //
108 Hand = KeTickCount.LowPart % TIMER_TABLE_SIZE;
109 if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
110 {
111 //
112 // Check if we are already doing expiration
113 //
114 if (!Prcb->TimerRequest)
115 {
116 //
117 // Request a DPC to handle this
118 //
119 Prcb->TimerRequest = TrapFrame->SvcSp;
120 Prcb->TimerHand = Hand;
121 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
122 }
123 }
124
125 //
126 // Check if we should request a debugger break
127 //
128 if (KdDebuggerEnabled)
129 {
130 //
131 // Check if we should break
132 //
133 if (KdPollBreakIn()) DbgBreakPointWithStatus(DBG_STATUS_CONTROL_C);
134 }
135
136 //
137 // Check if this was a full tick
138 //
139 if (KiTickOffset <= 0)
140 {
141 //
142 // Updare the tick offset
143 //
144 KiTickOffset += KeMaximumIncrement;
145
146 //
147 // Update system runtime
148 //
149 KeUpdateRunTime(TrapFrame, CLOCK2_LEVEL);
150 }
151 else
152 {
153 //
154 // Increase interrupt count and exit
155 //
156 Prcb->InterruptCount++;
157 }
158 }
159
160 VOID
161 NTAPI
162 KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame,
163 IN KIRQL Irql)
164 {
165 PKTHREAD Thread = KeGetCurrentThread();
166 PKPROCESS Process = Thread->ApcState.Process;
167 PKPRCB Prcb = KeGetCurrentPrcb();
168
169 //
170 // Do nothing if this tick is being skipped
171 //
172 if (Prcb->SkipTick)
173 {
174 //
175 // Handle it next time
176 //
177 Prcb->SkipTick = FALSE;
178 return;
179 }
180
181 //
182 // Increase interrupt count
183 //
184 Prcb->InterruptCount++;
185
186 //
187 // Check if we came from user mode
188 //
189 if (TrapFrame->PreviousMode != KernelMode)
190 {
191 //
192 // Increase process user time
193 //
194 InterlockedIncrement((PLONG)&Process->UserTime);
195 Prcb->UserTime++;
196 Thread->UserTime++;
197 }
198 else
199 {
200 //
201 // See if we were in an ISR
202 //
203 if (TrapFrame->OldIrql > DISPATCH_LEVEL)
204 {
205 //
206 // Handle that
207 //
208 Prcb->InterruptTime++;
209 }
210 else if ((TrapFrame->OldIrql < DISPATCH_LEVEL) ||
211 !(Prcb->DpcRoutineActive))
212 {
213 //
214 // Handle being in kernel mode
215 //
216 Thread->KernelTime++;
217 InterlockedIncrement((PLONG)&Process->KernelTime);
218 }
219 else
220 {
221 //
222 // Handle being in a DPC
223 //
224 Prcb->DpcTime++;
225
226 //
227 // Update Debug DPC time
228 //
229 Prcb->DebugDpcTime++;
230
231 //
232 // Check if we've timed out
233 //
234 if (Prcb->DebugDpcTime >= KiDPCTimeout)
235 {
236 //
237 // Print a message
238 //
239 DbgPrint("\n*** DPC routine > 1 sec --- This is not a break in "
240 "KeUpdateSystemTime\n");
241
242 //
243 // Break if a debugger is attached
244 //
245 if (KdDebuggerEnabled) DbgBreakPoint();
246
247 //
248 // Restore the debug DPC time
249 //
250 Prcb->DebugDpcTime = 0;
251 }
252 }
253 }
254
255 //
256 // Update DPC rates
257 //
258 Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
259 Prcb->DpcRequestRate) >> 1;
260 Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
261
262 //
263 // Check if the queue is large enough
264 //
265 if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
266 {
267 //
268 // Request a DPC
269 //
270 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
271 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
272
273 //
274 // Fix the maximum queue depth
275 //
276 if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
277 (Prcb->MaximumDpcQueueDepth > 1))
278 {
279 //
280 // Make it smaller
281 //
282 Prcb->MaximumDpcQueueDepth--;
283 }
284 }
285 else
286 {
287 //
288 // Check if we've reached the adjustment limit
289 //
290 if (!(--Prcb->AdjustDpcThreshold))
291 {
292 //
293 // Reset it, and check the queue maximum
294 //
295 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
296 if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
297 {
298 //
299 // Increase it
300 //
301 Prcb->MaximumDpcQueueDepth++;
302 }
303 }
304 }
305
306 //
307 // Decrement the thread quantum
308 //
309 Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
310
311 //
312 // Check if the time expired
313 //
314 if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
315 {
316 //
317 // Schedule a quantum end
318 //
319 Prcb->QuantumEnd = 1;
320 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
321 }
322 }