+.global _HalpReleaseCmosSpinLock@0
+.func HalpReleaseCmosSpinLock@0
+_HalpReleaseCmosSpinLock@0:
+
+#ifdef CONFIG_SMP
+ /* Save clobbered register */
+ push eax
+
+ /* Push saved EFLAGS */
+ push _HalpSystemHardwareFlags
+
+ /* Release the lock */
+ lea eax, _HalpSystemHardwareLock
+ RELEASE_SPINLOCK(eax)
+
+ /* Restore EFLAGS */
+ popf
+
+ /* Return */
+ pop eax
+ ret
+#else
+ /* Restore EFLAGS and return */
+ push _HalpSystemHardwareFlags
+ popf
+ ret
+#endif
+.endfunc
+
+.global _HalpAcquireSystemHardwareSpinLock@0
+.func HalpAcquireSystemHardwareSpinLock@0
+_HalpAcquireSystemHardwareSpinLock@0:
+
+#ifdef CONFIG_SMP
+ /* Save clobbered register */
+ push eax
+
+HardwareLock:
+ /* Save EFLAGS and disable interrupts */
+ pushf
+ cli
+
+ /* This is the CMOS lock, acquire it */
+ lea eax, _HalpSystemHardwareLock
+ ACQUIRE_SPINLOCK(eax, CmosSpin)
+
+ /* We have it, return the flags */
+ pop _HalpSystemHardwareFlags
+ pop eax
+ ret
+
+CmosSpin:
+
+ /* Restore EFLAGS */
+ pushf _HalpSystemHardwareLock
+ popf
+
+ /* Spin */
+ SPIN_ON_LOCK(eax, HardwareLock)
+
+#else
+ /* Save EFLAGS, disable interrupts and return */
+ pushf
+ cli
+ pop _HalpSystemHardwareFlags
+ ret
+#endif
+.endfunc
+
+.global _HalpCalibrateStallExecution@0
+.func HalpCalibrateStallExecution@0
+_HalpCalibrateStallExecution@0:
+
+ /* Setup the stack frame */
+ push ebp
+ mov ebp, esp
+ sub esp, 12
+
+ /* Save EFLAGS and kill interrupts */
+ pushf
+ cli
+
+ /* Get the current interrupt mask on the PICs */
+ xor eax, eax
+ in al, 0xA1
+ shl eax, 8
+ in al, 0x21
+
+ /* Save it */
+ push eax
+
+ /* Now mask everything except the RTC and PIC 2 chain-interrupt */
+ mov eax, ~((1 << 2) | (1 << 8))
+
+ /* Program the PICs */
+ out 0x21, al
+ shr eax, 8
+ out 0xA1, al
+
+ /* Now get the IDT */
+ sidt [ebp-8]
+ mov ecx, [ebp-6]
+
+ /* Get the IDT entry for the RTC */
+ mov eax, 0x38
+ shl eax, 3
+ add ecx, eax
+
+ /* Save the original RTC ISR */
+ push [ecx]
+ push [ecx+4]
+ push ecx
+
+ /* Now load our new handler */
+ mov eax, offset OnlyOnePersonCanWriteHalCode
+ mov [ecx], ax
+ mov word ptr [ecx+2], KGDT_R0_CODE
+ mov word ptr [ecx+4], 0x8E00
+ shr eax, 16
+ mov [ecx+6], ax
+
+ /* Reset our counter */
+ mov dword ptr [ebp-12], 0
+
+ /* Acquire CMOS lock */
+ call _HalpAcquireSystemHardwareSpinLock@0
+
+ /* Now initialize register A on the CMOS */
+ mov ax, (0x2D << 8) | 0xA
+ out 0x70, al
+ jmp $+2
+ mov al, ah
+ out 0x71, al
+ jmp $+2
+
+ /* Read register B */
+ mov ax, 0xB
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Don't touch the LastKnownGoodConfig hack */
+ and al, 1
+ mov ah, al
+
+ /* Enable the interrupt */
+ or ah, 0x42
+
+ /* Now write the register B */
+ mov al, 0xB
+ out 0x70, al
+ jmp $+2
+ mov al, ah
+ out 0x71, al
+ jmp $+2
+
+ /* Read register C */
+ mov al, 0xC
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Read register D */
+ mov al, 0xD
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Release CMOS lock */
+ mov dword ptr [ebp-12], 0
+ call _HalpReleaseCmosSpinLock@0
+
+ /* Initialize looper */
+ xor eax, eax
+
+ /* Align to 16 bytes */
+ .align 16
+
+ /* Enable interrupts! */
+ sti
+ jmp Looper
+
+ /* Align to 16 bytes */
+ .align 16
+
+ /* Subtract one count */
+Looper:
+ sub eax, 1
+ jnz Looper
+
+ /* ASSERT: If we got here, then the RTC never fired */
+ call _DbgBreakPoint@0
+ jmp Looper
+
+OnlyOnePersonCanWriteHalCode:
+ /*********************** THIS IS THE RTC HANDLER **************************/
+
+ /* Increment the interrupt count and check if this is the first one */
+ inc dword ptr [ebp-12]
+ cmp dword ptr [ebp-12], 1
+ jnz ComputeStall
+
+ /*
+ * It is the first one -- we'll ignore it, since it fires randomly!
+ * Get rid of the old return address and push the new one in (our looper)
+ */
+ pop eax
+ push offset Looper
+
+ /* Acquire CMOS lock */
+ call _HalpAcquireSystemHardwareSpinLock@0
+
+ /* Now initialize register A on the CMOS */
+ mov ax, (0x2D << 8) | 0xA
+ out 0x70, al
+ jmp $+2
+ mov al, ah
+ out 0x71, al
+ jmp $+2
+
+ /* Read register B */
+ mov ax, 0xB
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Don't touch the LastKnownGoodConfig hack */
+ and al, 1
+ mov ah, al
+
+ /* Enable the interrupt */
+ or ah, 0x42
+
+ /* Now write the register B */
+ mov al, 0xB
+ out 0x70, al
+ jmp $+2
+ mov al, ah
+ out 0x71, al
+ jmp $+2
+
+ /* Read register C */
+ mov al, 0xC
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Read register D */
+ mov al, 0xD
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Release CMOS lock */
+ call _HalpReleaseCmosSpinLock@0
+
+ /* Dismiss the interrupt */
+ mov al, 0x20
+ out 0xA0, al
+ mov al, 0x62
+ out 0x20, al
+
+ /* Reset the counter and return back to the looper */
+ xor eax, eax
+ iretd
+
+ /******************* THIS IS THE 2ND RTC HANDLER **************************/
+ComputeStall:
+
+ /* Do the calculation */
+ neg eax
+ xor edx, edx
+ mov ecx, 125000 /* RTC fires every 125 ms */
+ div ecx
+
+ /* Is the remainder 0? */
+ cmp edx, 0
+ jz FoundFactor
+
+ /* Otherwise fix-up the loop count */
+ inc eax
+
+FoundFactor:
+ /* Save the stall scale factor */
+ mov fs:[KPCR_STALL_SCALE_FACTOR], eax
+
+ /* Prepare for interrupt return */
+ pop eax
+ push offset AndItsNotYou
+ mov eax, 0x13
+
+ /* Acquire CMOS lock */
+ call _HalpAcquireSystemHardwareSpinLock@0
+
+ /* Now initialize register A on the CMOS */
+ mov ax, (0x2D << 8) | 0xA
+ out 0x70, al
+ jmp $+2
+ mov al, ah
+ out 0x71, al
+ jmp $+2
+
+ /* Read register B */
+ mov ax, 0xB
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Don't touch the LastKnownGoodConfig hack */
+ and al, 1
+ mov ah, al
+
+ /* Disable the interrupt */
+ or ah, 0x2
+
+ /* Now write the register B */
+ mov al, 0xB
+ out 0x70, al
+ jmp $+2
+ mov al, ah
+ out 0x71, al
+ jmp $+2
+
+ /* Read register C */
+ mov al, 0xC
+ out 0x70, al
+ jmp $+2
+ in al, 0x71
+ jmp $+2
+
+ /* Release CMOS lock */
+ call _HalpReleaseCmosSpinLock@0
+
+ /* Dismiss the interrupt */
+ mov al, 0x20
+ out 0xA0, al
+ mov al, 0x62
+ out 0x20, al
+
+ /* Disable interrupts on return */
+ and word ptr [esp+8], ~EFLAGS_INTERRUPT_MASK
+ iretd
+
+ /************************* WE ARE BACK FROM RTC ***************************/
+AndItsNotYou:
+
+ /* Restore the IDT */
+ pop ecx
+ pop [ecx+4]
+ pop [ecx]
+
+ /* Restore the mask */
+ pop eax
+ out 0x21, al
+ shr eax, 8
+ out 0xA1, al
+
+ /* Restore EFLAGS */
+ popf
+
+ /* Restore stack and return */
+ mov esp, ebp
+ pop ebp
+ ret
+.endfunc
+