2 * FILE: ntoskrnl/ke/i386/clock.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Clock Management
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
8 /* INCLUDES ******************************************************************/
11 #include <internal/i386/asmmacro.S>
12 .intel_syntax noprefix
14 /* FUNCTIONS ******************************************************************/
16 .globl _KiComputeTimerTableIndex@8
17 .func KiComputeTimerTableIndex@8
18 _KiComputeTimerTableIndex@8:
23 /* Make the first multiplication */
25 mul dword ptr [_KiTimeIncrementReciprocal+4]
29 /* Make the second multiplication */
31 mul dword ptr [_KiTimeIncrementReciprocal]
35 /* Multiply by the reciprocal */
37 mul dword ptr [_KiTimeIncrementReciprocal]
40 mul dword ptr [_KiTimeIncrementReciprocal+4]
45 /* Shift the result and generate the index */
46 mov cl, [_KiTimeIncrementShiftCount]
48 and eax, TIMER_TABLE_SIZE - 1
55 .globl _KeUpdateRunTime@4
56 .func KeUpdateRunTime@4
60 mov eax, [fs:KPCR_SELF]
65 /* Increase interrupt count */
66 inc dword ptr [eax+KPCR_PRCB_INTERRUPT_COUNT]
68 /* Get the current thread and process */
69 mov ebx, [eax+KPCR_CURRENT_THREAD]
70 mov ecx, [ebx+KTHREAD_APCSTATE_PROCESS]
72 /* Check if this was V86 or user mode */
73 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
75 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
78 /* Increase kernel time */
79 inc dword ptr [eax+KPCR_PRCB_KERNEL_TIME]
81 /* Check if IRQL was DISPATCH_LEVEL */
82 cmp byte ptr [esp+8], DISPATCH_LEVEL
86 /* Check if the DPC routine is active */
87 cmp dword ptr[eax+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
90 /* At dispatch, increase DPC time */
91 inc dword ptr [eax+KPCR_PRCB_DPC_TIME]
95 /* Update interrupt time */
96 inc dword ptr [eax+KPCR_PRCB_INTERRUPT_TIME]
100 /* Update kernel time */
101 inc dword ptr [ebx+KTHREAD_KERNEL_TIME]
105 /* Update user time */
106 inc dword ptr [eax+KPCR_PRCB_USER_TIME]
107 inc dword ptr [ebx+KTHREAD_USER_TIME]
110 /* Get the DPC Count and last count, and set the ne wone */
111 mov ecx, [eax+KPCR_PRCB_DPC_COUNT]
112 mov edx, [eax+KPCR_PRCB_DPC_LAST_COUNT]
113 mov [eax+KPCR_PRCB_DPC_LAST_COUNT], ecx
115 /* Substract counts and add request rate, divide by two to get average */
117 add ecx, [eax+KPCR_PRCB_DPC_REQUEST_RATE]
120 /* Set this as the new request rate */
121 mov [eax+KPCR_PRCB_DPC_REQUEST_RATE], ecx
123 /* Check for depth > 0, DPCs to be inactive, and no other pending request */
124 cmp dword ptr [eax+KPCR_PRCB_DPC_QUEUE_DEPTH], 0
126 cmp byte ptr [eax+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
128 cmp byte ptr [eax+KPCR_PRCB_DPC_INTERRUPT_REQUESTED], 0
132 mov ecx, DISPATCH_LEVEL
133 call @HalRequestSoftwareInterrupt@4
135 /* Restore PCR address */
136 mov eax, [fs:KPCR_SELF]
138 /* Get the DPC request rate and threshold adjust, and set it */
139 mov ecx, [eax+KPCR_PRCB_DPC_REQUEST_RATE]
140 mov edx, _KiAdjustDpcThreshold
141 mov [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD], edx
143 /* Check if the rate now is not ideal */
144 cmp ecx, _KiIdealDpcRate
146 cmp dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH], 1
150 dec dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
154 /* We didn't request a DPC, decrease the threshold */
155 dec dword ptr [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD]
158 /* We're at 0 now, reset it */
159 mov ecx, _KiAdjustDpcThreshold
160 mov [eax+KPCR_PRCB_ADJUST_DPC_THRESHOLD], ecx
162 /* Get maximum depth and check it */
163 mov ecx, _KiMaximumDpcQueueDepth
164 cmp ecx, [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
167 /* Increase it, it's below maximum */
168 inc dword ptr [eax+KPCR_PRCB_MAXIMUM_DPC_QUEUE_DEPTH]
171 /* Decrement quantum and verify it */
172 sub byte ptr [ebx+KTHREAD_QUANTUM], CLOCK_QUANTUM_DECREMENT
175 /* Make sure this isn't the idle thread */
176 cmp ebx, [eax+KPCR_PRCB_IDLE_THREAD]
179 /* Set quantum end */
180 mov byte ptr [eax+KPCR_PRCB_QUANTUM_END], 1
181 mov ecx, DISPATCH_LEVEL
182 call @HalRequestSoftwareInterrupt@4
185 /* Restore ebx and return */
190 .globl _KeUpdateSystemTime@0
191 .func KeUpdateSystemTime@0
192 _KeUpdateSystemTime@0:
194 /* Get shared data in ECX */
195 mov ecx, USER_SHARED_DATA
197 /* Get interrupt time */
198 mov edi, [ecx+USER_SHARED_DATA_INTERRUPT_TIME]
199 mov esi, [ecx+USER_SHARED_DATA_INTERRUPT_TIME+4]
201 /* Add the increment and get the carry */
205 /* Now store the updated times */
206 mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME+8], esi
207 mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME], edi
208 mov [ecx+USER_SHARED_DATA_INTERRUPT_TIME+4], esi
210 /* Substract tick count and get the low count */
211 LOCK sub _KiTickOffset, eax
212 mov eax, _KeTickCount
216 /* Get shared data in ECX */
217 mov ebx, USER_SHARED_DATA
219 /* Get system time */
220 mov ecx, [ebx+USER_SHARED_DATA_SYSTEM_TIME]
221 mov edx, [ebx+USER_SHARED_DATA_SYSTEM_TIME+4]
223 /* Add the increment and get the carry */
224 add ecx, _KeTimeAdjustment
227 /* Now store the updated times */
228 mov [ebx+USER_SHARED_DATA_SYSTEM_TIME+8], edx
229 mov [ebx+USER_SHARED_DATA_SYSTEM_TIME], ecx
230 mov [ebx+USER_SHARED_DATA_SYSTEM_TIME+4], edx
232 /* Put tick count back in EBX */
235 /* Copyit in ECX and get hich count */
237 mov edx, _KeTickCount + 4
239 /* Add the increment and get the carry */
243 /* Now store the updated tick */
244 mov [_KeTickCount+8], edx
245 mov [_KeTickCount], ecx
246 mov [_KeTickCount+4], edx
248 /* Store in in shared data too */
249 mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT+8], edx
250 mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT], ecx
251 mov ds:[USER_SHARED_DATA+USER_SHARED_DATA_TICK_COUNT+4], edx
254 mov ds:[USER_SHARED_DATA], ecx
256 /* Get hand index and entry into the table */
257 and eax, TIMER_TABLE_SIZE - 1
260 /* Compare the due time */
261 cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4]
264 cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME]
268 /* Move to the next hand */
274 /* Get hand index and entry into the table */
275 and eax, TIMER_TABLE_SIZE - 1
278 /* Compare the due time */
279 cmp esi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME+4]
282 cmp edi, [eax+_KiTimerTableListHead+KTIMER_TABLE_TIME]
287 /* Check if expiration is active */
288 mov ecx, [fs:KPCR_PRCB]
289 cmp dword ptr [ecx+KPRCB_TIMER_REQUEST], 0
292 /* It's not, register it */
293 mov [ecx+KPRCB_TIMER_REQUEST], esp
294 mov [ecx+KPRCB_TIMER_HAND], ebx
295 mov ecx, DISPATCH_LEVEL
296 call @HalRequestSoftwareInterrupt@4
299 /* FIXME: Check for KdDebuggerEnabled */
301 /* Check if this was a full tick */
302 cmp dword ptr _KiTickOffset, 0
305 /* Increase tick offset */
306 mov eax, _KeMaximumIncrement
307 add _KiTickOffset, eax
309 /* Update system run time */
311 call _KeUpdateRunTime@4
315 /* Increase interrupt count */
316 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
319 /* Exit the interrupt */
321 call _HalEndSystemInterrupt@8
322 jmp _Kei386EoiHelper@0