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/systime…
==============================================================================
--- 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 */