2 * FILE: hal/halx86/generic/timer.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Timer Interrupt and Management
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
8 /* INCLUDES ******************************************************************/
11 .intel_syntax noprefix
13 /* GLOBALS *******************************************************************/
15 .globl _HalpPerfCounter
16 _HalpLastPerfCounterLow: .long 0
17 _HalpLastPerfCounterHigh: .long 0
19 _HalpPerfCounterLow: .long 0
20 _HalpPerfCounterHigh: .long 0
21 _HalpSystemHardwareFlags: .long 0
24 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
26 /* FUNCTIONS *****************************************************************/
28 .global _HalpCalibrateStallExecution@0
29 .func HalpCalibrateStallExecution@0
30 _HalpCalibrateStallExecution@0:
32 /* Setup the stack frame */
37 /* Save EFLAGS and kill interrupts */
41 /* Get the current interrupt mask on the PICs */
50 /* Now mask everything except the RTC and PIC 2 chain-interrupt */
51 mov eax, ~((1 << 2) | (1 << 8))
53 /* Program the PICs */
62 /* Get the IDT entry for the RTC */
67 /* Save the original RTC ISR */
72 /* Now load our new handler */
73 mov eax, offset OnlyOnePersonCanWriteHalCode
75 mov word ptr [ecx+2], KGDT_R0_CODE
76 mov word ptr [ecx+4], 0x8E00
80 /* Reset our counter */
81 mov dword ptr [ebp-12], 0
83 /* Acquire CMOS lock */
84 call _HalpAcquireSystemHardwareSpinLock@0
86 /* Now initialize register A on the CMOS */
87 mov ax, (0x2D << 8) | 0xA
101 /* Don't touch the LastKnownGoodConfig hack */
105 /* Enable the interrupt */
108 /* Now write the register B */
116 /* Read register C */
123 /* Read register D */
130 /* Release CMOS lock */
131 mov dword ptr [ebp-12], 0
132 call _HalpReleaseCmosSpinLock@0
134 /* Initialize looper */
137 /* Align to 16 bytes */
140 /* Enable interrupts! */
144 /* Align to 16 bytes */
147 /* Subtract one count */
152 /* ASSERT: If we got here, then the RTC never fired */
153 call _DbgBreakPoint@0
156 OnlyOnePersonCanWriteHalCode:
157 /*********************** THIS IS THE RTC HANDLER **************************/
159 /* Increment the interrupt count and check if this is the first one */
160 inc dword ptr [ebp-12]
161 cmp dword ptr [ebp-12], 1
165 * It is the first one -- we'll ignore it, since it fires randomly!
166 * Get rid of the old return address and push the new one in (our looper)
171 /* Acquire CMOS lock */
172 call _HalpAcquireSystemHardwareSpinLock@0
174 /* Now initialize register A on the CMOS */
175 mov ax, (0x2D << 8) | 0xA
182 /* Read register B */
189 /* Don't touch the LastKnownGoodConfig hack */
193 /* Enable the interrupt */
196 /* Now write the register B */
204 /* Read register C */
211 /* Read register D */
218 /* Release CMOS lock */
219 call _HalpReleaseCmosSpinLock@0
221 /* Dismiss the interrupt */
227 /* Reset the counter and return back to the looper */
231 /******************* THIS IS THE 2ND RTC HANDLER **************************/
234 /* Do the calculation */
237 mov ecx, 125000 /* RTC fires every 125 ms */
240 /* Is the remainder 0? */
244 /* Otherwise fix-up the loop count */
248 /* Save the stall scale factor */
249 mov fs:[KPCR_STALL_SCALE_FACTOR], eax
251 /* Prepare for interrupt return */
253 push offset AndItsNotYou
256 /* Acquire CMOS lock */
257 call _HalpAcquireSystemHardwareSpinLock@0
259 /* Now initialize register A on the CMOS */
260 mov ax, (0x2D << 8) | 0xA
267 /* Read register B */
274 /* Don't touch the LastKnownGoodConfig hack */
278 /* Disable the interrupt */
281 /* Now write the register B */
289 /* Read register C */
296 /* Release CMOS lock */
297 call _HalpReleaseCmosSpinLock@0
299 /* Dismiss the interrupt */
305 /* Disable interrupts on return */
306 and word ptr [esp+8], ~EFLAGS_INTERRUPT_MASK
309 /************************* WE ARE BACK FROM RTC ***************************/
312 /* Restore the IDT */
317 /* Restore the mask */
326 /* Restore stack and return */
332 .globl _KeStallExecutionProcessor@4
333 .func KeStallExecutionProcessor@4
334 _KeStallExecutionProcessor@4:
336 /* Get the number of microseconds required */
340 /* Multiply by the stall factor */
341 mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
344 /* Align to 16 bytes */
347 /* Jump to subtraction loop */
350 /* Align to 16 bytes */
353 /* Subtract one count */
363 .global _KeQueryPerformanceCounter@4
364 .func KeQueryPerformanceCounter@4
365 _KeQueryPerformanceCounter@4:
367 /* Check if we were called too early */
368 cmp dword ptr _HalpCurrentRollOver, 0
377 /* Disable interrupts */
383 /* Get the current value */
384 mov ebx, _HalpPerfCounterLow
385 mov esi, _HalpPerfCounterHigh
387 /* Read 8254 timer */
397 /* Enable interrupts and do a short wait */
402 /* Disable them again */
406 /* Get the counter value again */
407 mov eax, _HalpPerfCounterLow
408 mov edx, _HalpPerfCounterHigh
410 /* Check if someone updated the counter */
416 /* Check if the current 8254 value causes rollover */
418 add ecx, _HalpCurrentRollOver
423 /* Calculate the sum */
427 /* Check if we're above or below the last high value */
428 cmp edx, _HalpLastPerfCounterHigh
432 /* Check if we're above or below the last low value */
433 cmp eax, _HalpLastPerfCounterLow
438 /* Update the last value and bring back interrupts */
439 mov _HalpLastPerfCounterLow, eax
440 mov _HalpLastPerfCounterHigh, edx
443 /* Check if caller wants frequency */
444 cmp dword ptr [esp+12], 0
447 /* Save hard-coded frequency */
448 mov ecx, dword ptr [esp+12]
449 mov dword ptr [ecx], 1193182
450 mov dword ptr [ecx+4], 0
454 /* Restore volatiles */
461 /* Return empty, called too soon */
468 /* We might have an incoming interrupt, save EFLAGS and reset rollover */
470 mov ecx, _HalpCurrentRollOver
473 /* Check if interrupts were enabled and try again */
474 test esi, EFLAGS_INTERRUPT_MASK
477 /* They're not, continue where we left */
483 /* Get the last counter values */
484 mov ebx, _HalpLastPerfCounterLow
485 mov esi, _HalpLastPerfCounterHigh
487 /* Check if the previous value was 0 and go back if yes */
492 /* Make sure that the count is still valid */
496 cmp ebx, _HalpCurrentRollOver
499 /* Fixup the count with the last known value */
503 /* We might have an incoming interrupt, save EFLAGS */
507 /* Check if interrupts were enabled and try again */
508 test ecx, EFLAGS_INTERRUPT_MASK
511 /* They're not, continue where we left */
518 mov _HalpLastPerfCounterLow, eax
519 mov _HalpLastPerfCounterHigh, eax