home *** CD-ROM | disk | FTP | other *** search
/ Troubleshooting Netware Systems / CSTRIAL0196.BIN / attach / msj / v10n05 / dynvxd.exe / VCYCLASM.EXE / VCYCLE.ASM < prev    next >
Assembly Source File  |  1995-05-01  |  16KB  |  367 lines

  1. ;==============================================================================
  2. ;
  3. ;    VCYCLE.ASM -- Virtual Device for Pentium RDTSC performance counter
  4. ;
  5. ;    Written by Walter Oney
  6. ;
  7. ;==============================================================================
  8.  
  9.          name  capvxd
  10.          .486p
  11.          include vmm.inc
  12.          include vwin32.inc
  13.          include debug.inc
  14.  
  15. devid    equ   Undefined_Device_ID             ; don't need a unique id
  16.  
  17. byp      equ   <byte ptr>
  18. wp       equ   <word ptr>
  19. dwp      equ   <dword ptr>
  20. fwp      equ   <fword ptr>
  21.  
  22. ;------------------------------------------------------------------------------
  23. ;              D E V I C E   D E F I N I T I O N   B L O C K
  24. ;------------------------------------------------------------------------------
  25.  
  26. Declare_Virtual_Device VCYCLE, 1, 0, control, devid, Undefined_Init_Order
  27.  
  28. ;------------------------------------------------------------------------------
  29. ;                          D A T A   A R E A S
  30. ;------------------------------------------------------------------------------
  31.  
  32. VxD_LOCKED_DATA_SEG
  33.  
  34. tcounter dd    -1                              ; THCB cell containing pointer
  35.                                                ;   to thread's RDTSC counter
  36. nvirtual dd    0                               ; number of virtualized counters
  37.                                                ;   system-wide
  38.  
  39. servtbl  label dword                           ; DeviceIoControl service table
  40.          dd    offset32 closehandle            ; -1 -- DIOC_CLOSEHANDLE
  41.          dd    offset32 getversion             ;  0 -- DIOC_GETVERSION
  42.          dd    offset32 getappversion          ;  1 -- GETAPPVERSION
  43.          dd    offset32 virtualizecounter      ;  2 -- VIRTUALIZECOUNTER
  44. numservices equ ($-servtbl)/4
  45.  
  46. VxD_LOCKED_DATA_ENDS
  47.  
  48. ;------------------------------------------------------------------------------
  49. ;            D E V I C E   C O N T R O L   P R O C E D U R E
  50. ;------------------------------------------------------------------------------
  51.  
  52. VxD_LOCKED_CODE_SEG
  53.  
  54. BeginProc control
  55.  
  56.          Control_Dispatch Sys_Dynamic_Device_Init, dyninit
  57.          Control_Dispatch Sys_Dynamic_Device_Exit, dynexit
  58.          Control_Dispatch W32_DeviceIocontrol,     devctrl
  59.          Control_Dispatch Create_Thread,           threadcreate
  60.          Control_Dispatch Terminate_Thread,        threadterm
  61.  
  62.          clc                                   ; indicate no error
  63.          ret
  64.  
  65. EndProc  control
  66.  
  67. ;------------------------------------------------------------------------------
  68. ;         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
  69. ;------------------------------------------------------------------------------
  70.  
  71. BeginProc dyninit
  72.  
  73.          Trace_Out 'VCYCLE: Dynamic loading'
  74.  
  75. ;    Are we on a Pentium? If not, there's no point in loading.
  76.  
  77.          VMMCall Get_Machine_Info              ; get system information
  78.          bt    ebx, GMIF_CPUID_BIT             ; is this a Pentium?
  79.          jnc   dyninit_nopoint                 ; if not, never mind
  80.  
  81. ;    Allocate a thread data slot to hold the address (if any) of the
  82. ;    the application's last-counter cell
  83.  
  84.          VMMCall _AllocateThreadDataSlot       ; allocate a slot in TLS
  85.          test  eax, eax                        ; success?
  86.          jz    dyninit_fail                    ; if not, signal error
  87.          mov   tcounter, eax                   ; yes. save offset
  88.  
  89. ;    Thread data slots aren't initialized, so enumerate the currently
  90. ;    active threads in order to zero the slot we just allocated.
  91.  
  92.          VMMCall Get_Sys_Thread_Handle         ; get a starting point
  93.          mov   esi, edi                        ; remember so we can stop loop
  94. @@:
  95.          mov   eax, edi                        ; zero this thread's slot
  96.          add   eax, tcounter                   ;   ..
  97.          mov   dwp [eax], 0                    ;   ..
  98.          VMMCall Get_Next_Thread_Handle        ; find next thread
  99.          cmp   edi, esi                        ; back to starting point
  100.          jne   @B                              ; if not, continue enumeration
  101.  
  102. ;    Establish a thread-switch callback routine
  103.  
  104.          mov   esi, offset32 threadswitch      ; setup thread-switch callback
  105.          VMMCall Call_When_Thread_Switched     ;   ..
  106.  
  107.          clc                                   ; indicate success
  108.          ret                                   ; return to vxd loader
  109.  
  110. dyninit_fail:
  111.          Debug_Out 'VCYCLE: Unable to allocate thread data slots'
  112.          stc                                   ; indicate failure
  113.          ret                                   ; return to vxd loader
  114.  
  115. dyninit_nopoint:
  116.          Trace_Out 'VCYCLE: Not loading on this 486 or earlier processor'
  117.          stc                                   ; indicate failure
  118.          ret                                   ; return to vxd loader
  119.  
  120. EndProc  dyninit
  121.  
  122. ;------------------------------------------------------------------------------
  123. ;                      D Y N A M I C   U N L O A D
  124. ;------------------------------------------------------------------------------
  125.  
  126. BeginProc dynexit
  127.  
  128.          Trace_Out 'VCYCLE: Dynamic unload'
  129.  
  130.          mov   esi, offset32 threadswitch      ; remove thread-switch callback
  131.          VMMCall Cancel_Call_When_Thread_Switched
  132.          jc    dynexit_fail                    ; don't unload if that fails
  133.  
  134. ;    Unlock any virtual counter pages that may still be lying around
  135.  
  136.          cmp   nvirtual, 0                     ; any counters still virtualized?
  137.          je    dynexit_1                       ; if yes, okay
  138.  
  139. IFDEF DEBUG
  140.          mov   eax, nvirtual
  141.          Trace_Out 'VCYCLE: #EAX virtual counter(s) not closed'
  142. ENDIF
  143.  
  144.          VMMCall Get_Sys_Thread_Handle         ; get a starting place
  145.          mov   esi, edi                        ; ESI = starting thread handle
  146. @@:
  147.          call  unlockcounter                   ; unlock this thread's counter
  148.          VMMCall Get_Next_Thread_Handle        ; get next (wraps to next VM)
  149.          cmp   edi, esi                        ; back to starting point?
  150.          jne   @B                              ; if not, continue enumeration
  151.  
  152. ;    Release our thread data slot
  153.  
  154. dynexit_1:
  155.          mov   eax, -1                         ; set "tcounter" to -1
  156.          xchg  eax, tcounter                   ;   ..
  157.          VMMCall _FreeThreadDataSlot, <eax>    ; release THCB slot
  158.  
  159.          clc                                   ; indicate no error
  160.          ret                                   ; return to vxd loader
  161.  
  162. dynexit_fail:
  163. Debug_Out 'VCYCLE: Cannot unload because cannot cancel thread-switch callback'
  164.          stc                                   ; indicate failure
  165.          ret                                   ; return to vxd loader
  166.  
  167. EndProc   dynexit
  168.  
  169. ;------------------------------------------------------------------------------
  170. ;           D E V I C E I O C O N T R O L   I N T E R F A C E
  171. ;------------------------------------------------------------------------------
  172.  
  173. ;    ENTRY:
  174. ;        ESI -> address of DIOC structure
  175.  
  176. BeginProc devctrl
  177.          mov   ecx, [esi+dwIoControlCode]      ; ECX = service index
  178.          inc   ecx                             ; add one to service index
  179.          cmp   ecx, numservices                ; is service in bounds?
  180.          jae   devctrl_fail                    ; if not, fail the call
  181.          jmp   servtbl[4*ecx]                  ; yes. branch to server
  182.  
  183. ;------------------------------------------------------------------------------
  184.  
  185. ;    ECX = -1 (DIOC_CLOSEHANDLE)
  186.  
  187. closehandle:
  188.          jmp   devctrl_okay
  189.  
  190. ;------------------------------------------------------------------------------
  191.  
  192. ;    ECX = 0 (DIOC_GETVERSION)
  193.  
  194. getversion:
  195.          jmp   devctrl_okay                    ; satisfy check by VWIN32's
  196.                                                ;   CreateFile handler
  197.  
  198. ;------------------------------------------------------------------------------
  199.  
  200. ;    ECX = 1 (GETAPPVERSION)
  201. ;
  202. ;    Output:
  203. ;        0     (DWORD) version number of this VxD
  204.  
  205. getappversion:
  206.          cmp   [esi+cbOutBuffer], 4            ; need at least 4 output bytes
  207.          jb    @F                              ; fail call if not
  208.          mov   edx, [esi+lpvOutBuffer]         ; point to output buffer
  209.          test  edx, edx                        ; be sure not null
  210.          jz    @F                              ;   ..
  211.  
  212.          movzx eax, wp VCYCLE_DDB + DDB_Dev_Major_Version
  213.          xchg  ah, al                          ; (fields reversed in DDB)
  214.          mov   dwp [edx], eax                  ; store version number
  215.  
  216.          mov   edx, [esi+lpcbBytesReturned]    ; get ptr to caller's variable
  217.          test  edx, edx                        ; make sure not null
  218.          jz    @F                              ;   ..
  219.          mov   dwp [edx], 4                    ; store # bytes returned
  220. @@:
  221.          jmp   devctrl_okay                    ; done
  222.  
  223. ;------------------------------------------------------------------------------
  224.  
  225. ;    ECX = 2 (VIRTUALIZECOUNTER)
  226. ;
  227. ;    Input:
  228. ;       0       (DWORD) Address of counter to virtualize
  229.  
  230. virtualizecounter:
  231.          Trace_Out 'VCYCLE: VIRTUALIZECOUNTER'
  232.  
  233.          cmp   [esi+cbInBuffer], 4             ; need at least 4 input bytes
  234.          jb    devctrl_fail                    ; error if not
  235.  
  236.          push  edi                             ; save working register (1)
  237.          VMMCall Get_Cur_Thread_Handle         ; EDI = address of current THCB
  238.          call  unlockcounter                   ; unlock previous counter cell
  239.  
  240.          mov   edx, [esi+lpvInBuffer]          ; point to input data
  241.          mov   eax, dwp [edx]                  ; get address of virtual counter
  242.          test  eax, eax                        ; is it zero?
  243.          jz    dontlock                        ; if yes, nothing more to do
  244.  
  245.          push  eax                             ; save on stack (2)
  246.          shr   eax, 12                         ; convert to page number
  247.          VMMCall _LinPageLock, <eax, 1, PAGEMAPGLOBAL>
  248.          pop   edx                             ; restore original address (2)
  249.          test  eax, eax                        ; did we succeed?
  250.          jz    cantlock                        ; if not, error
  251.  
  252. ;    The undocumented return from LinPageLock is the global alias address for
  253. ;    the page we locked. This can be used out-of-context to access the page
  254. ;    during thread switches.
  255.  
  256.          and   eax, not 4095                   ; shouldn't be necessary
  257.          and   edx, 4095                       ; compute global addr of counter
  258.          or    eax, edx                        ;   ..
  259.  
  260.          add   edi, tcounter                   ; point to our slot in THCB
  261.          mov   dwp [edi], eax                  ; save for task switches
  262.          inc   nvirtual                        ; adjust bookkeeping counter
  263.  
  264. dontlock:
  265.          pop   edi                             ; restore EDI (1)
  266.          jmp   devctrl_okay                    ; done
  267.  
  268. cantlock:
  269.          Debug_Out 'VCYCLE: LinPageLock failed for counters at #EDX'
  270.          pop   edi                             ; restore EDI (1)
  271.          jmp   devctrl_fail                    ; fail the call
  272.  
  273. ;------------------------------------------------------------------------------
  274.  
  275. devctrl_okay:
  276.          xor   eax, eax                        ; indicate success
  277.          clc                                   ;   ..
  278.          ret                                   ; return to VWIN32
  279.  
  280. devctrl_fail:
  281.          mov   eax, 50                         ; ERROR_NOT_SUPPORTED
  282.          stc                                   ; indicate error
  283.          ret                                   ; return to VWIN32
  284.  
  285. EndProc  devctrl
  286.  
  287. ;------------------------------------------------------------------------------
  288. ;                         C R E A T E _ T H R E A D
  289. ;------------------------------------------------------------------------------
  290.  
  291. BeginProc threadcreate
  292.          mov   eax, tcounter                   ; get offset of counter pointer
  293.          cmp   eax, -1                         ; is it -1 (unallocated?)
  294.          je    @F                              ; if yes, nothing to do here
  295.          add   eax, edi                        ; yes. point to THCB cell
  296.          mov   dwp [eax], 0                    ; initialize cell to zero
  297. @@:
  298.          clc                                   ; allow thread to be created
  299.          ret                                   ; return to caller
  300. EndProc  threadcreate
  301.  
  302. ;------------------------------------------------------------------------------
  303. ;                      T E R M I N A T E _ T H R E A D
  304. ;------------------------------------------------------------------------------
  305.  
  306. BeginProc threadterm
  307.          cmp   tcounter, -1                    ; counter cell allocated?
  308.          je    @F                              ; if not, skip unlock call
  309.          call  unlockcounter                   ; release counter if necessary
  310. @@:
  311.          clc                                   ; indicate no error
  312.          ret                                   ; return to caller
  313. EndProc  threadterm
  314.  
  315. ;    ENTRY:
  316. ;        EDI -> thread control block
  317.  
  318. BeginProc unlockcounter
  319.          push  edi                             ; save EDI (THCB address)
  320.          add   edi, tcounter                   ; get address of counter cell
  321.          xor   eax, eax                        ;   and reset cell pointer to 0
  322.          xchg  eax, dwp [edi]                  ;   ..
  323.          test  eax, eax                        ; is there one?
  324.          jz    @F                              ; if not, nothing to do
  325.  
  326.          dec   nvirtual                        ; adjust bookkeeping counter
  327.          shr   eax, 12                         ; convert to page index
  328.          VMMCall _LinPageUnlock, <eax, 1, PAGEMAPGLOBAL>
  329. @@:
  330.          pop   edi                             ; restore EDI
  331.          ret                                   ; return to local caller
  332. EndProc  unlockcounter
  333.  
  334. ;------------------------------------------------------------------------------
  335. ;              T H R E A D   S W I T C H   C A L L B A C K
  336. ;------------------------------------------------------------------------------
  337.  
  338. ;    ENTRY:
  339. ;        EAX -> outgoing thread's thcb
  340. ;        EDI -> incoming thread's thcb
  341.  
  342. BeginProc threadswitch
  343.          mov   ecx, eax                        ; save outgoing thcb addr
  344.          db    0Fh, 31h                        ; RDTSC -- EDX:EAX = cycle count
  345.  
  346.          add   ecx, tcounter                   ; locate outgoing & incoming
  347.          add   edi, tcounter                   ;   app's contouners
  348.          mov   ecx, dwp [ecx]                  ;   ..
  349.          mov   edi, dwp [edi]                  ;   ..
  350.  
  351.          test  ecx, ecx                        ; update old thread's counter
  352.          jz    @F                              ;   ..
  353.          sub   dwp [ecx], eax                  ;   ..
  354.          sbb   dwp [ecx+4], edx                ;   ..
  355. @@:
  356.          test  edi, edi                        ; update new thread's counter
  357.          jz    @F                              ;   ..
  358.          add   dwp [edi], eax                  ;   ..
  359.          adc   dwp [edi+4], edx                ;   ..
  360. @@:
  361.          ret                                   ; return to scheduler
  362. EndProc  threadswitch
  363.  
  364. VxD_LOCKED_CODE_ENDS
  365.  
  366.          end
  367.