Author: ion Date: Wed Nov 29 11:01:58 2006 New Revision: 24963
URL: http://svn.reactos.org/svn/reactos?rev=24963&view=rev Log: - Implement a working version of KeQueryPerformanceCounter based on the C implementation (without the strange MHZed-based code) and also support updating the performance timer during a clock interrupt, otherwise the value might become stale during the query. - Update clock interrupt handler to update the performance counter, and also detect if someone changed the clock rate (but don't yet support this). - Test app from previous revision now works beautifully.
Modified: trunk/reactos/hal/halx86/generic/systimer.S trunk/reactos/hal/halx86/generic/timer.c
Modified: trunk/reactos/hal/halx86/generic/systimer.S URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/systimer... ============================================================================== --- trunk/reactos/hal/halx86/generic/systimer.S (original) +++ trunk/reactos/hal/halx86/generic/systimer.S Wed Nov 29 11:01:58 2006 @@ -10,7 +10,13 @@ #include <asm.h> #include <internal/i386/asmmacro.S> .intel_syntax noprefix -.extern _HalpCurrentTimeIncrement + +/* GLOBALS *******************************************************************/ + +_HalpLastPerfCounterLow: .long 0 +_HalpLastPerfCounterHigh: .long 0 +_HalpPerfCounterLow: .long 0 +_HalpPerfCounterHigh: .long 0
/* FUNCTIONS *****************************************************************/
@@ -43,6 +49,152 @@ 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 + jne LoopPostInt + cmp edx, esi + jne 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 + + /* Fixup the count with the last known value */ + sub eax, ebx + sbb edx, esi + + /* We might have an incoming interrupt, save EFLAGS */ + mov esi, [esp] + 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 BelowLow .endfunc
.globl _HalpClockInterrupt@0 @@ -66,10 +218,19 @@ or al, al jz Spurious
- /* Do a tick */ + /* 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 - xor ebx, ebx - jmp _KeUpdateSystemTime@0 + cmp _HalpClockSetMSRate, ebx + jz _KeUpdateSystemTime@0 + + /* FIXME: Someone did! */ + int 3
Spurious:
Modified: trunk/reactos/hal/halx86/generic/timer.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/timer.c?... ============================================================================== --- trunk/reactos/hal/halx86/generic/timer.c (original) +++ trunk/reactos/hal/halx86/generic/timer.c Wed Nov 29 11:01:58 2006 @@ -294,56 +294,4 @@ #endif }
-LARGE_INTEGER -STDCALL -KeQueryPerformanceCounter(PLARGE_INTEGER PerformanceFreq) -/* - * FUNCTION: Queries the finest grained running count available in the system - * ARGUMENTS: - * PerformanceFreq (OUT) = The routine stores the number of - * performance counter ticks per second here - * RETURNS: The number of performance counter ticks since boot - */ -{ - PKIPCR Pcr; - LARGE_INTEGER Value; - - _disable(); - - Pcr = (PKIPCR)KeGetPcr(); - - if (Pcr->PrcbData.FeatureBits & KF_RDTSC) - { - _enable(); - if (NULL != PerformanceFreq) - { - PerformanceFreq->QuadPart = Pcr->PrcbData.MHz * (ULONGLONG)1000000; - } - Value.QuadPart = (LONGLONG)__rdtsc(); - } - else - { - LARGE_INTEGER TicksOld; - LARGE_INTEGER TicksNew; - ULONG CountsLeft; - - _enable(); - - if (NULL != PerformanceFreq) - { - PerformanceFreq->QuadPart = CLOCK_TICK_RATE; - } - - do - { - KeQueryTickCount(&TicksOld); - CountsLeft = Read8254Timer(); - Value.QuadPart = TicksOld.QuadPart * LATCH + (LATCH - CountsLeft); - KeQueryTickCount(&TicksNew); - } - while (TicksOld.QuadPart != TicksNew.QuadPart); - } - return Value; -} - /* EOF */