mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +00:00
- 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. svn path=/trunk/; revision=24963
This commit is contained in:
parent
7cd2e3f498
commit
f09a042483
2 changed files with 165 additions and 56 deletions
|
@ -10,7 +10,13 @@
|
||||||
#include <asm.h>
|
#include <asm.h>
|
||||||
#include <internal/i386/asmmacro.S>
|
#include <internal/i386/asmmacro.S>
|
||||||
.intel_syntax noprefix
|
.intel_syntax noprefix
|
||||||
.extern _HalpCurrentTimeIncrement
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
_HalpLastPerfCounterLow: .long 0
|
||||||
|
_HalpLastPerfCounterHigh: .long 0
|
||||||
|
_HalpPerfCounterLow: .long 0
|
||||||
|
_HalpPerfCounterHigh: .long 0
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
@ -45,6 +51,152 @@ Done:
|
||||||
ret 4
|
ret 4
|
||||||
.endfunc
|
.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
|
.globl _HalpClockInterrupt@0
|
||||||
.func HalpClockInterrupt@0
|
.func HalpClockInterrupt@0
|
||||||
_HalpClockInterrupt@0:
|
_HalpClockInterrupt@0:
|
||||||
|
@ -66,10 +218,19 @@ _HalpClockInterrupt@0:
|
||||||
or al, al
|
or al, al
|
||||||
jz Spurious
|
jz Spurious
|
||||||
|
|
||||||
/* Do a tick */
|
/* Update the performance counter */
|
||||||
mov eax, _HalpCurrentTimeIncrement
|
|
||||||
xor ebx, ebx
|
xor ebx, ebx
|
||||||
jmp _KeUpdateSystemTime@0
|
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:
|
Spurious:
|
||||||
|
|
||||||
|
|
|
@ -294,56 +294,4 @@ VOID HalpCalibrateStallExecution(VOID)
|
||||||
#endif
|
#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 */
|
/* EOF */
|
||||||
|
|
Loading…
Reference in a new issue