title "Query Performace Counter" ;++ ; ; Copyright (c) 1989 Microsoft Corporation ; ; Module Name: ; ; mpclksup.asm ; ; Abstract: ; ; This module implements the code necessary to do ; QueryPerformaceCounter the MPS way. ; ; Author: ; ; Shie-Lin Tzong (shielint) 12-Jan-1990 ; ; Environment: ; ; Kernel mode only. ; ; Revision History: ; ; bryanwi 20-Sep-90 ; jakeo 12-16-97 -- moved code from mpprofil.asm ; ;-- .586p .xlist include hal386.inc include callconv.inc ; calling convention macros include i386\kimacro.inc include mac386.inc include apic.inc include ntapic.inc include i386\mp8254.inc .list EXTRNP _HalpAcquireSystemHardwareSpinLock,0 EXTRNP _HalpReleaseSystemHardwareSpinLock,0 extrn _HalpUse8254:BYTE _DATA SEGMENT DWORD PUBLIC 'DATA' ALIGN dword ; ; counters for the performance counter ; public _HalpPerfCounterLow, _HalpPerfCounterHigh public _HalpLastPerfCounterLow, _HalpLastPerfCounterHigh _HalpPerfCounterLow dd 0 _HalpPerfCounterHigh dd 0 _HalpLastPerfCounterLow dd 0 _HalpLastPerfCounterHigh dd 0 _DATA ends _TEXT SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING page ,132 subttl "Query Performance Counter" ;++ ; ; LARGE_INTEGER ; KeQueryPerformanceCounter ( ; OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL ; ) ; ; Routine Description: ; ; This routine returns current 64-bit performance counter and, ; optionally, the Performance Frequency. ; ; Note this routine can NOT be called at Profiling interrupt ; service routine. Because this routine depends on IRR0 to determine ; the actual count. ; ; Also note that the performace counter returned by this routine ; is not necessary the value when this routine is just entered. ; The value returned is actually the counter value at any point ; between the routine is entered and is exited. ; ; Arguments: ; ; PerformanceFrequency [TOS+4] - optionally, supplies the address ; of a variable to receive the performance counter frequency. ; ; Return Value: ; ; Current value of the performance counter will be returned. ; ;-- ; ; Parameter definitions ; KqpcFrequency EQU [esp+4] ; User supplied Performance Frequence ifdef MMTIMER cPublicProc _HalpAcpiTimerQueryPerfCount ,1 else cPublicProc _KeQueryPerformanceCounter ,1 endif mov al, _HalpUse8254 or al, al jnz short KqpcUse8254 KqpcUseTSC: ; use time stamp counter as performance counter mov ecx, KqpcFrequency or ecx, ecx jz short kpc10 mov eax, PCR[PcHal.TSCHz] mov dword ptr [ecx], eax mov dword ptr [ecx+4], 0 kpc10: rdtsc add eax, PCR[PcHal.PerfCounterLow] adc edx, PCR[PcHal.PerfCounterHigh] ifdef MMTIMER stdRET _HalpAcpiTimerQueryPerfCount else stdRET _KeQueryPerformanceCounter endif KqpcUse8254: ; use 8254 as time base for performance counters mov ecx, KqpcFrequency or ecx, ecx jz short Kqpc10 mov dword ptr [ecx], PERFORMANCE_FREQUENCY mov dword ptr [ecx+4], 0 xor ecx, ecx Kqpc10: test al, PERF_8254_INITIALIZED jz KqpcNoInit stdCall _HalpAcquireSystemHardwareSpinLock ; intr disabled ; Read current offset from 8254 counter 0 ; Counter Latch PIT Ctr 0 command mov al, COMMAND_8254_LATCH_READ+COMMAND_8254_COUNTER0 out TIMER1_CONTROL_PORT0, al IODelay in al, TIMER1_DATA_PORT0 ; Read 8254 Ctr 0, LSByte. IODelay movzx edx,al ; Zero upper bytes of (EDX). in al, TIMER1_DATA_PORT0 ; Read 8254 Ctr 0, MSByte. mov dh, al ; (DX) = 8254 Ctr 0 count. neg edx ; PIT counts down, calculate interval add edx, PERFORMANCE_INTERVAL ; (edx) = offset value from most recent base value in ; _HalpPerfCounterHigh:_HalpPerfCounterLow mov eax, _HalpPerfCounterLow add eax, edx mov edx, _HalpPerfCounterHigh adc edx, ecx ; (edx:eax) = 64 bit counter value ; ; Check to see if the new value is sane - should be greater than ; the last counter value returned by KeQueryPerformanceCounter. ; Can happen only due to wrap around of the 8254. Correct by ; updating the performance counter base. cmp edx, _HalpLastPerfCounterHigh jg short KqpcContinue ; Current value > last returned value jl short KqpcCatchupPerfCounter ; Current value < last returned value ; high dwords equal, compare low dword cmp eax, _HalpLastPerfCounterLow jg short KqpcContinue ; Current value > last returned value KqpcCatchupPerfCounter: ; Current counter value is not greater than the previously returned ; counter value - can happen only due to the 8254 timer wraparound. ; Update base to account for wrap around. add eax, PERFORMANCE_INTERVAL adc edx, ecx add _HalpPerfCounterLow, PERFORMANCE_INTERVAL adc _HalpPerfCounterHigh, ecx KqpcContinue: mov _HalpLastPerfCounterLow, eax mov _HalpLastPerfCounterHigh, edx stdCall _HalpReleaseSystemHardwareSpinLock ifdef MMTIMER stdRET _HalpAcpiTimerQueryPerfCount else stdRET _KeQueryPerformanceCounter endif KqpcNoInit: ; 8254 is not yet initialized. Just return 0 for now xor eax, eax xor edx, edx ifdef MMTIMER stdRET _HalpAcpiTimerQueryPerfCount stdENDP _HalpAcpiTimerQueryPerfCount else stdRET _KeQueryPerformanceCounter stdENDP _KeQueryPerformanceCounter endif page ,132 subttl "Stall Execution" ;++ ; ; VOID ; KeStallExecutionProcessor ( ; IN ULONG MicroSeconds ; ) ; ; Routine Description: ; ; This function stalls execution for the specified number of microseconds. ; KeStallExecutionProcessor ; ; Arguments: ; ; MicroSeconds - Supplies the number of microseconds that execution is to be ; stalled. ; ; Return Value: ; ; None. ; ;-- MicroSeconds equ [esp + 12] ifdef MMTIMER cPublicProc _HalpAcpiTimerStallExecProc ,1 else cPublicProc _KeStallExecutionProcessor ,1 endif cPublicFpo 1,2 push ebx push edi ; ; Issue a CPUID to implement a "fence" ; xor eax, eax fence1: cpuid ; ; Get current TSC ; rdtsc mov ebx, eax mov edi, edx ; ; Determine ending TSC ; mov ecx, MicroSeconds ; (ecx) = Microseconds mov eax, PCR[PcStallScaleFactor] ; get per microsecond mul ecx add ebx, eax adc edi, edx ; ; Wait for ending TSC ; kese10: rdtsc cmp edi, edx ja short kese10 jc short kese20 cmp ebx, eax ja short kese10 kese20: pop edi pop ebx ifdef MMTIMER stdRET _HalpAcpiTimerStallExecProc stdENDP _HalpAcpiTimerStallExecProc else stdRET _KeStallExecutionProcessor stdENDP _KeStallExecutionProcessor endif _TEXT ends INIT SEGMENT DWORD PUBLIC 'CODE' ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING cPublicProc _HalpRemoveFences mov word ptr fence1, 0c98bh stdRET _HalpRemoveFences stdENDP _HalpRemoveFences INIT ends end