318 lines
8.3 KiB
NASM
318 lines
8.3 KiB
NASM
|
|
title "Stall Execution Support"
|
|
;++
|
|
;
|
|
; Copyright (c) 1989 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; ixstall.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements the code necessary to field and process the
|
|
; interval clock interrupt.
|
|
;
|
|
; Author:
|
|
;
|
|
; Shie-Lin Tzong (shielint) 12-Jan-1990
|
|
;
|
|
; Environment:
|
|
;
|
|
; Kernel mode only.
|
|
;
|
|
; Revision History:
|
|
;
|
|
; bryanwi 20-Sep-90
|
|
;
|
|
; Add KiSetProfileInterval, KiStartProfileInterrupt,
|
|
; KiStopProfileInterrupt procedures.
|
|
; KiProfileInterrupt ISR.
|
|
; KiProfileList, KiProfileLock are delcared here.
|
|
;
|
|
; shielint 10-Dec-90
|
|
; Add performance counter support.
|
|
; Move system clock to irq8, ie we now use RTC to generate system
|
|
; clock. Performance count and Profile use timer 1 counter 0.
|
|
; The interval of the irq0 interrupt can be changed by
|
|
; KiSetProfileInterval. Performance counter does not care about the
|
|
; interval of the interrupt as long as it knows the rollover count.
|
|
; Note: Currently I implemented 1 performance counter for the whole
|
|
; i386 NT.
|
|
;
|
|
; John Vert (jvert) 11-Jul-1991
|
|
; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
|
|
;
|
|
; shie-lin tzong (shielint) 13-March-92
|
|
; Move System clock back to irq0 and use RTC (irq8) to generate
|
|
; profile interrupt. Performance counter and system clock use time1
|
|
; counter 0 of 8254.
|
|
;
|
|
; Landy Wang (corollary!landy) 04-Dec-92
|
|
; Created this module by moving routines from ixclock.asm to here.
|
|
;
|
|
;--
|
|
|
|
.386p
|
|
.xlist
|
|
include hal386.inc
|
|
include callconv.inc ; calling convention macros
|
|
include i386\ix8259.inc
|
|
include i386\kimacro.inc
|
|
include mac386.inc
|
|
include i386\ixcmos.inc
|
|
include xxacpi.h
|
|
.list
|
|
|
|
EXTRNP _KeBugCheckEx,5,IMPORT
|
|
EXTRNP _DbgBreakPoint,0,IMPORT
|
|
EXTRNP _HalpAcquireCmosSpinLock ,0
|
|
EXTRNP _HalpReleaseCmosSpinLock ,0
|
|
extrn _HalpFixedAcpiDescTable:DWORD
|
|
extrn _QueryTimer:DWORD
|
|
extrn _PMTimerFreq:DWORD
|
|
|
|
_DATA SEGMENT DWORD PUBLIC 'DATA'
|
|
|
|
MinimumLoopQuantum equ 42
|
|
MinimumLoopCount dd MinimumLoopQuantum
|
|
KqpcStallCount db 0
|
|
|
|
; temptemp
|
|
if DBG
|
|
HalpAcpiStallIns dd 0
|
|
endif
|
|
|
|
_DATA ends
|
|
|
|
INIT SEGMENT PARA PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
page ,132
|
|
subttl "Initialize Stall Execution Counter"
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpInitializeStallExecution (
|
|
; IN CCHAR ProcessorNumber
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This routine is obsolete in this HAL.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; ProcessorNumber - Processor Number
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicProc _HalpInitializeStallExecution ,1
|
|
stdRET _HalpInitializeStallExecution
|
|
stdENDP _HalpInitializeStallExecution
|
|
|
|
page ,132
|
|
subttl "Stall Execution"
|
|
|
|
cPublicProc _HalpRemoveFences
|
|
mov word ptr fence1, 0c98bh
|
|
stdRET _HalpRemoveFences
|
|
stdENDP _HalpRemoveFences
|
|
|
|
INIT ends
|
|
|
|
_TEXT SEGMENT PARA PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; HalpAcpiTimerStallExecProc(
|
|
; 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.
|
|
;
|
|
; Comments:
|
|
;
|
|
; edi - total ticks elapsed
|
|
; ebx:esi - starting time, in ticks
|
|
;
|
|
;--
|
|
|
|
Target equ [ebp + 8]
|
|
cyclesStalled equ [ebp - 4]
|
|
|
|
MASK24 equ 0ff000000h
|
|
BIT24 equ 001000000h
|
|
|
|
cPublicProc _HalpAcpiTimerStallExecProc ,1
|
|
cPublicFpo 1, 5
|
|
|
|
;
|
|
; Issue a CPUID to implement a "fence"
|
|
;
|
|
push ebp
|
|
mov ebp, esp
|
|
sub esp, 4 ; make room for locals
|
|
push ebx ; cpuid uses eax, ebx, ecx, edx
|
|
push esi
|
|
push edi
|
|
|
|
xor eax, eax ; Processor zero
|
|
|
|
.586p
|
|
fence1: cpuid
|
|
.386p
|
|
|
|
xor edi, edi ; zero total stall count
|
|
|
|
mov eax, Target
|
|
|
|
or eax, eax
|
|
jz aese10 ; return if no loop needed
|
|
|
|
; 'Target' starts out as the argument of the function.
|
|
; It is in uSeconds. We convert to timer ticks.
|
|
mov ebx, _PMTimerFreq
|
|
mul ebx
|
|
mov ebx, 1000000
|
|
div ebx
|
|
sub eax, 1 ; fudge factor
|
|
|
|
mov Target, eax
|
|
|
|
mov eax, _QueryTimer ; move current counter into edx:eax
|
|
call eax
|
|
|
|
mov esi, eax ; record the starting tick count
|
|
mov ebx, edx
|
|
|
|
if DBG
|
|
inc HalpAcpiStallIns
|
|
endif
|
|
mov cyclesStalled, 0
|
|
mov eax, MinimumLoopCount
|
|
|
|
AcpiLoop:
|
|
add cyclesStalled, eax ; update total cycles stalled
|
|
ALIGN 16
|
|
YIELD
|
|
jmp short aese05
|
|
|
|
ALIGN 16
|
|
YIELD
|
|
aese05: sub eax, 1 ; (eax) = (eax) - 1
|
|
jnz short aese05
|
|
|
|
;
|
|
; Now figure out if we have to loop again
|
|
;
|
|
mov eax, _QueryTimer ; move current counter into edx:eax
|
|
call eax
|
|
|
|
sub eax, esi ; get actual elapsed ticks
|
|
sbb edx, ebx ; check to see that the upper 32 bits agrees
|
|
|
|
if 0
|
|
jnl short @f
|
|
int 3 ; time seems to have gone backwards
|
|
@@:
|
|
endif
|
|
|
|
jz short aese06
|
|
;
|
|
; If the upper 32 bits doesn't agree, then something, perhaps the debugger,
|
|
; has caused time to slip a whole lot. Just fix up the bottom 32-bits to
|
|
; reflect a large time slip to make the math simpler.
|
|
;
|
|
|
|
mov eax, 7fffffffh
|
|
aese06:
|
|
|
|
; edx:eax now contains the number of timer ticks elapsed
|
|
|
|
cmp eax, 3 ; if 1 less than 1uS elapsed, loop some more
|
|
jge short aese09
|
|
|
|
add MinimumLoopCount, MinimumLoopQuantum
|
|
mov eax, MinimumLoopCount
|
|
jmp short AcpiLoop ; loop some more
|
|
|
|
aese09: mov edi, eax ; edi <- total number of ticks elapsed
|
|
|
|
if DBG
|
|
or edi, edi ; if the total elapsed ticks is still 0,
|
|
jz short aese20 ; the timer hardware is broken. Bugcheck.
|
|
endif
|
|
|
|
; if we have waited long enough, quit
|
|
cmp edi, Target
|
|
jge short aese10
|
|
|
|
; calculate remaining wait
|
|
push ebx
|
|
mov ebx, Target
|
|
sub ebx, edi ; ebx <- remaining ticks
|
|
|
|
mov eax, cyclesStalled
|
|
mul ebx ; multiply by number of ticks remaining to wait
|
|
and edx, 011b ; chop edx so that we don't overflow
|
|
div edi ; divide by the number of ticks we have waited
|
|
inc eax ; Never zero!
|
|
pop ebx
|
|
@@: jmp AcpiLoop
|
|
|
|
aese10:
|
|
;
|
|
; Knock down MinimumLoopCount once every 0x100 calls to this
|
|
; function so that we don't accidentally stall for very
|
|
; large amounts of time.
|
|
;
|
|
|
|
inc KqpcStallCount
|
|
.if ((KqpcStallCount == 0) && (MinimumLoopCount > MinimumLoopQuantum))
|
|
mov eax, MinimumLoopCount
|
|
sub eax, MinimumLoopQuantum
|
|
mov MinimumLoopCount, eax
|
|
.endif
|
|
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
mov esp, ebp
|
|
pop ebp
|
|
stdRET _HalpAcpiTimerStallExecProc
|
|
|
|
if DBG
|
|
aese20:
|
|
mov eax, 0a5h
|
|
mov ebx, 020000h
|
|
xor esi, esi
|
|
xor edi, edi
|
|
stdCall _KeBugCheckEx, <eax, ebx, edx, esi, edi>
|
|
jmp short aese10
|
|
endif
|
|
|
|
stdENDP _HalpAcpiTimerStallExecProc
|
|
|
|
_TEXT ends
|
|
|
|
end
|