Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

461 lines
10 KiB

title "ACPI Timer Functions"
;++
;
; Copyright (c) 1989 Microsoft Corporation
;
; Module Name:
;
; pmtimer.asm
;
; Abstract:
;
; This module implements the code for ACPI-related timer
; functions.
;
; Author:
;
; Jake Oshins (jakeo) March 28, 1997
;
; Environment:
;
; Kernel mode only.
;
; Revision History:
;
; Split from pmclock.asm due to PIIX4 bugs.
;
;--
.386p
.xlist
include hal386.inc
include callconv.inc ; calling convention macros
include mac386.inc
include i386\ix8259.inc
include i386\ixcmos.inc
include xxacpi.h
.list
extrn _HalpFixedAcpiDescTable:DWORD
extrn _HalpPiix4:byte
extrn _HalpNextMSRate:DWORD
extrn _PMTimerFreq:DWORD
if DBG
extrn _LastKQPCValue:DWORD
endif
;
; ==== Values used for ACPI Clock ====
;
_DATA SEGMENT DWORD PUBLIC 'DATA'
MSBMASK24 equ 00800000h
MSBMASK32 equ 80000000h
CurrentTimePort equ 0
TimeLow equ 4
TimeHigh2 equ 8
TimeHigh1 equ 12
MsbMask equ 16
BiasLow equ 20
BiasHigh equ 24
UpperBoundLow equ 28
UpperBoundHigh2 equ 32
UpperBoundHigh1 equ 36
public _TimerInfo
_TimerInfo dd 0,0,0,0,MSBMASK24,0,0,0,2,2
public _QueryTimer
_QueryTimer dd offset FLAT:@HalpQueryPerformanceCounter
if 0
;
; The UpperBoundTable contains the values which should be added
; to the current counter value to ensure that the upper bound is
; reasonable. Values listed here are for all the 15 possible
; timer tick lengths. The unit is "PM Timer Ticks" and the
; value corresponds to the number of ticks that will pass in
; roughly two timer ticks at this rate.
;
UpperBoundTable dd 14000 ; 1 ms
dd 28600 ; 2 ms
dd 43200 ; 3 ms
dd 57200 ; 4 ms
dd 71600 ; 5 ms
dd 86000 ; 6 ms
dd 100200 ; 7 ms
dd 114600 ; 8 ms
dd 128800 ; 9 ms
dd 143400 ; 10 ms
dd 157400 ; 11 ms
dd 171800 ; 12 ms
dd 186200 ; 13 ms
dd 200400 ; 14 ms
dd 214800 ; 15 ms
endif
if DBG
TicksPassed dd 0,0
public _TimerPerf, _TimerPerfIndex
_TimerPerf db 4096 dup(0)
RawRead0 equ 0
RawRead1 equ 4
AdjustedLow0 equ 8
AdjustedHigh0 equ 12
AdjustedLow1 equ 16
AdjustedHigh1 equ 20
TITL equ 24
TITH equ 28
UBL equ 32
UBH equ 36
ReturnedLow equ 40
ReturnedHigh equ 44
ReadCount equ 48
TickMin equ 52
TickCount equ 56
TickNewUB equ 60
TimerPerfBytes equ 64
_TimerPerfIndex dd 0
endif
_DATA ends
_TEXT$03 SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
page ,132
subttl "Query Performance Counter"
;++
;
; VOID
; HalCalibratePerformanceCounter (
; IN LONG volatile *Number,
; IN ULONGLONG NewCount
; )
;
; /*++
;
; Routine Description:
;
; This routine resets the performance counter value for the current
; processor to zero. The reset is done such that the resulting value
; is closely synchronized with other processors in the configuration.
;
; Arguments:
;
; Number - Supplies a pointer to count of the number of processors in
; the configuration.
;
; NewCount - Supplies the value to synchronize the counter too
;
; Return Value:
;
; None.
;--
cPublicProc _HalpPmTimerCalibratePerfCount, 3
cPublicFpo 3,1
push edi
mov edi, [esp+8] ; ponter to context
cmp byte ptr PCR[PcNumber], 0 ; only execute on one processor
jnz short hcp_50 ; if not boot processor, wait
mov eax, _QueryTimer ; move current counter into edx:eax
call eax
mov ecx, [esp+12] ; compute how far current count
sub ecx, eax ; is from target count
mov eax, [esp+16]
sbb eax, edx
mov _TimerInfo.BiasLow, ecx ; replace bias
mov _TimerInfo.BiasHigh, eax
hcp_50:
lock dec dword ptr [edi] ; count down
@@: YIELD
cmp dword ptr [edi], 0 ; wait for all processors to signal
jnz short @b
pop edi
stdRET _HalpPmTimerCalibratePerfCount
stdENDP _HalpPmTimerCalibratePerfCount
page ,132
subttl "Query Performance Counter"
;++
;
; LARGE_INTEGER
; FASTCALL
; HalpQueryPerformanceCounter(
; VOID
; )
;
; Routine Description:
;
; This function is a simplified form of HalpAcpiTimerQueryPerfCount
; meant to be used internally by the HAL.
;
cPublicFastCall HalpQueryPerformanceCounter,0
cPublicFpo 0, 2
push ebx
push esi
;
; Snap current times
;
kqpc10: YIELD
mov esi, _TimerInfo.TimeHigh2
mov ebx, _TimerInfo.TimeLow
cmp esi, _TimerInfo.TimeHigh1
jne short kqpc10 ; Loop until consistent copy read
mov edx, _TimerInfo.CurrentTimePort
in eax, dx
;
; See if h/w MSb matches s/w copy
;
mov ecx, _TimerInfo.MsbMask
mov edx, eax
xor edx, ebx
and edx, ecx ; Isolate MSb match or mismatch
;
; Strip high hardware bit
;
not ecx
and eax, ecx
not ecx
;
; merge low bits
;
dec ecx
not ecx
and ebx, ecx
or eax, ebx
;
; If there was a mismatch, add a tick
;
add eax, edx
adc esi, 0
mov edx, esi ; get the top-half of the return value
pop esi
pop ebx
fstRET HalpQueryPerformanceCounter
fstENDP HalpQueryPerformanceCounter
;++
;
; LARGE_INTEGER
; HalpPmTimerQueryPerfCount (
; OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
; )
;
; Routine Description:
;
; This routine returns current 64-bit performance counter and,
; optionally, the Performance Frequency.
;
; N.B. 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.
;
;--
KqpcFrequency EQU [esp+8] ; User supplied Performance Frequence
cPublicProc _HalpPmTimerQueryPerfCount, 1
.FPO (0, 1, 0, 1, 0, 0)
push esi
mov eax, _QueryTimer
call eax
if 0
;
; Check to see if the timer ever reports time moving backwards
;
@@:
mov esi, [_LastKQPCValue+8]
mov ecx, [_LastKQPCValue]
cmp esi, [_LastKQPCValue+4]
jne short @b
cmp edx, esi ; check for rollover
jl short @f
sub ecx, eax
sbb esi, edx
jng short @f
int 3
@@:
mov [_LastKQPCValue+4], edx
mov [_LastKQPCValue], eax
mov [_LastKQPCValue+8], edx
endif
;
; Apply bias to time
;
mov ecx, _TimerInfo.BiasLow
mov esi, _TimerInfo.BiasHigh
add eax, ecx
adc edx, esi
mov ecx, KqpcFrequency
or ecx, ecx
jnz short kqpc20
pop esi
stdRET _HalpPmTimerQueryPerfCount
kqpc20: mov esi, _PMTimerFreq
mov [ecx], esi ; Hertz of PM timer
mov [ecx+4], 0
pop esi
stdRET _HalpPmTimerQueryPerfCount
stdENDP _HalpPmTimerQueryPerfCount
;++
;
; VOID
; HalAcpiTimerCarry (
; VOID
; )
;
; Routine Description:
;
; This routine is called to service the PM timer carry interrupt
;
; N.B. This function is called at interrupt time and assumes the
; caller clears the interrupt
;
; Arguments:
;
; None
;
; Return Value:
;
; None
;
;--
cPublicProc _HalAcpiTimerCarry, 0
cPublicFpo 0, 1
push ebx
;
; Get current time from h/w
;
mov edx, _TimerInfo.CurrentTimePort
in eax, dx
mov ebx, eax
mov ecx, _TimerInfo.MsbMask
mov eax, _TimerInfo.TimeLow
mov edx, _TimerInfo.TimeHigh2
;
; Add one tick
;
add eax, ecx
adc edx, 0
;
; MSb of h/w should now match s/w. If not, add another tick
; to get them back in sync. (debugger might knock them
; out of sync)
;
xor ebx, eax
and ebx, ecx
add eax, ebx
adc edx, 0
;
; Store in reverse order of code which reads it
;
mov _TimerInfo.TimeHigh1, edx
mov _TimerInfo.TimeLow, eax
mov _TimerInfo.TimeHigh2, edx
pop ebx
stdRET _HalAcpiTimerCarry
stdENDP _HalAcpiTimerCarry
;++
;
; VOID
; HalAcpiBrokenPiix4TimerCarry (
; VOID
; )
;
; Routine Description:
;
; This routine does nothing. When we are using the Broken Piix4
; Code (TM), we are guaranteed to have examined the timer many times
; since the last rollover. So we don't need to do any bookkeeping
; here.
;
; N.B. This function is called at interrupt time and assumes the
; caller clears the interrupt
;
; Arguments:
;
; None
;
; Return Value:
;
; None
;
;--
cPublicProc _HalAcpiBrokenPiix4TimerCarry, 0
stdRET _HalAcpiBrokenPiix4TimerCarry
stdENDP _HalAcpiBrokenPiix4TimerCarry
_TEXT$03 ends
end