windows-nt/Source/XPSP1/NT/base/hals/halmps/i386/mpclksup.asm
2020-09-26 16:20:57 +08:00

332 lines
7.7 KiB
NASM

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