mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +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 <internal/i386/asmmacro.S>
|
||||
.intel_syntax noprefix
|
||||
.extern _HalpCurrentTimeIncrement
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
_HalpLastPerfCounterLow: .long 0
|
||||
_HalpLastPerfCounterHigh: .long 0
|
||||
_HalpPerfCounterLow: .long 0
|
||||
_HalpPerfCounterHigh: .long 0
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
|
@ -45,6 +51,152 @@ Done:
|
|||
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
|
||||
.func HalpClockInterrupt@0
|
||||
_HalpClockInterrupt@0:
|
||||
|
@ -66,10 +218,19 @@ _HalpClockInterrupt@0:
|
|||
or al, al
|
||||
jz Spurious
|
||||
|
||||
/* Do a tick */
|
||||
mov eax, _HalpCurrentTimeIncrement
|
||||
/* Update the performance counter */
|
||||
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:
|
||||
|
||||
|
|
|
@ -294,56 +294,4 @@ VOID HalpCalibrateStallExecution(VOID)
|
|||
#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 */
|
||||
|
|
Loading…
Reference in a new issue