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 */
333 .globl _KeStallExecutionProcessor@4
334 .func KeStallExecutionProcessor@4
335 _KeStallExecutionProcessor@4:
337 /* Get the number of microseconds required */
341 /* Multiply by the stall factor */
342 mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
345 /* Align to 16 bytes */
348 /* Jump to subtraction loop */
351 /* Align to 16 bytes */
354 /* Subtract one count */
365 .global _KeQueryPerformanceCounter@4
366 .func KeQueryPerformanceCounter@4
367 _KeQueryPerformanceCounter@4:
369 /* Check if we were called too early */
370 cmp dword ptr _HalpCurrentRollOver, 0
379 /* Disable interrupts */
385 /* Get the current value */
386 mov ebx, _HalpPerfCounterLow
387 mov esi, _HalpPerfCounterHigh
389 /* Read 8254 timer */
399 /* Enable interrupts and do a short wait */
404 /* Disable them again */
408 /* Get the counter value again */
409 mov eax, _HalpPerfCounterLow
410 mov edx, _HalpPerfCounterHigh
412 /* Check if someone updated the counter */
418 /* Check if the current 8254 value causes rollover */
420 add ecx, _HalpCurrentRollOver
425 /* Calculate the sum */
429 /* Check if we're above or below the last high value */
430 cmp edx, _HalpLastPerfCounterHigh
434 /* Check if we're above or below the last low value */
435 cmp eax, _HalpLastPerfCounterLow
440 /* Update the last value and bring back interrupts */
441 mov _HalpLastPerfCounterLow, eax
442 mov _HalpLastPerfCounterHigh, edx
445 /* Check if caller wants frequency */
446 cmp dword ptr [esp+12], 0
449 /* Save hard-coded frequency */
450 mov ecx, dword ptr [esp+12]
451 mov dword ptr [ecx], 1193182
452 mov dword ptr [ecx+4], 0
456 /* Restore volatiles */
463 /* Return empty, called too soon */
470 /* We might have an incoming interrupt, save EFLAGS and reset rollover */
472 mov ecx, _HalpCurrentRollOver
475 /* Check if interrupts were enabled and try again */
476 test esi, EFLAGS_INTERRUPT_MASK
479 /* They're not, continue where we left */
485 /* Get the last counter values */
486 mov ebx, _HalpLastPerfCounterLow
487 mov esi, _HalpLastPerfCounterHigh
489 /* Check if the previous value was 0 and go back if yes */
494 /* Make sure that the count is still valid */
498 cmp ebx, _HalpCurrentRollOver
501 /* Fixup the count with the last known value */
505 /* We might have an incoming interrupt, save EFLAGS */
509 /* Check if interrupts were enabled and try again */
510 test ecx, EFLAGS_INTERRUPT_MASK
513 /* They're not, continue where we left */
520 mov _HalpLastPerfCounterLow, eax
521 mov _HalpLastPerfCounterHigh, eax