mirror of
https://github.com/reactos/reactos.git
synced 2024-11-10 00:34:39 +00:00
c501d8112c
svn path=/branches/aicom-network-fixes/; revision=34994
259 lines
5.3 KiB
ArmAsm
259 lines
5.3 KiB
ArmAsm
/*
|
|
* FILE: hal/halx86/generic/timer.S
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PURPOSE: System Timer Interrupt and Management
|
|
* PROGRAMMER: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <asm.h>
|
|
#include <internal/i386/asmmacro.S>
|
|
.intel_syntax noprefix
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
_HalpLastPerfCounterLow: .long 0
|
|
_HalpLastPerfCounterHigh: .long 0
|
|
_HalpPerfCounterLow: .long 0
|
|
_HalpPerfCounterHigh: .long 0
|
|
|
|
_UnhandledMsg:
|
|
.asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
.globl _KeStallExecutionProcessor@4
|
|
.func 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
|
|
|
|
/* Align to 16 bytes */
|
|
.align 16
|
|
|
|
/* 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
|
|
.endfunc
|
|
|
|
.global _KeQueryPerformanceCounter@4
|
|
.func KeQueryPerformanceCounter@4
|
|
_KeQueryPerformanceCounter@4:
|
|
|
|
/* Check if we were called too early */
|
|
cmp dword ptr _HalpCurrentRollOver, 0
|
|
je NoCount
|
|
|
|
/* Save volatiles */
|
|
push ebx
|
|
push esi
|
|
|
|
LoopPreInt:
|
|
|
|
/* Disable interrupts */
|
|
pushf
|
|
cli
|
|
|
|
LoopPostInt:
|
|
|
|
/* Get the current value */
|
|
mov ebx, _HalpPerfCounterLow
|
|
mov esi, _HalpPerfCounterHigh
|
|
|
|
/* Read 8254 timer */
|
|
mov al, 0
|
|
out 0x43, al
|
|
jmp $+2
|
|
in al, 0x40
|
|
jmp $+2
|
|
movzx ecx, al
|
|
in al, 0x40
|
|
mov ch, al
|
|
|
|
/* Enable interrupts and do a short wait */
|
|
popf
|
|
nop
|
|
jmp $+2
|
|
|
|
/* Disable them again */
|
|
pushf
|
|
cli
|
|
|
|
/* Get the counter value again */
|
|
mov eax, _HalpPerfCounterLow
|
|
mov edx, _HalpPerfCounterHigh
|
|
|
|
/* Check if someone updated the counter */
|
|
cmp eax, ebx
|
|
jnz LoopPostInt
|
|
cmp edx, esi
|
|
jnz LoopPostInt
|
|
|
|
/* Check if the current 8254 value causes rollover */
|
|
neg ecx
|
|
add ecx, _HalpCurrentRollOver
|
|
jnb DoRollOver
|
|
|
|
SetSum:
|
|
|
|
/* Calculate the sum */
|
|
add eax, ecx
|
|
adc edx, 0
|
|
|
|
/* Check if we're above or below the last high value */
|
|
cmp edx, _HalpLastPerfCounterHigh
|
|
jb short BelowHigh
|
|
jnz short BelowLow
|
|
|
|
/* Check if we're above or below the last low value */
|
|
cmp eax, _HalpLastPerfCounterLow
|
|
jb BelowHigh
|
|
|
|
BelowLow:
|
|
|
|
/* Update the last value and bring back interrupts */
|
|
mov _HalpLastPerfCounterLow, eax
|
|
mov _HalpLastPerfCounterHigh, edx
|
|
popf
|
|
|
|
/* Check if caller wants frequency */
|
|
cmp dword ptr [esp+12], 0
|
|
jz ReturnNoFreq
|
|
|
|
/* Save hard-coded frequency */
|
|
mov ecx, dword ptr [esp+12]
|
|
mov dword ptr [ecx], 1193182
|
|
mov dword ptr [ecx+4], 0
|
|
|
|
ReturnNoFreq:
|
|
|
|
/* Restore volatiles */
|
|
pop esi
|
|
pop ebx
|
|
ret 4
|
|
|
|
NoCount:
|
|
|
|
/* Return empty, called too soon */
|
|
mov eax, 0
|
|
mov edx, 0
|
|
ret 4
|
|
|
|
DoRollOver:
|
|
|
|
/* We might have an incoming interrupt, save EFLAGS and reset rollover */
|
|
mov esi, [esp]
|
|
mov ecx, _HalpCurrentRollOver
|
|
popf
|
|
|
|
/* Check if interrupts were enabled and try again */
|
|
test esi, EFLAGS_INTERRUPT_MASK
|
|
jnz LoopPreInt
|
|
|
|
/* They're not, continue where we left */
|
|
pushf
|
|
jmp SetSum
|
|
|
|
BelowHigh:
|
|
|
|
/* Get the last counter values */
|
|
mov ebx, _HalpLastPerfCounterLow
|
|
mov esi, _HalpLastPerfCounterHigh
|
|
|
|
/* Check if the previous value was 0 and go back if yes */
|
|
mov ecx, ebx
|
|
or ecx, esi
|
|
jz BelowLow
|
|
|
|
/* Make sure that the count is still valid */
|
|
sub ebx, eax
|
|
sbb esi, edx
|
|
jnz InvalidCount
|
|
cmp ebx, _HalpCurrentRollOver
|
|
jg InvalidCount
|
|
|
|
/* Fixup the count with the last known value */
|
|
sub eax, ebx
|
|
sbb edx, esi
|
|
|
|
/* We might have an incoming interrupt, save EFLAGS */
|
|
mov ecx, [esp]
|
|
popf
|
|
|
|
/* Check if interrupts were enabled and try again */
|
|
test ecx, EFLAGS_INTERRUPT_MASK
|
|
jnz LoopPreInt
|
|
|
|
/* They're not, continue where we left */
|
|
pushf
|
|
jmp BelowLow
|
|
|
|
InvalidCount:
|
|
popf
|
|
xor eax, eax
|
|
mov _HalpLastPerfCounterLow, eax
|
|
mov _HalpLastPerfCounterHigh, eax
|
|
jmp LoopPreInt
|
|
.endfunc
|
|
|
|
.globl _HalpClockInterrupt@0
|
|
.func HalpClockInterrupt@0
|
|
TRAP_FIXUPS hci_a, hci_t, DoFixupV86, DoFixupAbios
|
|
_HalpClockInterrupt@0:
|
|
|
|
/* Enter trap */
|
|
INT_PROLOG hci_a, hci_t, DoPushFakeErrorCode
|
|
|
|
/* Push vector and make stack for IRQL */
|
|
push 0x30
|
|
sub esp, 4
|
|
|
|
/* Begin the interrupt */
|
|
push esp
|
|
push 0x30
|
|
push CLOCK2_LEVEL
|
|
call _HalBeginSystemInterrupt@12
|
|
|
|
/* Check if it's spurious */
|
|
or al, al
|
|
jz Spurious
|
|
|
|
/* Update the performance counter */
|
|
xor ebx, ebx
|
|
mov eax, _HalpCurrentRollOver
|
|
add _HalpPerfCounterLow, eax
|
|
adc _HalpPerfCounterHigh, ebx
|
|
|
|
/* Get the time increment and check if someone changed the clock rate */
|
|
mov eax, _HalpCurrentTimeIncrement
|
|
cmp _HalpClockSetMSRate, ebx
|
|
jz _KeUpdateSystemTime@0
|
|
|
|
/* FIXME: Someone did! */
|
|
int 3
|
|
|
|
Spurious:
|
|
|
|
/* Exit the interrupt */
|
|
add esp, 8
|
|
jmp _Kei386EoiHelper@0
|
|
.endfunc
|
|
|