home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Troubleshooting Netware Systems
/
CSTRIAL0196.BIN
/
attach
/
msj
/
v10n05
/
dynvxd.exe
/
VCYCLASM.EXE
/
VCYCLE.ASM
< prev
next >
Wrap
Assembly Source File
|
1995-05-01
|
16KB
|
367 lines
;==============================================================================
;
; VCYCLE.ASM -- Virtual Device for Pentium RDTSC performance counter
;
; Written by Walter Oney
;
;==============================================================================
name capvxd
.486p
include vmm.inc
include vwin32.inc
include debug.inc
devid equ Undefined_Device_ID ; don't need a unique id
byp equ <byte ptr>
wp equ <word ptr>
dwp equ <dword ptr>
fwp equ <fword ptr>
;------------------------------------------------------------------------------
; D E V I C E D E F I N I T I O N B L O C K
;------------------------------------------------------------------------------
Declare_Virtual_Device VCYCLE, 1, 0, control, devid, Undefined_Init_Order
;------------------------------------------------------------------------------
; D A T A A R E A S
;------------------------------------------------------------------------------
VxD_LOCKED_DATA_SEG
tcounter dd -1 ; THCB cell containing pointer
; to thread's RDTSC counter
nvirtual dd 0 ; number of virtualized counters
; system-wide
servtbl label dword ; DeviceIoControl service table
dd offset32 closehandle ; -1 -- DIOC_CLOSEHANDLE
dd offset32 getversion ; 0 -- DIOC_GETVERSION
dd offset32 getappversion ; 1 -- GETAPPVERSION
dd offset32 virtualizecounter ; 2 -- VIRTUALIZECOUNTER
numservices equ ($-servtbl)/4
VxD_LOCKED_DATA_ENDS
;------------------------------------------------------------------------------
; D E V I C E C O N T R O L P R O C E D U R E
;------------------------------------------------------------------------------
VxD_LOCKED_CODE_SEG
BeginProc control
Control_Dispatch Sys_Dynamic_Device_Init, dyninit
Control_Dispatch Sys_Dynamic_Device_Exit, dynexit
Control_Dispatch W32_DeviceIocontrol, devctrl
Control_Dispatch Create_Thread, threadcreate
Control_Dispatch Terminate_Thread, threadterm
clc ; indicate no error
ret
EndProc control
;------------------------------------------------------------------------------
; D Y N A M I C L O A D I N I T I A L I Z A T I O N
;------------------------------------------------------------------------------
BeginProc dyninit
Trace_Out 'VCYCLE: Dynamic loading'
; Are we on a Pentium? If not, there's no point in loading.
VMMCall Get_Machine_Info ; get system information
bt ebx, GMIF_CPUID_BIT ; is this a Pentium?
jnc dyninit_nopoint ; if not, never mind
; Allocate a thread data slot to hold the address (if any) of the
; the application's last-counter cell
VMMCall _AllocateThreadDataSlot ; allocate a slot in TLS
test eax, eax ; success?
jz dyninit_fail ; if not, signal error
mov tcounter, eax ; yes. save offset
; Thread data slots aren't initialized, so enumerate the currently
; active threads in order to zero the slot we just allocated.
VMMCall Get_Sys_Thread_Handle ; get a starting point
mov esi, edi ; remember so we can stop loop
@@:
mov eax, edi ; zero this thread's slot
add eax, tcounter ; ..
mov dwp [eax], 0 ; ..
VMMCall Get_Next_Thread_Handle ; find next thread
cmp edi, esi ; back to starting point
jne @B ; if not, continue enumeration
; Establish a thread-switch callback routine
mov esi, offset32 threadswitch ; setup thread-switch callback
VMMCall Call_When_Thread_Switched ; ..
clc ; indicate success
ret ; return to vxd loader
dyninit_fail:
Debug_Out 'VCYCLE: Unable to allocate thread data slots'
stc ; indicate failure
ret ; return to vxd loader
dyninit_nopoint:
Trace_Out 'VCYCLE: Not loading on this 486 or earlier processor'
stc ; indicate failure
ret ; return to vxd loader
EndProc dyninit
;------------------------------------------------------------------------------
; D Y N A M I C U N L O A D
;------------------------------------------------------------------------------
BeginProc dynexit
Trace_Out 'VCYCLE: Dynamic unload'
mov esi, offset32 threadswitch ; remove thread-switch callback
VMMCall Cancel_Call_When_Thread_Switched
jc dynexit_fail ; don't unload if that fails
; Unlock any virtual counter pages that may still be lying around
cmp nvirtual, 0 ; any counters still virtualized?
je dynexit_1 ; if yes, okay
IFDEF DEBUG
mov eax, nvirtual
Trace_Out 'VCYCLE: #EAX virtual counter(s) not closed'
ENDIF
VMMCall Get_Sys_Thread_Handle ; get a starting place
mov esi, edi ; ESI = starting thread handle
@@:
call unlockcounter ; unlock this thread's counter
VMMCall Get_Next_Thread_Handle ; get next (wraps to next VM)
cmp edi, esi ; back to starting point?
jne @B ; if not, continue enumeration
; Release our thread data slot
dynexit_1:
mov eax, -1 ; set "tcounter" to -1
xchg eax, tcounter ; ..
VMMCall _FreeThreadDataSlot, <eax> ; release THCB slot
clc ; indicate no error
ret ; return to vxd loader
dynexit_fail:
Debug_Out 'VCYCLE: Cannot unload because cannot cancel thread-switch callback'
stc ; indicate failure
ret ; return to vxd loader
EndProc dynexit
;------------------------------------------------------------------------------
; D E V I C E I O C O N T R O L I N T E R F A C E
;------------------------------------------------------------------------------
; ENTRY:
; ESI -> address of DIOC structure
BeginProc devctrl
mov ecx, [esi+dwIoControlCode] ; ECX = service index
inc ecx ; add one to service index
cmp ecx, numservices ; is service in bounds?
jae devctrl_fail ; if not, fail the call
jmp servtbl[4*ecx] ; yes. branch to server
;------------------------------------------------------------------------------
; ECX = -1 (DIOC_CLOSEHANDLE)
closehandle:
jmp devctrl_okay
;------------------------------------------------------------------------------
; ECX = 0 (DIOC_GETVERSION)
getversion:
jmp devctrl_okay ; satisfy check by VWIN32's
; CreateFile handler
;------------------------------------------------------------------------------
; ECX = 1 (GETAPPVERSION)
;
; Output:
; 0 (DWORD) version number of this VxD
getappversion:
cmp [esi+cbOutBuffer], 4 ; need at least 4 output bytes
jb @F ; fail call if not
mov edx, [esi+lpvOutBuffer] ; point to output buffer
test edx, edx ; be sure not null
jz @F ; ..
movzx eax, wp VCYCLE_DDB + DDB_Dev_Major_Version
xchg ah, al ; (fields reversed in DDB)
mov dwp [edx], eax ; store version number
mov edx, [esi+lpcbBytesReturned] ; get ptr to caller's variable
test edx, edx ; make sure not null
jz @F ; ..
mov dwp [edx], 4 ; store # bytes returned
@@:
jmp devctrl_okay ; done
;------------------------------------------------------------------------------
; ECX = 2 (VIRTUALIZECOUNTER)
;
; Input:
; 0 (DWORD) Address of counter to virtualize
virtualizecounter:
Trace_Out 'VCYCLE: VIRTUALIZECOUNTER'
cmp [esi+cbInBuffer], 4 ; need at least 4 input bytes
jb devctrl_fail ; error if not
push edi ; save working register (1)
VMMCall Get_Cur_Thread_Handle ; EDI = address of current THCB
call unlockcounter ; unlock previous counter cell
mov edx, [esi+lpvInBuffer] ; point to input data
mov eax, dwp [edx] ; get address of virtual counter
test eax, eax ; is it zero?
jz dontlock ; if yes, nothing more to do
push eax ; save on stack (2)
shr eax, 12 ; convert to page number
VMMCall _LinPageLock, <eax, 1, PAGEMAPGLOBAL>
pop edx ; restore original address (2)
test eax, eax ; did we succeed?
jz cantlock ; if not, error
; The undocumented return from LinPageLock is the global alias address for
; the page we locked. This can be used out-of-context to access the page
; during thread switches.
and eax, not 4095 ; shouldn't be necessary
and edx, 4095 ; compute global addr of counter
or eax, edx ; ..
add edi, tcounter ; point to our slot in THCB
mov dwp [edi], eax ; save for task switches
inc nvirtual ; adjust bookkeeping counter
dontlock:
pop edi ; restore EDI (1)
jmp devctrl_okay ; done
cantlock:
Debug_Out 'VCYCLE: LinPageLock failed for counters at #EDX'
pop edi ; restore EDI (1)
jmp devctrl_fail ; fail the call
;------------------------------------------------------------------------------
devctrl_okay:
xor eax, eax ; indicate success
clc ; ..
ret ; return to VWIN32
devctrl_fail:
mov eax, 50 ; ERROR_NOT_SUPPORTED
stc ; indicate error
ret ; return to VWIN32
EndProc devctrl
;------------------------------------------------------------------------------
; C R E A T E _ T H R E A D
;------------------------------------------------------------------------------
BeginProc threadcreate
mov eax, tcounter ; get offset of counter pointer
cmp eax, -1 ; is it -1 (unallocated?)
je @F ; if yes, nothing to do here
add eax, edi ; yes. point to THCB cell
mov dwp [eax], 0 ; initialize cell to zero
@@:
clc ; allow thread to be created
ret ; return to caller
EndProc threadcreate
;------------------------------------------------------------------------------
; T E R M I N A T E _ T H R E A D
;------------------------------------------------------------------------------
BeginProc threadterm
cmp tcounter, -1 ; counter cell allocated?
je @F ; if not, skip unlock call
call unlockcounter ; release counter if necessary
@@:
clc ; indicate no error
ret ; return to caller
EndProc threadterm
; ENTRY:
; EDI -> thread control block
BeginProc unlockcounter
push edi ; save EDI (THCB address)
add edi, tcounter ; get address of counter cell
xor eax, eax ; and reset cell pointer to 0
xchg eax, dwp [edi] ; ..
test eax, eax ; is there one?
jz @F ; if not, nothing to do
dec nvirtual ; adjust bookkeeping counter
shr eax, 12 ; convert to page index
VMMCall _LinPageUnlock, <eax, 1, PAGEMAPGLOBAL>
@@:
pop edi ; restore EDI
ret ; return to local caller
EndProc unlockcounter
;------------------------------------------------------------------------------
; T H R E A D S W I T C H C A L L B A C K
;------------------------------------------------------------------------------
; ENTRY:
; EAX -> outgoing thread's thcb
; EDI -> incoming thread's thcb
BeginProc threadswitch
mov ecx, eax ; save outgoing thcb addr
db 0Fh, 31h ; RDTSC -- EDX:EAX = cycle count
add ecx, tcounter ; locate outgoing & incoming
add edi, tcounter ; app's contouners
mov ecx, dwp [ecx] ; ..
mov edi, dwp [edi] ; ..
test ecx, ecx ; update old thread's counter
jz @F ; ..
sub dwp [ecx], eax ; ..
sbb dwp [ecx+4], edx ; ..
@@:
test edi, edi ; update new thread's counter
jz @F ; ..
add dwp [edi], eax ; ..
adc dwp [edi+4], edx ; ..
@@:
ret ; return to scheduler
EndProc threadswitch
VxD_LOCKED_CODE_ENDS
end