windows-nt/Source/XPSP1/NT/base/ntos/ke/i386/instemul.asm
2020-09-26 16:20:57 +08:00

2994 lines
78 KiB
NASM

title "Vdm Instuction Emulation"
;++
;
; Copyright (c) 1989 Microsoft Corporation
;
; Module Name:
;
; instemul.asm
;
; Abstract:
;
; This module contains the routines for emulating instructions and
; faults to a VDM.
;
; Author:
;
; Dave Hastings (daveh) 29-March-1991
;
; Environment:
;
; Kernel mode only.
;
; Notes:
;
;
;sudeepb 09-Dec-1992 Very Sonn this file will be deleted and protected
; mode instruction emulation will be merged in
; emv86.asm. Particularly following routines will
; simply become OpcodeInvalid.
; OpcodeIret
; OpcodePushf
; OpcodePopf
; OpcodeHlt
; Other routines such as
; OpcodeCli
; OpcodeSti
; OpcodeIN/OUT/SB/Immb etc
; will map exactly like emv86.asm
; OpcodeInt will be the main differeing routine.
;
; OpcodeDispatch Table will be deleted.
;
; So before making any major changes in this file please see
; Sudeepb or Daveh.
;
;neilsa 19-Oct-1993 Size and performance enhancements
;jonle 15-Nov-1993 - The Debug messages for each opcode may no longer work
; correctly, because interrupts may not have been enabled
;
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Revision History:
;
;--
.386p
.xlist
include ks386.inc
include i386\kimacro.inc
include mac386.inc
include i386\mi.inc
include callconv.inc
include ..\..\vdm\i386\vdm.inc
include vdmtib.inc
.list
extrn VdmOpcode0f:proc
extrn OpcodeNPXV86:proc
extrn VdmDispatchIntAck:proc ;; only OpcodeSti uses this
ifdef VDMDBG
EXTRNP _VdmTraceEvent,4
endif
extrn CommonDispatchException:proc ;; trap.asm
extrn _DbgPrint:proc
extrn _KeI386VdmIoplAllowed:dword
extrn _KeI386VirtualIntExtensions:dword
extrn _MmHighestUserAddress:dword
EXTRNP _Ki386GetSelectorParameters,4
EXTRNP _Ki386VdmDispatchIo,5
EXTRNP _Ki386VdmDispatchStringIo,8
EXTRNP _KiDispatchException,5
EXTRNP _VdmPrinterStatus,3
EXTRNP KfLowerIrql,1,IMPORT, FASTCALL
EXTRNP _VdmPrinterWriteData, 3
EXTRNP _VdmClearPMCliTimeStamp, 0
EXTRNP _VdmSetPMCliTimeStamp, 1
extrn _MmUserProbeAddress:DWORD
EXTRNP _VdmFetchULONG,1
page ,132
ifdef VDMDBG
%out Debugging version
endif
;
; Force assume into place
;
_PAGE SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
_PAGE ENDS
_TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING
_TEXT$00 ENDS
PAGECONST SEGMENT DWORD PUBLIC 'DATA'
;
; Instruction emulation emulates the following instructions.
; The emulation affects the noted user mode registers.
;
; In protected mode, the following instructions are emulated in the kernel
;
; Registers (E)Flags (E)SP SS CS
; INTnn X X X X
; INTO X X X X
; CLI X
; STI X
;
; The following instructions are always emulated by reflection to the
; Usermode VDM monitor
;
; INSB
; INSW
; OUTSB
; OUTSW
; INBimm
; INWimm
; OUTBimm
; OUTWimm
; INB
; INW
; OUTB
; OUTW
;
; WARNING What do we do about 32 bit io instructions??
;
; OpcodeIndex - packed 1st level table to index OpcodeDispatch table
;
public OpcodeIndex
diBEGIN OpcodeIndex,VDM_INDEX_Invalid
dtI 0fh, VDM_INDEX_0F
dtI 26h, VDM_INDEX_ESPrefix
dtI 2eh, VDM_INDEX_CSPrefix
dtI 36h, VDM_INDEX_SSPrefix
dtI 3eh, VDM_INDEX_DSPrefix
dtI 64h, VDM_INDEX_FSPrefix
dtI 65h, VDM_INDEX_GSPrefix
dtI 66h, VDM_INDEX_OPER32Prefix
dtI 67h, VDM_INDEX_ADDR32Prefix
dtI 6ch, VDM_INDEX_INSB
dtI 6dh, VDM_INDEX_INSW
dtI 6eh, VDM_INDEX_OUTSB
dtI 6fh, VDM_INDEX_OUTSW
dtI 9bh, VDM_INDEX_NPX
dtI 9ch, VDM_INDEX_PUSHF
dtI 9dh, VDM_INDEX_POPF
dtI 0cdh, VDM_INDEX_INTnn
dtI 0ceh, VDM_INDEX_INTO
dtI 0cfh, VDM_INDEX_IRET
dtI 0d8h, VDM_INDEX_NPX
dtI 0d9h, VDM_INDEX_NPX
dtI 0dah, VDM_INDEX_NPX
dtI 0dbh, VDM_INDEX_NPX
dtI 0dch, VDM_INDEX_NPX
dtI 0ddh, VDM_INDEX_NPX
dtI 0deh, VDM_INDEX_NPX
dtI 0dfh, VDM_INDEX_NPX
dtI 0e4h, VDM_INDEX_INBimm
dtI 0e5h, VDM_INDEX_INWimm
dtI 0e6h, VDM_INDEX_OUTBimm
dtI 0e7h, VDM_INDEX_OUTWimm
dtI 0ech, VDM_INDEX_INB
dtI 0edh, VDM_INDEX_INW
dtI 0eeh, VDM_INDEX_OUTB
dtI 0efh, VDM_INDEX_OUTW
dtI 0f0h, VDM_INDEX_LOCKPrefix
dtI 0f2h, VDM_INDEX_REPNEPrefix
dtI 0f3h, VDM_INDEX_REPPrefix
dtI 0f4h, VDM_INDEX_HLT
dtI 0fah, VDM_INDEX_CLI
dtI 0fbh, VDM_INDEX_STI
diEND NUM_OPCODE
;
; OpcodeDispatch - table of routines used to emulate instructions
;
public OpcodeDispatch
dtBEGIN OpcodeDispatch,OpcodeInvalid
dtS VDM_INDEX_0F , Opcode0F
dtS VDM_INDEX_ESPrefix , OpcodeESPrefix
dtS VDM_INDEX_CSPrefix , OpcodeCSPrefix
dtS VDM_INDEX_SSPrefix , OpcodeSSPrefix
dtS VDM_INDEX_DSPrefix , OpcodeDSPrefix
dtS VDM_INDEX_FSPrefix , OpcodeFSPrefix
dtS VDM_INDEX_GSPrefix , OpcodeGSPrefix
dtS VDM_INDEX_OPER32Prefix, OpcodeOPER32Prefix
dtS VDM_INDEX_ADDR32Prefix, OpcodeADDR32Prefix
dtS VDM_INDEX_INSB , OpcodeINSB
dtS VDM_INDEX_INSW , OpcodeINSW
dtS VDM_INDEX_OUTSB , OpcodeOUTSB
dtS VDM_INDEX_OUTSW , OpcodeOUTSW
dtS VDM_INDEX_INTnn , OpcodeINTnn
dtS VDM_INDEX_INTO , OpcodeINTO
dtS VDM_INDEX_INBimm , OpcodeINBimm
dtS VDM_INDEX_INWimm , OpcodeINWimm
dtS VDM_INDEX_OUTBimm , OpcodeOUTBimm
dtS VDM_INDEX_OUTWimm , OpcodeOUTWimm
dtS VDM_INDEX_INB , OpcodeINB
dtS VDM_INDEX_INW , OpcodeINW
dtS VDM_INDEX_OUTB , OpcodeOUTB
dtS VDM_INDEX_OUTW , OpcodeOUTW
dtS VDM_INDEX_LOCKPrefix , OpcodeLOCKPrefix
dtS VDM_INDEX_REPNEPrefix , OpcodeREPNEPrefix
dtS VDM_INDEX_REPPrefix , OpcodeREPPrefix
dtS VDM_INDEX_CLI , OpcodeCLI
dtS VDM_INDEX_STI , OpcodeSTI
dtEND MAX_VDM_INDEX
PAGECONST ENDS
PAGEDATA SEGMENT DWORD PUBLIC 'DATA'
public _ExVdmOpcodeDispatchCounts,_ExVdmSegmentNotPresent
_ExVdmOpcodeDispatchCounts dd MAX_VDM_INDEX dup(0)
_ExVdmSegmentNotPresent dd 0
PAGEDATA ENDS
_PAGE SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
page ,132
subttl "Overide Prefix Macro"
;++
;
; Routine Description:
;
; This macro generates the code for handling override prefixes
; The routine name generated is OpcodeXXXXPrefix, where XXXX is
; the name used in the macro invocation. The code will set the
; PREFIX_XXXX bit in the Prefix flags.
;
; Arguments
; name = name of prefix
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns
; user mode Eip advanced
; eax advanced
; edx contains next byte of opcode
;
; NOTE: This routine exits by dispatching through the table again.
;--
opPrefix macro name
public Opcode&name&Prefix
Opcode&name&Prefix proc
or [esi].RiPrefixFlags,PREFIX_&name
jmp OpcodeGenericPrefix ; dispatch to next handler
Opcode&name&Prefix endp
endm
irp prefix, <ES, CS, SS, DS, FS, GS, OPER32, ADDR32, LOCK, REPNE, REP>
opPrefix prefix
endm
page ,132
subttl "Instruction Emulation Dispatcher"
;++
;
; Routine Description:
;
; This routine dispatches to the opcode specific emulation routine,
; based on the first byte of the opcode. Two byte opcodes, and prefixes
; result in another level of dispatching, from the handling routine.
;
; Arguments:
;
; ebp = pointer to trap frame
;
; Returns:
;
; Nothing
;
;
cPublicProc _Ki386DispatchOpcode,0
sub esp,REGINFOSIZE
mov esi, esp ; scratch area
CsToLinearPM [ebp].TsSegCs, doerr ; initialize reginfo
mov edi,[ebp].TsEip ; get fault instruction address
cmp edi,[esi].RiCsLimit ; check eip
ja doerr
add edi,[esi].RiCsBase
cmp edi, [_MmHighestUserAddress]
ja doerr
movzx ecx,byte ptr [edi] ; get faulting opcode
mov eax,ecx
and eax,0F8h ; check for npx instr
cmp eax,0D8h
je do30 ; dispatch
movzx eax, OpcodeIndex[ecx]
mov ebx,1 ; length count, flags
; All handler routines will get the following on entry
; ebp -> trap frame
; ebx -> prefix flags, instruction length count
; ecx -> byte at the faulting address
; edx -> pointer to vdm state in DOS arena
; interrupts enabled and Irql at APC level
; edi -> address of faulting instruction
; esi -> reginfo struct
; All handler routines will return
; EAX = 0 for failure
; EAX = 1 for success
if DEVL
inc _ExVdmOpcodeDispatchCounts[eax * type _ExVdmOpcodeDispatchCounts]
endif
ifdef VDMDBG
pushad
stdCall _VdmTraceEvent, <VDMTR_KERNEL_OP_PM,ecx,0,ebp>
popad
endif
call OpcodeDispatch[eax * type OpcodeDispatch]
do20:
add esp,REGINFOSIZE
stdRET _Ki386DispatchOpcode
doerr: xor eax,eax
jmp do20
;
; If we get here, we have executed an NPX instruction in user mode
; with the emulator installed. If the EM bit was not set in CR0, the
; app really wanted to execute the instruction for detection purposes.
; In this case, we need to clear the TS bit, and restart the instruction.
; Otherwise we need to reflect the exception
;
do30:
call OpcodeNPXV86
jmp short do20
stdENDP _Ki386DispatchOpcode
page ,132
subttl "Invalid Opcode Handler"
;++
;
; Routine Description:
;
; This routine causes a GP fault to be reflected to the vdm
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeInvalid
OpcodeInvalid proc
xor eax,eax ; ret fail
ret
OpcodeInvalid endp
page ,132
subttl "Generic Prefix Handler"
;++
;
; Routine Description:
;
; This routine handles the generic portion of all of the prefixes,
; and dispatches the next byte of the opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; user mode Eip advanced
; edx contains next byte of opcode
;
public OpcodeGenericPrefix
OpcodeGenericPrefix proc
inc edi ; increment eip
inc ebx ; increment size
cmp bl, 128 ; set arbitrary inst size limit
ja ogperr ; in case of pointless prefixes
mov eax,edi ; current linear address
sub eax,[esi].RiCsBase ; make address eip
cmp eax,[esi].RiCsLimit ; check eip
ja ogperr
cmp edi, [_MmHighestUserAddress]
ja ogperr
mov cl,byte ptr [edi] ; get next opcode
movzx eax, OpcodeIndex[ecx]
if DEVL
inc _ExVdmOpcodeDispatchCounts[eax * type _ExVdmOpcodeDispatchCounts]
endif
jmp OpcodeDispatch[eax * type OpcodeDispatch]
ogperr:
xor eax,eax ; opcode was NOT handled
ret
OpcodeGenericPrefix endp
page ,132
subttl "0F Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates a 0Fh opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public Opcode0F
Opcode0F proc
mov eax,[ebp].TsEip ; get fault instruction address
mov [esi].RiEip,eax
mov [esi].RiTrapFrame,ebp
mov [esi].RiPrefixFlags,ebx
mov eax,dword ptr [ebp].TsEFlags
mov [esi].RiEFlags,eax
call VdmOpcode0F ; enables interrupts
test eax,0FFFFh
jz o0f20
mov eax,[esi].RiEip
mov [ebp].TsEip,eax
mov eax,1
o0f20:
ret
Opcode0F endp
page ,132
subttl "Byte string in Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an INSB opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
; WARNING what to do about size override? ds override?
public OpcodeINSB
OpcodeINSB proc
push ebp ; Trap Frame
push ebx ; size of insb
movzx eax,word ptr [ebp].TsSegEs
shl eax,16
; WARNING no support for 32bit edi
mov ax,word ptr [ebp].TsEdi ; don't support 32bit'ness
push eax ; address
xor eax, eax
mov ecx,1
test ebx,PREFIX_REP
jz @f
mov eax, 1
; WARNING no support for 32bit ecx
movzx ecx,word ptr [ebp].TsEcx
@@:
push ecx ; number of io ops
push TRUE ; read op
push eax ; REP prefix
push 1 ; byte op
movzx edx,word ptr [ebp].TsEdx
push edx ; port number
call _Ki386VdmDispatchStringIo@32 ; use retval
ret
OpcodeINSB endp
page ,132
subttl "Word String In Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an INSW opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeINSW
OpcodeINSW proc
push ebp ; Trap frame
push ebx ; sizeof insw
movzx eax,word ptr [ebp].TsSegEs
shl eax,16
; WARNING no support for 32bit edi
mov ax,word ptr [ebp].TsEdi
push eax ; address
xor eax, eax
mov ecx,1
test ebx,PREFIX_REP
jz @f
mov eax, 1
; WARNING no support for 32bit ecx
movzx ecx,word ptr [ebp].TsEcx
@@:
movzx edx,word ptr [ebp].TsEdx
push ecx ; number of io ops
push TRUE ; read op
push eax ; REP prefix
push 2 ; word size
push edx ; port number
call _Ki386VdmDispatchStringIo@32 ; use retval
ret
OpcodeINSW endp
page ,132
subttl "Byte String Out Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an OUTSB opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeOUTSB
OpcodeOUTSB proc
push ebp ; Trap Frame
push ebx ; size of outsb
movzx eax,word ptr [ebp].TsSegDs
shl eax,16
; WARNING don't support 32bit'ness, esi
mov ax,word ptr [ebp].TsEsi
push eax ; address
xor eax, eax
mov ecx,1
test ebx,PREFIX_REP
jz @f
mov eax, 1
; WARNING don't support 32bit'ness ecx
movzx ecx,word ptr [ebp].TsEcx
@@:
movzx edx,word ptr [ebp].TsEdx
push ecx ; number of io ops
push FALSE ; write op
push eax ; REP prefix
push 1 ; byte op
push edx ; port number
call _Ki386VdmDispatchStringIo@32 ; use retval
ret
OpcodeOUTSB endp
page ,132
subttl "Word String Out Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an OUTSW opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeOUTSW
OpcodeOUTSW proc
push ebp ; Trap Frame
push ebx ; size of outsb
movzx eax,word ptr [ebp].TsSegDs
shl eax,16
; WARNING don't support 32bit'ness esi
mov ax,word ptr [ebp].TsEsi
push eax ; address
xor eax, eax
mov ecx,1
test ebx,PREFIX_REP
jz @f
mov eax, 1
; WARNING don't support 32bit'ness ecx
movzx ecx,word ptr [ebp].TsEcx
@@:
movzx edx,word ptr [ebp].TsEdx
push ecx ; number of io ops
push FALSE ; write op
push eax ; REP prefix
push 2 ; byte op
push edx ; port number
call _Ki386VdmDispatchStringIo@32 ; use retval
ret
OpcodeOUTSW endp
page ,132
subttl "INTnn Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an INTnn opcode. It retrieves the handler
; from the IVT, pushes the current cs:ip and flags on the stack,
; and dispatches to the handler.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; Current CS:IP on user stack
; RiCs:RiEip -> handler from IVT
;
public OpcodeINTnn
OpcodeINTnn proc
mov eax, ds:FIXED_NTVDMSTATE_LINEAR
and eax, (VDM_INTERRUPT_PENDING + VDM_VIRTUAL_INTERRUPTS)
cmp eax, (VDM_INTERRUPT_PENDING + VDM_VIRTUAL_INTERRUPTS)
jnz short oi10
call VdmDispatchIntAck
jmp short oi99
oi10:
mov eax,dword ptr [ebp].TsEFlags
call GetVirtualBits ; set interrupt flag
mov [esi].RiEFlags,eax
movzx eax,word ptr [ebp].TsHardwareSegSs
call SsToLinear
test al,0FFh
jz oinerr
inc edi ; point to int #
mov eax,edi ; current linear address
sub eax,[esi].RiCsBase ; make address eip
cmp eax,[esi].RiCsLimit ; check eip
ja oinerr
cmp edi, [_MmHighestUserAddress]
ja oinerr
movzx ecx,byte ptr [edi] ; get int #
inc eax ; inc past end of instruction
mov [esi].RiEip,eax ; save for pushint's benefit
call PushInt ; will return retcode in al
test al,0FFh
jz oinerr ; error!
mov eax,[esi].RiEsp
mov [ebp].TsHardwareEsp,eax
mov ax,word ptr [esi].RiSegCs
or ax, 7 ; R3 LDT selectors only
mov word ptr [ebp].TsSegCs,ax
mov eax,[esi].RiEFlags
mov [ebp].TsEFlags,eax
mov eax,[esi].RiEip
mov [ebp].TsEip,eax
oi99:
mov eax,1
ret
oinerr:
xor eax,eax
ret
OpcodeINTnn endp
page ,132
subttl "INTO Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an INTO opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeINTO
OpcodeINTO proc
xor eax,eax
ret
OpcodeINTO endp
page ,132
subttl "In Byte Immediate Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an in byte immediate opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeINBimm
OpcodeINBimm proc
inc ebx ; length count
inc edi
mov eax,edi ; current linear address
sub eax,[esi].RiCsBase ; make address eip
cmp eax,[esi].RiCsLimit ; check eip
ja oibi20
cmp edi, [_MmHighestUserAddress]
ja oibi20
movzx ecx,byte ptr [edi]
; (eax) = inst. size
; read op
; I/O size = 1
; (ecx) = port number
stdCall _Ki386VdmDispatchIo, <ecx, 1, TRUE, ebx, ebp>
ret
oibi20:
xor eax, eax ; not handled
ret
OpcodeINBimm endp
page ,132
subttl "Word In Immediate Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an in word immediate opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeINWimm
OpcodeINWimm proc
inc ebx ; length count
inc edi
mov eax,edi ; current linear address
sub eax,[esi].RiCsBase ; make address eip
cmp eax,[esi].RiCsLimit ; check eip
ja oiwi20
cmp edi, [_MmHighestUserAddress]
ja oiwi20
movzx ecx,byte ptr [edi]
; TRUE - read op
; 2 - word op
; ecx - port number
stdCall _Ki386VdmDispatchIo, <ecx, 2, TRUE, ebx, ebp>
ret
oiwi20:
xor eax, eax ; not handled
ret
OpcodeINWimm endp
page ,132
subttl "Out Byte Immediate Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an invalid opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeOUTBimm
OpcodeOUTBimm proc
inc ebx ; length count
inc edi
mov eax,edi ; current linear address
sub eax,[esi].RiCsBase ; make address eip
cmp eax,[esi].RiCsLimit ; check eip
ja oobi20
cmp edi, [_MmHighestUserAddress]
ja oobi20
movzx ecx,byte ptr [edi]
; FALSE - write op
; 1 - byte op
; ecx - port #
stdCall _Ki386VdmDispatchIo, <ecx, 1, FALSE, ebx, ebp>
ret
oobi20:
xor eax, eax ; not handled
ret
OpcodeOUTBimm endp
page ,132
subttl "Out Word Immediate Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an out word immediate opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeOUTWimm
OpcodeOUTWimm proc
inc ebx ; length count
inc edi
mov eax,edi ; current linear address
sub eax,[esi].RiCsBase ; make address eip
cmp eax,[esi].RiCsLimit ; check eip
ja oowi20
cmp edi, [_MmHighestUserAddress]
ja oowi20
movzx ecx,byte ptr [edi]
; FALSE - write op
; 2 - word op
; ecx - port number
stdCall _Ki386VdmDispatchIo, <ecx, 2, FALSE, ebx, ebp>
ret
oowi20:
xor eax, eax ; not handled
ret
OpcodeOUTWimm endp
page ,132
subttl "INB Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an INB opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeINB
OpcodeINB proc
movzx eax,word ptr [ebp].TsEdx
; TRUE - read op
; 1 - byte op
; eax - port number
cmp eax, 3bdh
jz oib_prt1
cmp eax, 379h
jz oib_prt1
cmp eax, 279h
jz oib_prt1
oib_reflect:
stdCall _Ki386VdmDispatchIo, <eax, 1, TRUE, ebx, ebp>
ret
oib_prt1:
; call printer status routine with port number, size, trap frame
movzx ebx, bl ;clear prefix flags
push eax
stdCall _VdmPrinterStatus, <eax, ebx, ebp>
or al,al
pop eax
jz short oib_reflect
mov al, 1
ret
OpcodeINB endp
page ,132
subttl "INW Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an INW opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeINW
OpcodeINW proc
movzx eax,word ptr [ebp].TsEdx
; TRUE - read operation
; 2 - word op
; eax - port number
stdCall _Ki386VdmDispatchIo, <eax, 2, TRUE, ebx, ebp>
ret
OpcodeINW endp
page ,132
subttl "OUTB Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an OUTB opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeOUTB
OpcodeOUTB proc
movzx eax,word ptr [ebp].TsEdx
cmp eax, 03BCh
je short oob_printerVDD
cmp eax, 0378h
je short oob_printerVDD
cmp eax, 0278h
jz short oob_printerVDD
oob_reflect:
; FALSE - write op
; 1 - byte op
; eax - port number
stdCall _Ki386VdmDispatchIo, <eax, 1, FALSE, ebx, ebp>
ret
oob_printerVDD:
movzx ebx, bl ; instruction size
push eax ; save port address
stdCall _VdmPrinterWriteData, <eax, ebx, ebp>
or al,al ;
pop eax
jz short oob_reflect
mov al, 1
ret
OpcodeOUTB endp
page ,132
subttl "OUTW Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an OUTW opcode.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeOUTW
OpcodeOUTW proc
movzx eax,word ptr [ebp].TsEdx
; FALSE - write op
; 2 - word op
; edi - port #
stdCall _Ki386VdmDispatchIo, <eax, 2, FALSE, ebx, ebp>
ret
OpcodeOUTW endp
page ,132
subttl "CLI Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an CLI opcode. It clears the virtual
; interrupt flag in the VdmTeb.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeCLI
OpcodeCLI proc
mov eax, ds:FIXED_NTVDMSTATE_LINEAR
and eax, (VDM_INTERRUPT_PENDING + VDM_VIRTUAL_INTERRUPTS)
cmp eax, (VDM_INTERRUPT_PENDING + VDM_VIRTUAL_INTERRUPTS)
jnz short oc50
call VdmDispatchIntAck
jmp short oc99
oc50:
mov eax,[ebp].TsEFlags
and eax,NOT EFLAGS_INTERRUPT_MASK
call SetVirtualBits
inc dword ptr [ebp].TsEip
stdCall _VdmSetPMCliTimeStamp, <0>
oc99:
mov eax,1
ret
OpcodeCLI endp
page ,132
subttl "STI Opcode Handler"
;++
;
; Routine Description:
;
; This routine emulates an STI opcode. It sets the virtual
; interrupt flag in the VDM teb.
;
; Arguments:
; EBP -> trap frame
; EBX -> prefix flags, BL = instruction length count
; ECX -> byte at the faulting address
; EDX -> pointer to vdm state in DOS arena
; ESI -> Reginfo struct
; EDI -> address of faulting instruction
;
; Returns:
;
; nothing
;
public OpcodeSTI
OpcodeSTI proc
stdCall _VdmClearPMCliTimeStamp
mov eax,[ebp].TsEFlags
or eax,EFLAGS_INTERRUPT_MASK
call SetVirtualBits
inc dword ptr [ebp].TsEip
mov eax, ds:FIXED_NTVDMSTATE_LINEAR
test eax,VDM_INTERRUPT_PENDING
jz os10
call VdmDispatchIntAck
os10:
mov eax,1
ret
OpcodeSTI endp
page ,132
subttl "Check Vdm Flags"
;++
;
; Routine Description:
;
; This routine checks the flags that are going to be used for the
; dos or windows application.
;
; Arguments:
;
; ecx = EFlags to be set
; esi = address of reg info
;
; Returns:
;
; ecx = fixed flags
;
public CheckVdmFlags
CheckVdmFlags proc
push eax
mov eax,[esi].RiEFlags
and eax,EFLAGS_V86_MASK
test _KeI386VdmIoplAllowed,1
jnz cvf30
test _KeI386VirtualIntExtensions, V86_VIRTUAL_INT_EXTENSIONS OR PM_VIRTUAL_INT_EXTENSIONS
jnz cvf40
cvf10: or ecx,EFLAGS_INTERRUPT_MASK
cvf20: and ecx,NOT (EFLAGS_IOPL_MASK OR EFLAGS_NT_MASK OR EFLAGS_V86_MASK OR EFLAGS_VIF OR EFLAGS_VIP)
or ecx,eax ; restore original v86 bit
pop eax
ret
cvf30: test eax,EFLAGS_V86_MASK
jz cvf10
jmp cvf20
cvf40: test eax,EFLAGS_V86_MASK
jz cvf60
test _KeI386VirtualIntExtensions,V86_VIRTUAL_INT_EXTENSIONS
jz cvf10
cvf50: push eax
mov eax,ecx
and eax,EFLAGS_INTERRUPT_MASK
shl eax,0ah
pop eax
jmp cvf10
cvf60: test _KeI386VirtualIntExtensions,PM_VIRTUAL_INT_EXTENSIONS
jz cvf10
jmp cvf50
CheckVdmFlags endp
page ,132
subttl "Get Virtual Interrupt Flag"
;++
;
; Routine Description:
;
; This routine correctly gets the VDMs virtual interrupt flag and
; puts it into an EFlags image to be put on the stack.
;
; Arguments:
;
; eax = EFlags value
;
; Returns:
;
; eax = EFlags value with correct setting for IF
;
; Uses:
; ecx
;
public GetVirtualBits
GetVirtualBits proc
push ebp
push edx
push ebx
push esi
push edi
test _KeI386VdmIoplAllowed,1
jnz gvb60
test _KeI386VirtualIntExtensions, V86_VIRTUAL_INT_EXTENSIONS OR PM_VIRTUAL_INT_EXTENSIONS
jnz gvb30
gvb10: and eax,NOT EFLAGS_INTERRUPT_MASK
call gvbGetFixedStateLinear
and ecx,VDM_VIRTUAL_INTERRUPTS OR VDM_VIRTUAL_AC
or eax,ecx ; put virtual int flag into flags
or eax,EFLAGS_IOPL_MASK ; make it look like a 386
gbvexit:
pop edi
pop esi
pop ebx
pop edx
pop ebp
ret
gvb30: test eax, EFLAGS_V86_MASK
jz gvb50
test _KeI386VirtualIntExtensions, V86_VIRTUAL_INT_EXTENSIONS
jz gvb10
gvb40: mov ecx,eax
and ecx,EFLAGS_VIF
shr ecx,0ah ; mov vif to if posn
and eax,NOT EFLAGS_INTERRUPT_MASK
or eax,ecx
call gvbGetFixedStateLinear
and ecx,VDM_VIRTUAL_AC
and eax,NOT EFLAGS_ALIGN_CHECK
or eax,ecx
or eax,EFLAGS_IOPL_MASK
jmp gbvexit
gvb50: test _KeI386VirtualIntExtensions, PM_VIRTUAL_INT_EXTENSIONS
jz gvb10
jmp gvb40
gvb60: test eax,EFLAGS_V86_MASK
jz gvb10
call gvbGetFixedStateLinear
and ecx,VDM_VIRTUAL_AC
and eax,NOT EFLAGS_ALIGN_CHECK
or eax,ecx
or eax,EFLAGS_IOPL_MASK
jmp gbvexit
gvbGetFixedStateLinear:
push esp ; Pass current Esp to handler
push offset GetVirtualBits_Handler
push PCR[PcExceptionList]
mov PCR[PcExceptionList], esp
mov ecx, ds:FIXED_NTVDMSTATE_LINEAR
gvbexit1:
pop PCR[PcExceptionList]
add esp, 8 ; pop out except handler
ret
GetVirtualBits_Handler:
mov esp, [esp+8] ; (esp)-> ExceptionList
xor ecx, ecx
jmp gvbexit1
GetVirtualBits endp
page ,132
subttl "Set Virtual Interrupt Flag"
;++
;
; Routine Description:
;
; This routine correctly sets the VDMs virtual interrupt flag.
;
; Arguments:
;
; eax = EFlags value
;
; Returns:
;
; Virtual interrupt flag set
;
public SetVirtualBits
SetVirtualBits proc
Flags equ [ebp - 4]
push ebp
push edx
push ebx
push esi
push edi
push esp ; Pass current Esp to handler
push offset SetVirtualBits_Handler
push PCR[PcExceptionList]
mov PCR[PcExceptionList], esp
mov ebp,esp
sub esp,4
mov Flags,eax
lea edx,ds:FIXED_NTVDMSTATE_LINEAR
and eax,EFLAGS_INTERRUPT_MASK ; isolate int flag
MPLOCK and [edx],NOT VDM_VIRTUAL_INTERRUPTS
MPLOCK or [edx],eax ; place virtual int flag value
test _KeI386VirtualIntExtensions, V86_VIRTUAL_INT_EXTENSIONS OR PM_VIRTUAL_INT_EXTENSIONS
jnz svb40
svb20:
; WARNING 32 bit support!
test ebx,PREFIX_OPER32
jz svb30 ; 16 bit instr
mov eax,Flags
and eax,EFLAGS_ALIGN_CHECK
MPLOCK and dword ptr [edx],NOT EFLAGS_ALIGN_CHECK
MPLOCK or [edx],eax
svb30:
mov esp,ebp
svbexit:
pop PCR[PcExceptionList] ; Remove handler
lea esp, [esp+8]
pop edi
pop esi
pop ebx
pop edx
pop ebp
ret
svb40: test Flags,dword ptr EFLAGS_V86_MASK
jz svb60
test _KeI386VirtualIntExtensions,V86_VIRTUAL_INT_EXTENSIONS
jz svb20
svb50: shl eax,0ah
jmp svb20
svb60: test _KeI386VirtualIntExtensions,PM_VIRTUAL_INT_EXTENSIONS
jz svb20
jmp svb50
SetVirtualBits_Handler:
mov esp, [esp+8] ; (esp)-> ExceptionList
jmp svbexit
SetVirtualBits endp
page ,132
subttl "Reflect Exception to a Vdm"
;++
;
; Routine Description:
;
; This routine reflects an exception to a VDM. It uses the information
; in the trap frame to determine what exception to reflect, and updates
; the trap frame with the new CS, EIP, SS, and SP values
;
; Arguments:
;
; ebp -> Trap frame
; ss:esp + 4 = trap number
;
; Returns
;
; Nothing
;
; Notes:
; Interrupts are enabled upon entry, Irql is at APC level
; This routine may not preserve all of the non-volatile registers if
; a fault occurs.
;
cPublicProc _Ki386VdmReflectException,1
RI equ [ebp - REGINFOSIZE]
;
; First make sure this is for us to handle
;
mov eax,PCR[PcPrcbData+PbCurrentThread]
mov eax,[eax]+ThApcState+AsProcess
cmp dword ptr [eax]+PrVdmObjects,0 ; is this a vdm process?
jne short @f
xor eax, eax ; not handled
ret
@@:
push ebp
mov ebp,esp
sub esp,REGINFOSIZE
pushad
lea esi,ds:FIXED_NTVDMSTATE_LINEAR
;
; Look to see if the debugger wants exceptions
;
stdCall _VdmFetchULONG, <esi>
test eax,VDM_BREAK_EXCEPTIONS
jz vredbg ; no, check for debug events
mov ebx,DBG_STACKFAULT
cmp word ptr [ebp + 8],0ch ; stack fault?
jz @f ; yes, check dbg flag
mov ebx,DBG_GPFAULT
cmp word ptr [ebp + 8],0dh ; gp fault?
jne vredbg ; no, continue
@@:
test eax,VDM_USE_DBG_VDMEVENT
jnz vrexc_event
jmp vrexcd ; reflect the exception to 32
;
; Look to see if the debugger wants debug events
;
vredbg:
test eax,VDM_BREAK_DEBUGGER
jz vrevdm ; no debug events, reflect to vdm
mov ebx,DBG_SINGLESTEP
cmp word ptr [ebp + 8],1
jnz @f
test eax,VDM_USE_DBG_VDMEVENT
jnz vrexc_event
jmp vrexc1
@@:
mov ebx,DBG_BREAK
cmp word ptr [ebp + 8],3
jnz vrevdm
test eax,VDM_USE_DBG_VDMEVENT
jnz vrexc_event
jmp vrexc3
;
; Reflect the exception to the VDM
;
vrevdm:
mov esi,[ebp]
cmp word ptr [esi].TsSegCs, KGDT_R3_CODE OR RPL_MASK ; int sim after fault?
je vre28
if DEVL
cmp word ptr [ebp + 8],11
jne @f
inc _ExVdmSegmentNotPresent
@@:
endif
mov RI.RiTrapFrame,esi
mov eax,[esi].TsHardwareSegSs
mov RI.RiSegSs,eax
mov eax,[esi].TsHardwareEsp
mov RI.RiEsp,eax
mov eax,[esi].TsEFlags
mov RI.RiEFlags,eax
mov eax,[esi].TsEip
mov RI.RiEip,eax
mov eax,[esi].TsSegCs
mov RI.RiSegCs,eax
lea esi,RI
call CsToLinear ; uses eax as selector
test al,0FFh
jz vrerr
mov eax,[esi].RiSegSs
call SsToLinear
test al,0FFh
jz vrerr
mov ecx,[ebp + 8]
call PushException
test al,0FFh
jz vrerr
mov esi,RI.RiTrapFrame
mov eax,RI.RiEsp
mov [esi].TsHardwareEsp,eax
xor bl, bl ; R3 mask. 0 on V86 mode
test dword ptr [esi].TsEFlags, EFLAGS_V86_MASK ;
jnz @F ;
mov bl, 7 ; protected mode, R3 LDT selectors only
@@:
mov eax,RI.RiSegSs
or al, bl
mov [esi].TsHardwareSegSs,eax
mov eax,RI.RiEFlags
mov [esi].TsEFlags,eax
mov eax,RI.RiSegCs
or al, bl
mov [esi].TsSegCs,eax
mov eax,RI.RiEip
mov [esi].TsEip,eax
cmp word ptr [ebp + 8],1
jne vre28
and dword ptr [esi].TsEFlags, NOT EFLAGS_TF_MASK
vre28:
popad
mov eax,1 ; handled
vre30:
mov esp,ebp
pop ebp
stdRET _Ki386VdmReflectException
vrerr:
popad
xor eax,eax
jmp vre30
vrexc1:
mov eax, [ebp]
and dword ptr [eax]+TsEflags, not EFLAGS_TF_MASK
mov eax, [ebp]+TsEip ; (eax)-> faulting instruction
stdCall _VdmDispatchException <[ebp],STATUS_SINGLE_STEP,eax,0,0,0,0>
jmp vre28
vrexc3:
mov eax,BREAKPOINT_BREAK
mov ebx, [ebp]
mov ebx, [ebx]+TsEip
dec ebx ; (eax)-> int3 instruction
stdCall _VdmDispatchException <[ebp],STATUS_BREAKPOINT,ebx,3,eax,ecx,edx>
jmp vre28
vrexcd:
mov eax, [ebp]
mov eax, [eax]+TsEip
stdCall _VdmDispatchException <[ebp],STATUS_ACCESS_VIOLATION,eax,2,0,-1,0>
jmp vre28
vrexc_event:
mov eax, [ebp]
cmp ebx, DBG_SINGLESTEP
jnz vrexc_event2
and dword ptr [eax]+TsEflags, not EFLAGS_TF_MASK
vrexc_event2:
mov eax, [eax]+TsEip
stdCall _VdmDispatchException <[ebp],STATUS_VDM_EVENT,eax,1,ebx,0,0>
jmp vre28
stdENDP _Ki386VdmReflectException
page ,132
subttl "Reflect Segment Not Present Exception to a Vdm"
;++
;
; Routine Description:
;
; This routine reflects an TRAP B to a VDM. It uses the information
; in the trap frame to determine what exception to reflect, and updates
; the trap frame with the new CS, EIP, SS, and SP values
;
; Arguments:
;
; ebp -> Trap frame
;
; Returns
;
; 0 is returned if the reflection fails.
;
cPublicProc _Ki386VdmSegmentNotPresent,0
mov edi,PCR[PcTeb]
mov ecx,VDM_FAULT_HANDLER_SIZE * 0Bh
;
; Set up an exception handler in case we fault
; during the user-space accesses below.
;
push ebp
push offset FLAT:VdmSegNotPres_ExceptionHandler
; set up exception registration record
push PCR[PcExceptionList]
mov PCR[PcExceptionList], esp
mov edi,[edi].TeVdm
xor ebx, ebx
cmp edi, _MmUserProbeAddress ; probe the TeVdm
jae reflect
lea esi,[edi].VtDpmiInfo ; (edi)->dpmi info struct
mov edi, [edi].VtFaultTable ;
lea edi,[edi+ecx] ; (edi)->FaultHandler
cmp edi, _MmUserProbeAddress ; probe the table address
jae reflect
cmp word ptr [esi].VpLockCount, 0 ; switching stacks?
jz short seg_not_pres ; yes, we can handle it
; no, let normal code check
; for stack faults
reflect:
;
; WARNING: Here we directly unlink the exception handler from the
; exception registration chain. NO unwind is performed.
;
pop PCR[PcExceptionList]
add esp, 4 ; pop out except handler
pop ebp
;
; Reflect the failure (or exception) back to the usermode ntvdm
; to handle.
;
pop eax ; (eax) = return addr
push 0bh
push eax
jmp _Ki386VdmReflectException
seg_not_pres:
if DEVL
inc _ExVdmSegmentNotPresent
endif
inc word ptr [esi].VpLockCount
; save stuff just like SwitchToHandlerStack does
mov eax, [ebp].TsEip
mov [esi].VpSaveEip, eax
mov eax, [ebp].TsHardwareEsp
mov [esi].VpSaveEsp, eax
mov ax, [ebp].TsHardwareSegSs
mov [esi].VpSaveSsSelector, ax
mov bx,word ptr [esi].VpSsSelector
mov eax, PCR[PcPrcbData+PbCurrentThread]
mov eax, [eax+ThApcState+AsProcess]
lea eax, [eax+PrLdtDescriptor]
mov ch, [eax+KgdtBaseHi]
mov cl, [eax+KgdtBaseMid]
shl ecx, 16
and ebx, 0fffffff8h
mov cx, [eax+KgdtBaseLow]
lea eax, [ecx+ebx]
mov bh, [eax+KgdtBaseHi]
mov bl, [eax+KgdtBaseMid]
shl ebx, 16
mov bx, [eax+KgdtBaseLow] ; (ebx) = Base of SS
mov eax, [ebp].TsEFlags
call GetVirtualBits ; (eax) = app's eflags
push esi
mov edx, 0fe0h ; dpmistack offset (per win31)
test word ptr [esi].VpFlags, 1 ; 32-bit frame?
jz short @f
sub edx, 8 * 4
add edx, ebx
mov esi, [ebp].TsHardwareEsp
mov ecx, [ebp].TsHardwareSegSs
mov [edx + 20], eax ; push flags
mov [edx + 24], esi ; put esp on new stack
mov [edx + 28], ecx ; put ss on new stack
mov ecx, [ebp].TsSegCs
mov eax, [ebp].TsEip
mov esi, [ebp].TsErrCode
mov [edx + 16], ecx ; push cs
mov [edx + 12], eax ; push ip
mov [edx + 8], esi ; push error code
pop esi
mov ecx, [esi].VpDosxFaultIretD
mov eax, ecx
shr eax, 16
and ecx, 0ffffh
mov [edx + 4], eax ; push fault iret seg
mov [edx], ecx ; push fault iret offset
jmp short vsnp_update
@@:
sub edx, 8 * 2
add edx, ebx
mov esi, [ebp].TsHardwareEsp
mov ecx, [ebp].TsHardwareSegSs
mov [edx + 10], ax ; push flags
mov [edx + 12], si ; put esp on new stack
mov [edx + 14], cx ; put ss on new stack
mov ecx, [ebp].TsSegCs
mov eax, [ebp].TsEip
mov esi, [ebp].TsErrCode
mov [edx + 8], cx ; push cs
mov [edx + 6], ax ; push ip
mov [edx + 4], si ; push error code
pop esi
mov ecx, [esi].VpDosxFaultIret
mov eax, ecx
shr eax, 16
mov [edx + 2], ax ; push fault iret seg
mov [edx], cx ; push fault iret offset
vsnp_update:
mov eax,[edi].VfEip
sub edx, ebx
mov cx, word ptr [edi].VfCsSelector
mov bx, word ptr [esi].VpSsSelector
test dword ptr [edi].VfFlags, VDM_INT_INT_GATE
jz short @f
lea esi,ds:FIXED_NTVDMSTATE_LINEAR
MPLOCK and [esi],NOT VDM_VIRTUAL_INTERRUPTS
and dword ptr [ebp].TsEflags, 0FFF7FFFFH ; clear VIF
@@:
or cx, 7 ; R3 LDT selectors only
or bx, 7 ; R3 LDT selectors only
mov [ebp].TsSegCs, cx
mov [ebp].TsEip, eax
mov [ebp].TsHardwareEsp,edx
mov [ebp].TsHardwareSegSs,bx
;
; WARNING: Here we directly unlink the exception handler from the
; exception registration chain. NO unwind is performed.
;
pop PCR[PcExceptionList]
add esp, 4 ; pop out except handler
pop ebp
mov eax, 1
stdRET _Ki386VdmSegmentNotPresent
stdENDP _Ki386VdmSegmentNotPresent
;
; Error and exception blocks for Ki386VdmSegmentNoPresent
;
VdmSegNotPres_ExceptionHandler:
;
; WARNING: Here we directly unlink the exception handler from the
; exception registration chain. NO unwind is performed.
;
mov esp, [esp+8] ; (esp)-> ExceptionList
jmp reflect
page ,132
subttl "Dispatch UserMode Exception to a Vdm"
;++
;
; Routine Description:
;
; Dispatches exception for vdm from in the kernel, by invoking
; CommonDispatchException.
;
; Arguments: See CommonDispatchException for parameter description
;
; VOID
; VdmDispatchException(
; PKTRAP_FRAME TrapFrame,
; NTSTATUS ExcepCode,
; PVOID ExcepAddr,
; ULONG NumParms,
; ULONG Parm1,
; ULONG Parm2,
; ULONG Parm3
; )
;
; Returns
;
; Nothing
;
; Notes:
;
; This routine may not preserve all of the non-volatile registers if
; a fault occurs.
;
cPublicProc _VdmDispatchException,7
TrapFrame equ [ebp+8]
ExcepCode equ [ebp+12]
ExcepAddr equ [ebp+16]
NumParms equ [ebp+20]
Parm1 equ [ebp+24]
Parm2 equ [ebp+28]
Parm3 equ [ebp+32]
push ebp
mov ebp,esp
pushad
xor ecx, ecx ; lower irql to 0
fstCall KfLowerIrql ; allow APCs and debuggers in!
mov eax, ExcepCode
mov ebx, ExcepAddr
mov ecx, NumParms
mov edx, Parm1
mov esi, Parm2
mov edi, Parm3
mov ebp, TrapFrame
call CommonDispatchException
popad
pop ebp
stdRET _VdmDispatchException
stdENDP _VdmDispatchException
page ,132
subttl "Push Interrupt frame on user stack"
;++
;
; Routine Description:
;
; This routine pushes an interrupt frame on the user stack
;
; Arguments:
;
; ecx = interrupt #
; esi = address of reg info
; Returns:
;
; interrupt frame pushed on stack
; reg info updated
;
public PushInt
PushInt proc
push ebx
push edi
;
; Handle dispatching interrupts directly to the handler, rather than
; to the dos extender
;
;
; Get the information on the interrupt handler
;
.errnz (VDM_INTERRUPT_HANDLER_SIZE - 8)
mov eax,PCR[PcTeb]
;
; Set up an exception handler in case we fault
; during the user-space accesses below.
;
push ebp
push offset FLAT:PushIntExceptionHandler ; set up exception registration record
push PCR[PcExceptionList]
mov PCR[PcExceptionList], esp
mov eax,[eax].TbVdm
cmp eax, _MmUserProbeAddress
jae pierr
mov eax, [eax].VtInterruptTable
lea eax,[eax + ecx*8]
cmp eax, _MmUserProbeAddress
jae pierr
;
; Get SP
;
mov edi,[ebp].TsHardwareEsp
test [esi].RiSsFlags,SEL_TYPE_BIG
jnz @f
movzx edi,di ; zero high bits for 64k stack
;
; Update SP
;
@@: test [eax].ViFlags,dword ptr VDM_INT_32
jz @f
;
; 32 bit iret frame
;
cmp edi,12 ; enough space on stack?
jb pierr ; no, go fault
sub edi,12
mov [esi].RiEsp,edi
jmp pi130
;
; 16 bit iret frame
;
@@: cmp edi,6 ; enough space on stack?
jb pierr ; no, go fault
sub edi,6
mov [esi].RiEsp,edi
;
; Check limit
;
pi130: test [esi].RiSsFlags,SEL_TYPE_ED
jz pi140
;
; Expand down, Sp must be above limit
;
cmp edi,[esi].RiSsLimit
jna pierr
jmp pi150
;
; Normal, Sp must be below limit
;
pi140: cmp edi,[esi].RiSsLimit
jnb pierr
;
; Get base of ss
;
pi150: mov ebx,[esi].RiSsBase
test [eax].ViFlags,dword ptr VDM_INT_32
jz pi160
;
; "push" 32 bit iret frame
;
mov edx,[esi].RiEip
mov [edi + ebx],edx
mov dx,word ptr [ebp].TsSegCs
mov [edi + ebx] + 4,edx
push eax
mov eax,[esi].RiEFlags
call GetVirtualBits
mov [edi + ebx] + 8,eax
pop eax
jmp pi170
;
; push 16 bit iret frame
;
pi160: mov dx,word ptr [esi].RiEip
mov [edi + ebx],dx
mov dx,word ptr [ebp].TsSegCs
mov [edi + ebx] + 2,dx
push eax
mov eax,[esi].RiEFlags
call GetVirtualBits
mov [edi + ebx] + 4,ax
pop eax
;
; Update CS and IP
;
pi170: mov ebx,eax ; save int info
mov dx,[eax].ViCsSelector
mov word ptr [esi].RiSegCs,dx
mov edx,[eax].ViEip
mov [esi].RiEip,edx
movzx eax, word ptr [esi].RiSegCs
call CsToLinear ; uses eax as selector
test al,0ffh
jnz pi175
;
; Check for destination not present
;
test [esi].RiCsFlags,SEL_TYPE_NP
jz pierr
mov al,0ffh ; succeeded
jmp pi180
;
; Check handler address
;
pi175: mov edx,[esi].RiEip
cmp edx,[esi].RiCsLimit
jnb pierr
;
; Turn off the trap flag
;
pi180: and [esi].RiEFlags,NOT EFLAGS_TF_MASK
;
; Turn off virtual interrupts if necessary
;
test [ebx].ViFlags,dword ptr VDM_INT_INT_GATE
; n.b. We know al is non-zero, because we succeeded in cstolinear
jz pi80
test _KeI386VirtualIntExtensions,PM_VIRTUAL_INT_EXTENSIONS
jz pi75
and [esi].RiEFlags, NOT (EFLAGS_VIF)
pi75: lea ebx,ds:FIXED_NTVDMSTATE_LINEAR
MPLOCK and [ebx], NOT EFLAGS_INTERRUPT_MASK
pi80: and [esi].RiEFlags,NOT (EFLAGS_IOPL_MASK OR EFLAGS_NT_MASK OR EFLAGS_V86_MASK)
or [esi].RiEFlags,EFLAGS_INTERRUPT_MASK
pi90:
;
; WARNING: Here we directly unlink the exception handler from the
; exception registration chain. NO unwind is performed.
;
pop PCR[PcExceptionList]
add esp, 4 ; pop out except handler
pop ebp
pop edi
pop ebx
ret
pierr: xor eax,eax
jmp pi90
PushInt endp
PushIntExceptionHandler:
mov esp, [esp+8] ; (esp)-> ExceptionList
xor eax,eax
jmp pi90
page ,132
subttl "Convert CS Segment or selector to linear address"
;++
;
; Routine Description:
;
; Convert CS segment or selector to linear address as appropriate
; for the current user mode processor mode.
;
; Arguments:
;
; esi = reg info
;
; Returns:
;
; reg info updated
;
public CsToLinear
CsToLinear proc
test [esi].RiEFlags,EFLAGS_V86_MASK
jz ctl10
shl eax,4
mov [esi].RiCsBase,eax
mov [esi].RiCsLimit,0FFFFh
mov [esi].RiCsFlags,0
mov eax,1
ret
ctl10:
push edx ; WARNING volatile regs!!!
lea edx,[esi].RiCsLimit
push edx
lea edx,[esi].RiCsBase
push edx
lea edx,[esi].RiCsFlags
push edx
push eax ; push selector
IFDEF STD_CALL
call _Ki386GetSelectorParameters@16
ELSE
call _Ki386GetSelectorParameters
add esp,10h
ENDIF
pop edx
or al,al
jz ctlerr
test [esi].RiCsFlags,SEL_TYPE_EXECUTE
jz ctlerr
test [esi].RiCsFlags,SEL_TYPE_2GIG
jz ctl30
; Correct limit value for granularity
shl [esi].RiCsLimit,12
or [esi].RiCsLimit,0FFFh
ctl30:
mov eax,1
ret
ctlerr: xor eax,eax
ret
CsToLinear endp
page ,132
subttl "Verify that EIP is still valid"
;++
;
; Routine Description:
;
; Verify that Eip is still valid and put it into the trap frame
;
; Arguments:
;
; esi = address of reg info
;
; Returns:
;
;
public CheckEip
CheckEip proc
mov eax,[esi].RiEip
test [esi].RiEFlags,EFLAGS_V86_MASK
jz ce20
and eax,[esi].RiCsLimit
mov [esi].RiEip,eax
jmp ce40
ce20: cmp eax,[esi].RiCsLimit
ja ceerr
ce40: mov eax,1
ce50: ret
ceerr: xor eax,eax
jmp ce50
CheckEip endp
page ,132
subttl "Convert Ss Segment or selector to linear address"
;++
;
; Routine Description:
;
; Convert Ss segment or selector to linear address as appropriate
; for the current user mode processor mode.
;
; Arguments:
;
; eax = selector to convert
; esi = address of reg info
;
; Returns:
;
; reg info updated
;
public SsToLinear
SsToLinear proc
test [esi].RiEFlags,EFLAGS_V86_MASK
jz stl10
shl eax,4
mov [esi].RiSsBase,eax
mov [esi].RiSsLimit,0FFFFh
mov [esi].RiSsFlags,0
mov eax,1
ret
stl10: push ecx
lea ecx,[esi].RiSsLimit
push ecx
lea ecx,[esi].RiSsBase
push ecx
lea ecx,[esi].RiSsFlags
push ecx
push eax ;selector
IFDEF STD_CALL
call _Ki386GetSelectorParameters@16
ELSE
call _Ki386GetSelectorParameters
add esp,10h
ENDIF
pop ecx
or al,al
jz stlerr
test [esi].RiSsFlags,SEL_TYPE_WRITE
jz stlerr
test [esi].RiSsFlags,SEL_TYPE_2GIG
jz stl30
; Correct limit value for granularity
mov eax,[esi].RiSsLimit
shl eax,12
or eax,0FFFh
mov [esi].RiSsLimit,eax
stl30:
mov eax,1
stl40: ret
stlerr: xor eax,eax
jmp stl40
SsToLinear endp
page ,132
subttl "Verify that Esp is still valid"
;++
;
; Routine Description:
;
; Verify that Esp is still valid
;
; Arguments:
;
; ecx = # of bytes needed for stack frame
; esi = address of reg info
;
; Returns:
;
;
;
public CheckEsp
CheckEsp proc
mov eax,[esi].RiEsp
test [esi].RiEFlags,EFLAGS_V86_MASK
jz cs20
and eax,[esi].RiSsLimit
mov [esi].RiEsp,eax
jmp cs40
cs20: test [esi].RiSsFlags,SEL_TYPE_BIG
jnz cs25
and eax,0FFFFh ; only use 16 bit for 16 bit
cs25:
cmp ecx, eax ; StackOffset > SP?
ja cserr ; yes error
dec eax ; make limit checks work
test [esi].RiSsFlags,SEL_TYPE_ED ; Expand down?
jz cs30 ; jif no
;
; Expand Down
;
sub eax, ecx ; New SP
cmp eax,[esi].RiSsLimit ; NewSp < Limit?
jb cserr
jmp cs40
;
; Not Expand Down
;
cs30: cmp eax,[esi].RiSsLimit
ja cserr
cs40: mov eax,1
cs50: ret
cserr: xor eax,eax
jmp cs50
CheckEsp endp
page ,132
subttl "Switch to protected mode interrupt stack"
;++
;
; Routine Description:
;
; Switch to protected mode interrupt handler stack
;
; Arguments:
;
; ecx = interrupt number
; esi = address of reg info
; edi = address of PM Stack info
;
; Returns:
;
; reg info updated
;
public SwitchToHandlerStack
SwitchToHandlerStack proc
;
; Install exception handler
;
push ebp
push esp ; Pass current Esp to handler
push offset SwitchToHandlerStack_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
cmp word ptr [edi].VpLockCount, 0 ; already switched?
jnz short @f ; yes
mov eax, [esi].RiEip
mov [edi].VpSaveEip, eax
mov eax, [esi].RiEsp
mov [edi].VpSaveEsp, eax
mov eax, [esi].RiSegSs
mov [edi].VpSaveSsSelector, ax
movzx eax,word ptr [edi].VpSsSelector
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
mov [esi].RiSegSs,eax
mov dword ptr [esi].RiEsp,1000h ; dpmi stack offset
movzx eax, word ptr [esi].RiSegSs
push ecx
call SsToLinear ; compute new base
pop ecx
test al,0FFh
jz shserr
push ebp
push esp ; Pass current Esp to handler
push offset SwitchToHandlerStack_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
@@:
inc word ptr [edi].VpLockCount ; maintain lock count
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
mov eax,1
ret
shserr:
xor eax,eax
ret
SwitchToHandlerStack_fault:
mov esp, [esp+8]
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
xor eax,eax
ret
SwitchToHandlerStack endp
page ,132
subttl "Get protected mode interrupt handler address"
;++
;
; Routine Description:
;
; Get the address of the interrupt handler for the specified interrupt
;
; Arguments:
;
; ecx = interrupt number
; esi = address of reg info
;
; Returns:
;
; reg info updated
;
public GetHandlerAddress
GetHandlerAddress proc
push ebp
push ecx
push edx
push esp ; Pass current Esp to handler
push offset GetHandlerAddress_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov eax,VDM_FAULT_HANDLER_SIZE
mul ecx
mov edi,PCR[PcTeb]
mov edi,[edi].TeVdm
cmp edi, _MmUserProbeAddress ; Probe the VMD structure
jae @f
mov edi,[edi].VtFaultTable
cmp edi, _MmUserProbeAddress
jae @f
movzx ecx,word ptr [edi + eax].VfCsSelector
mov [esi].RiSegCs,ecx
mov ecx,[edi + eax].VfEip
mov [esi].RiEip,ecx
mov eax,1
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop edx
pop ecx
pop ebp
ret
@@:
GetHandlerAddress_fault_resume:
xor eax, eax
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop edx
pop ecx
pop ebp
ret
GetHandlerAddress_fault:
mov esp, [esp+8]
jmp GetHandlerAddress_fault_resume
GetHandlerAddress endp
page ,132
subttl "Push processor exception"
;++
;
; Routine Description:
;
; Update the stack and registers to emulate the specified exception
;
; Arguments:
;
; ecx = interrupt number
; esi = address of reg info
;
; Returns:
;
; reg info updated
;
public PushException
PushException Proc
push ebx
push edi
test [esi].RiEflags,EFLAGS_V86_MASK
jz pe40
;
; Push V86 mode exception
;
cmp ecx, 7 ; device not available fault
ja peerr ; per win3.1, no exceptions
; above 7 for v86 mode
mov edx,[esi].RiEsp
mov ebx,[esi].RiSsBase
and edx,0FFFFh ; only use a 16 bit sp
sub dx,2
mov eax,[esi].RiEFlags
push ecx
call GetVirtualBits
pop ecx
;
; Install exception handler
;
push ebp
push esp ; Pass current Esp to handler
push offset perr_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov [ebx+edx],ax ; push flags
sub dx,2
mov ax,word ptr [esi].RiSegCs
mov [ebx+edx],ax ; push cs
sub dx,2
mov ax,word ptr [esi].RiEip
mov [ebx+edx],ax ; push ip
mov eax,[ecx*4] ; get new cs:ip value
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
push eax
movzx eax,ax
mov [esi].RiEip,eax
pop eax
shr eax,16
mov [esi].RiSegCs,eax
mov word ptr [esi].RiEsp,dx
jmp pe60
perr1_fault:
mov esp, [esp+8] ; (esp)-> ExceptionList
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
jmp peerr1
perr_fault:
mov esp, [esp+8] ; (esp)-> ExceptionList
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
jmp peerr
;
; Push PM exception
;
pe40:
push [esi].RiEsp ; save for stack frame
push [esi].RiSegSs
;
; Install exception handler
;
push ebp
push esp ; Pass current Esp to handler
push offset perr1_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov edi,PCR[PcTeb]
mov edi, [edi].TeVdm
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
cmp edi, _MmUserProbeAddress
jae peerr1
lea edi,[edi].VtDpmiInfo
call SwitchToHandlerStack
test al,0FFh
jz peerr1 ; pop off stack and exit
sub [esi].RiEsp, 20h ; win31 undocumented feature
mov ebx,[esi].RiSsBase
mov edx,[esi].RiEsp
test [esi].RiSsFlags,SEL_TYPE_BIG
jnz short @f
movzx edx,dx ; zero high bits for 64k stack
@@:
;
; Install exception handler
;
push ebp
push esp ; Pass current Esp to handler
push offset perr1_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
test word ptr [edi].VpFlags, 1 ; 32 bit app?
pop PCR[PcExceptionList] ; Remove our exception handle
lea esp, [esp+8] ; clear stack
pop ebp
jnz pe45 ; yes
;
; push 16-bit frame
;
push ecx
mov ecx, 8*2 ; room for 8 words?
call CheckEsp
pop ecx
test al,0FFh
jz peerr1 ; pop off stack and exit
sub edx,8*2
mov [esi].RiEsp,edx
;
; Install exception handler
;
push ebp
push esp ; Pass current Esp to handler
push offset perr1_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov eax, [esp+4*4]
mov [ebx+edx+14], ax
mov eax, [esp+4*5]
mov [ebx+edx+12], ax
pop PCR[PcExceptionList] ; Remove our exception handle
lea esp, [esp+8] ; clear stack
pop ebp
lea esp, [esp+8] ; clear stack
mov eax,[esi].RiEFlags
push ecx
call GetVirtualBits
pop ecx
;
; Install exception handler
;
push ebp
push esp ; Pass current Esp to handler
push offset perr_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov [ebx+edx+10],ax ; push flags
movzx eax,word ptr [esi].RiSegCs
mov [ebx+edx+8],ax ; push cs
mov eax,[esi].RiEip
mov [ebx+edx+6],ax ; push ip
mov eax,RI.RiTrapFrame
mov eax,[eax].TsErrCode
mov [ebx+edx+4],ax ; push error code
mov eax,[edi].VpDosxFaultIret
mov [ebx+edx],eax ; push iret address
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
jmp pe50
pe45:
;
; push 32-bit frame
;
push ecx
mov ecx, 8*4 ; room for 8 dwords?
call CheckEsp
pop ecx
test al,0FFh
jz peerr1 ; pop off stack and exit
sub edx,8*4
mov [esi].RiEsp,edx
push ebp
push esp ; Pass current Esp to handler
push offset perr1_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov eax, [esp+4*4]
mov [ebx+edx+28], eax
mov eax, [esp+4*5]
mov [ebx+edx+24], eax
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
lea esp, [esp+8] ; drop ss etc
mov eax,[esi].RiEFlags
push ecx
call GetVirtualBits
pop ecx
push ebp
push esp ; Pass current Esp to handler
push offset perr_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov [ebx+edx+20],eax ; push flags
movzx eax,word ptr [esi].RiSegCs
mov [ebx+edx+16],eax ; push cs
mov eax,[esi].RiEip
mov [ebx+edx+12],eax ; push ip
mov eax,RI.RiTrapFrame
mov eax,[eax].TsErrCode
mov [ebx+edx+8],eax ; push error code
mov eax,[edi].VpDosxFaultIretD
shr eax, 16
mov [ebx+edx+4],eax ; push iret seg
mov eax,[edi].VpDosxFaultIretD
and eax, 0ffffh
mov [ebx+edx],eax ; push iret offset
pop PCR[PcExceptionList] ; Remove our exception handle
add esp, 8 ; clear stack
pop ebp
pe50:
call GetHandlerAddress
test al,0FFh
jz peerr
pe60: push ecx
movzx eax,word ptr [esi].RiSegCs
call CsToLinear ; uses eax as selector
pop ecx
test al,0FFh
jz peerr
mov eax,[esi].RiEip
cmp eax,[esi].RiCsLimit
ja peerr
mov eax,VDM_FAULT_HANDLER_SIZE
push edx
mul ecx
pop edx
push ebp
push esp ; Pass current Esp to handler
push offset perr_fault ; Set Handler address
push PCR[PcExceptionList] ; Set next pointer
mov PCR[PcExceptionList],esp ; Link us on
mov edi,PCR[PcTeb]
mov edi,[edi].TbVdm
cmp edi, _MmUserProbeAddress
jb @f
mov edi, _MmUserProbeAddress
@@: mov edi,[edi].VtFaultTable
add edi,eax
cmp edi, _MmUserProbeAddress
jb @f
mov edi, _MmUserProbeAddress
@@: mov eax,[esi].RiEFlags ;WARNING 16 vs 32
test dword ptr [edi].VfFlags,VDM_INT_INT_GATE
pop PCR[PcExceptionList] ; Remove our exception handle
lea esp, [esp+8] ; clear stack
pop ebp
jz pe70
and eax,NOT (EFLAGS_INTERRUPT_MASK OR EFLAGS_TF_MASK)
push eax
xor ebx, ebx ; clear prefix flags
call SetVirtualBits
pop eax
pe70: push ecx
mov ecx,eax
call CheckVdmFlags
and ecx,NOT EFLAGS_TF_MASK
mov [esi].RiEFlags,ecx
pop ecx
mov eax,1 ; success
pe80: pop edi
pop ebx
ret
peerr1: add esp, 8 ;throw away esp, ss
peerr: xor eax,eax
jmp pe80
PushException endp
_PAGE ends
_TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
ASSUME DS:NOTHING, ES:NOTHING, SS:FLAT, FS:NOTHING, GS:NOTHING
;
; Non-pagable code
;
page ,132
subttl "Ipi worker for enabling Pentium extensions"
;++
;
; Routine Description:
;
; This routine sets or resets the VME bit in CR4 for each processor
;
; Arguments:
;
; [esp + 4] -- 1 if VME is to be set, 0 if it is to be reset
; Returns:
;
; 0
;
cPublicProc _Ki386VdmEnablePentiumExtentions, 1
Enable equ [ebp + 8]
push ebp
mov ebp,esp
;
; Insure we do not get an interrupt in here. We may
; be called at IPI_LEVEL - 1 by KiIpiGenericCall.
;
pushf
cli
; mov eax,cr4
db 0fh, 020h,0e0h
test Enable,1
je vepe20
or eax,CR4_VME
jmp vepe30
vepe20: and eax,NOT CR4_VME
; mov cr4,eax
vepe30: db 0fh,022h,0e0h
popf
xor eax,eax
mov esp,ebp
pop ebp
stdRET _Ki386VdmEnablePentiumExtentions
stdENDP _Ki386VdmEnablePentiumExtentions
_TEXT$00 ends
end