home *** CD-ROM | disk | FTP | other *** search
-
- Description of the STAT.386 API v3.2.3 from 01.04.1996
- =============================== STAT.386 driver v01.03
-
- The file contains a description of the STAT.386 API (Application Program[ming]
- Interface) and some programming examples for it.
-
-
- 1. Introduction
- ================
-
- The STAT.386 driver was written by Ton Plooy (tonp@xs4all.nl) in December 1995
- to make STAT.EXE runs under MS-Windows 3.1 or MS-Windows 95 too. To be able to
- execute some iPentium-specific instructions, like RDTSC, RDMSR and WRMSR, your
- code needs to run at CPL=0 (Code Privilege Level #0), to avoid exceptioms from
- these instructions, listed above.
-
- Because the DOS box under MS-Windows 3.1 or MS-Windows 95 runs at CPL=3 (which
- is the lowest privilege level), you can't execute a RDMSR or WRMSR instruction
- in the DOS box. This causes an exception and MS-Windows will close the DOS box
- then. So you need -- somehow -- access to CPL=0.
-
- Outside the MS-Windows DOS box STAT.EXE will use the VCPI API (Virtual Control
- Program[ming] Interface), to enter CPL=0, execute the iPentium-specific RDTSC,
- RDMSR or WRMSR instructions, and to return to CPL=3. (The VCPI API is provided
- by most EMM386 drivers, as EMM386.EXE, QEMM386.SYS etc. If you load one of the
- EMM386 drivers, then the driver kernel runs at CPL=0, to have the full control
- over your machine, and your 'DOS command line' runs at CPL=3. So the processor
- runs in virtual 8086 mode then.)
-
- The STAT.386 driver is a MS-Windows VxD. On start up MS-Windows loads all VxDs
- which are listed in the SYSTEM.INI file, section [386Enh]. There you will find
- entries like 'DEVICE=x:\path\STAT.386'. Most VxDs contain an API, which can be
- used by applications. And VxDs may contain code, which runs at CPL=0. So a VxD
- is the key to CPL=0 under MS-Windows 3.1 or MS-Windows 95. (Another way is the
- modification of the GDT (Global Descriptor Table). This table is not protected
- by MS-Windows 3.1 or MS-Windows 95. So you could include a Call Gate into this
- GDT and use it to enter CPL=0.)
-
- So the STAT.386 driver provides an API for STAT.EXE and all other programs, to
- execute the RDTSC, RDMSR and WRMSR instruction under MS-Windows 3.1 or MS-Win-
- dows 95. The driver is only neccessary, when MS-Windows runs in enhanced mode,
- because (a) VxDs are not used in standard mode and (b) MS-Windows will not use
- its own virtual mode kernel in standard mode. (So if you run standard mode and
- an EMM386 driver, then the VCPI API can be used from inside a DOS box too. But
- if you run enhanced mode and an EMM386 driver, then the MS-Windows kernel will
- replace the EMM386 driver's virtual mode kernel, and so the VCPI is disabled.)
-
-
- 2. The API
- ===========
-
- First you must check, whether the INT 2Fh is handled by someone, or not. After
- this check you can try to get the VxD entry point:
-
- ------------------------------------------------------------------------------
- in: AX=1684h function 'Get VxD Entry Point'
- BX=37DEh final unique VxD ID (assigned by Microsoft)
- ES:DI=0000:0000h clear pointer for VxD entry point
- use: INT 2Fh call multiplex interrupt
- out: ES:DI=xxxx:xxxxh VxD entry point
- ------------------------------------------------------------------------------
-
- If ES:DI returns not 0000:0000h, then the VxD is active (and so MS-Windows 3.1
- or MS-Windows 95 runs in enhanced mode). So you can call this entry point then
- for the following functions:
-
- ------------------------------------------------------------------------------
- in: AX=0000h function 'Get STAT.386 Version'
- use: call entry point call STAT.386 entry point
- out: AX=xxyyh STAT.386 version xx.yy
- rem: This function returns the internal STAT.386 driver version. The future
- versions may have a different API. So do check for the correct version
- before you call any function above 0000h!
- ------------------------------------------------------------------------------
- in: AX=0001h function 'Execute RDTSC, RDMSR or WRMSR'
- BX=00xxh 2nd opcode byte (30h, 31h or 32h)
- EDX:EDI=64 bit input value for WRMSR
- ECX=32 bit MSR number for RDMSR or WRMSR
- use: call entry point call STAT.386 entry point
- out: EDX:EAX=64 bit output value from RDTSC or RDMSR
- rem: This function executes the RDTSC, RDMSR or WRMSR instruction. Load the
- 2nd opcode byte to BL (30h=WRMSR, 31h=RDTSC, 32h=RDMSR), the MSR # for
- RDMSR or WRMSR to ECX and the MSR value for WRMSR to EDX:EDI.
- The TSC or MSR value is returned in EDX:EAX. All unused register parts
- should contain zero.
- ------------------------------------------------------------------------------
- in: AX=0002h..FFFFh reserved for future use
- use: call entry point call STAT.386 entry point
- out: nothing reserved for future use
- rem: All functions above 0001h are reserved for future use. Do not use them
- at the moment, because this may cause trouble.
- ------------------------------------------------------------------------------
-
- Attention! This API layout may be changed with future versions of the STAT.386
- driver. Only function 0000h is guaranteed to stay stable.
-
-
- 3. Programming Example
- =======================
-
- The following Turbo/Borland Pascal unit is used by STAT.EXE to handle the VxD.
-
- ------------------------------------------------------------------------------
- Unit CL_VxD; {uses the STAT.386 VxD}
-
- INTERFACE {exported stuff}
- Const VxD_ID : Word = $37DE; {final VxD ID value}
- VxD_Ver_W : Word = $0103; {actual VxD version}
- VxD_Ver_S : String[4] = '1.03'; {actual VxD version}
- Function Check_VxD : Pointer; {the install check}
- Function Get_VxD_Version : Word; {the installed version}
- Procedure CPL0_VxD(B1,B2:Byte; Var W4,W3,W2,W1:Word); {the procedure itself}
-
- IMPLEMENTATION {internal stuff}
- Uses DOS; {for some INT stuff}
- Var CPU : Registers; {for some INT stuff}
- Entry_VxD : Pointer; {for VxD entry point}
- a_Procedure : Procedure; {a dummy procedure}
-
- { The following function checks, whether the INT 2Fh is handled or not. Then }
- { it checks, whether the STAT.386 is loaded or not, and if it's loaded, then }
- { returns the VxD entry point. }
-
- Function Check_VxD:Pointer; {the install check}
- Var Int2F : Pointer; {for INT 2Fh handler}
- Begin
- GetIntVec($2F,Int2F); {get INT 2Fh handler}
- Check_VxD:=NIL; {assume no VxD}
- If Int2F<>NIL Then Begin {if INT 2Fh is handled}
- CPU.AX:=$1684; {function 'Get API'}
- CPU.BX:=VxD_ID; {signature "STAT.386"}
- CPU.DI:=$0000; {prepare VxD entry}
- CPU.ES:=$0000; {ES:DI->0000:0000}
- INTR($2F,CPU); {call multiplex INT}
- Check_VxD:=Ptr(CPU.ES,CPU.DI); {return VxD entry}
- End;
- End;
-
- { The following function returns an internal STAT.386 VxD version. If no VxD }
- { is installed, then it returns 0000h for the version. The value 0100h would }
- { indicate a version 01.00 for STAT.386. }
-
- Function Get_VxD_Version:Word; {the installed version}
- Var Version:Word; {for a dummy value}
- Begin
- Version:=$0000; {assume version 00.00}
- If Entry_VxD<>NIL Then Begin {only if installed}
- CPU.AX:=$0000; {function 0000h}
- a_Procedure; {do the CPL0 access}
- Asm MOV [Version],AX End; {return version}
- End;
- Get_VxD_Version:=Version; {return version value}
- End;
-
- { The following procedure executes the RDTSC, RDMSR or WRMSR instruction. It }
- { needs the 2nd opcode byte stored in B1, the MSR number in B2 (so here only }
- { MSR numbers from 0..FFh are supported, because B2 is a byte value) and the }
- { 64 bit wide MSR value in W4:W3:W2:W1 (W4=highest part..W1=lowest part). On }
- { RDTSC or RDMSR it returns the TSC or MSR value in W4:W3:W2:W1. }
- { Attention! Because the Turbo/Borland Pascal's integrated assembler doesn't }
- { support 32 bit code, some DB 66h statements must be used. Because there is }
- { no variable type for the 64 bit unsigned integer value available, 4x16 bit }
- { wide word variables must be used. :-( }
-
- Procedure CPL0_VxD(B1,B2:Byte; Var W4,W3,W2,W1:Word); {the procedure itself}
- Var WW4,WW3,WW2,WW1 : Word; {for some dummy values}
- Begin
- WW4:=W4; WW3:=W3; WW2:=W2; WW1:=W1; {get input values}
- If Entry_VxD<>NIL Then Begin {only if installed}
- Asm
- DB 66h; XOR BX,BX; MOV BL,[B1] {MOV EBX,[B1]} {store 2nd opcode byte}
- DB 66h; XOR CX,CX; MOV CL,[B2] {MOV ECX,[B2]} {store MSR number}
- MOV AX,[WW4]; PUSH AX; MOV AX,[WW3]; PUSH AX {store EDX}
- DB 66h; POP DX {MOV EDX,[W4:W3]}
- MOV AX,[WW2]; PUSH AX; MOV AX,[WW1]; PUSH AX {store EDI}
- DB 66h; POP DI {MOV EDI,[W2:W1]}
- MOV AX,1 {function 0001h}
- End;
- a_Procedure; {do the CPL0 access}
- Asm
- DB 66h; PUSH AX; {MOV [W2:W1],EAX}
- POP AX; MOV [WW1],AX; POP AX; MOV [WW2],AX; {return EAX}
- DB 66h; PUSH DX; {MOV [W4:W3],EDX}
- POP AX; MOV [WW3],AX; POP AX; MOV [WW4],AX; {return EDX}
- End;
- End;
- W4:=WW4; W3:=WW3; W2:=WW2; W1:=WW1; {return values}
- End;
-
- { The following part of this unit will be executed on start up of a program, }
- { which includes this unit. It checks for the installed and active STAT.386, }
- { and it modifies the variable a_Procedure, so that this procedure points to }
- { the VxD entry point. }
- { Attention! Do include this check for the installed STAT.386 into your code }
- { again, before you call one of the VxD functions. }
-
- Begin {init}
- Entry_VxD:=Check_VxD; {get VxD entry}
- If Entry_VxD<>NIL Then Begin {if VxD is installed}
- Seg(a_Procedure):=MemW[Seg(Entry_VxD):Ofs(Entry_VxD)+2]; {point to entry}
- Ofs(a_Procedure):=MemW[Seg(Entry_VxD):Ofs(Entry_VxD)+0]; {point to entry}
- End;
- End.
- ------------------------------------------------------------------------------
-
- *** END OF FILE ***
-