reactos/hal/halx86/generic/systimer.S

378 lines
7.7 KiB
ArmAsm

/*
* FILE: hal/halx86/generic/systimer.S
* COPYRIGHT: See COPYING in the top level directory
* PURPOSE: System Timer Interrupt and Management
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ******************************************************************/
#include <asm.inc>
#include <ks386.inc>
EXTERN _HalpAcquireCmosSpinLock@0:PROC
EXTERN _HalpReleaseCmosSpinLock@0:PROC
EXTERN _DbgBreakPoint@0:PROC
#define PIC1_BASE HEX(20) /* IO base address for master PIC */
#define PIC2_BASE HEX(A0) /* IO base address for slave PIC */
#define PIC1_COMMAND PIC1_BASE
#define PIC1_DATA (PIC1_BASE+1)
#define PIC2_COMMAND PIC2_BASE
#define PIC2_DATA (PIC2_BASE+1)
#define PIC_EOI HEX(20)
#define PIC_SPECIFIC_EOI2 HEX(62)
#define CMOS_ADDR HEX(70)
#define CMOS_DATA HEX(71)
#define CMOS_REGISTER_A HEX(0A)
#define CMOS_REGISTER_B HEX(0B)
#define CMOS_REGISTER_C HEX(0C)
#define CMOS_REGISTER_D HEX(0D)
#define PIT_CH0 HEX(40)
#define PIT_MODE HEX(43)
#define SYSTEM_CTRL_PORT_A HEX(92)
/* GLOBALS *******************************************************************/
.data
ASSUME CS:NOTHING, DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING
/* FUNCTIONS *****************************************************************/
.code
PUBLIC _HalpCalibrateStallExecution@0
_HalpCalibrateStallExecution@0:
/* Setup the stack frame */
push ebp
mov ebp, esp
sub esp, 12
/* Save EFLAGS and kill interrupts */
pushfd
cli
/* Get the current interrupt mask on the PICs */
xor eax, eax
in al, PIC2_DATA
shl eax, 8
in al, PIC1_DATA
/* Save it */
push eax
/* Now mask everything except the RTC and PIC 2 chain-interrupt */
mov eax, NOT (HEX(04) OR HEX(100))
/* Program the PICs */
out PIC1_DATA, al
shr eax, 8
out PIC2_DATA, al
/* Now get the IDT */
sidt [ebp-8]
mov ecx, [ebp-6]
/* Get the IDT entry for the RTC */
mov eax, HEX(38)
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], HEX(08E00)
shr eax, 16
mov [ecx+6], ax
/* Reset our counter */
mov dword ptr [ebp-12], 0
/* Acquire CMOS lock */
call _HalpAcquireCmosSpinLock@0
/* Now initialize register A on the CMOS */
mov ax, HEX(2D00) OR CMOS_REGISTER_A
out CMOS_ADDR, al
jmp $+2
mov al, ah
out CMOS_DATA, al
jmp $+2
/* Read register B */
mov ax, CMOS_REGISTER_B
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Don't touch the LastKnownGoodConfig hack */
and al, 1
mov ah, al
/* Enable the interrupt */
or ah, HEX(42)
/* Now write the register B */
mov al, CMOS_REGISTER_B
out CMOS_ADDR, al
jmp $+2
mov al, ah
out CMOS_DATA, al
jmp $+2
/* Read register C */
mov al, CMOS_REGISTER_C
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Read register D */
mov al, CMOS_REGISTER_D
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
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 _HalpAcquireCmosSpinLock@0
/* Now initialize register A on the CMOS */
mov ax, HEX(2D00) OR CMOS_REGISTER_A
out CMOS_ADDR, al
jmp $+2
mov al, ah
out CMOS_DATA, al
jmp $+2
/* Read register B */
mov ax, CMOS_REGISTER_B
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Don't touch the LastKnownGoodConfig hack */
and al, 1
mov ah, al
/* Enable the interrupt */
or ah, HEX(42)
/* Now write the register B */
mov al, CMOS_REGISTER_B
out CMOS_ADDR, al
jmp $+2
mov al, ah
out CMOS_DATA, al
jmp $+2
/* Read register C */
mov al, CMOS_REGISTER_C
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Read register D */
mov al, CMOS_REGISTER_D
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Release CMOS lock */
call _HalpReleaseCmosSpinLock@0
/* Dismiss the interrupt */
mov al, PIC_EOI
out PIC2_COMMAND, al
mov al, PIC_SPECIFIC_EOI2
out PIC1_COMMAND, 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, HEX(13)
/* Acquire CMOS lock */
call _HalpAcquireCmosSpinLock@0
/* Now initialize register A on the CMOS */
mov ax, HEX(2D00) OR CMOS_REGISTER_A
out CMOS_ADDR, al
jmp $+2
mov al, ah
out CMOS_DATA, al
jmp $+2
/* Read register B */
mov ax, CMOS_REGISTER_B
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Don't touch the LastKnownGoodConfig hack */
and al, 1
mov ah, al
/* Disable the interrupt */
or ah, 2
/* Now write the register B */
mov al, CMOS_REGISTER_B
out CMOS_ADDR, al
jmp $+2
mov al, ah
out CMOS_DATA, al
jmp $+2
/* Read register C */
mov al, CMOS_REGISTER_C
out CMOS_ADDR, al
jmp $+2
in al, CMOS_DATA
jmp $+2
/* Release CMOS lock */
call _HalpReleaseCmosSpinLock@0
/* Dismiss the interrupt */
mov al, PIC_EOI
out PIC2_COMMAND, al
mov al, PIC_SPECIFIC_EOI2
out PIC1_COMMAND, al
/* Disable interrupts on return */
and word ptr [esp+8], NOT 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 PIC1_DATA, al
shr eax, 8
out PIC2_DATA, al
/* Restore EFLAGS */
popfd
/* Restore stack and return */
mov esp, ebp
pop ebp
ret
#ifndef _MINIHAL_
PUBLIC _KeStallExecutionProcessor@4
_KeStallExecutionProcessor@4:
/* Get the number of microseconds required */
mov ecx, [esp+4]
jecxz Done
/* Multiply by the stall factor */
mov eax, fs:[KPCR_STALL_SCALE_FACTOR]
mul ecx
/* Jump to subtraction loop */
jmp SubtractLoop
/* Align to 16 bytes */
.align 16
/* Subtract one count */
SubtractLoop:
sub eax, 1
jnz SubtractLoop
Done:
/* Return */
ret 4
#endif
END