Windows2000/private/ntos/ke/i386/instemul.asm
2020-09-30 17:12:32 +02:00

2624 lines
66 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 ..\..\..\inc\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
EXTRNP _KeBugCheck,1
EXTRNP _Ki386GetSelectorParameters,4
EXTRNP _Ki386VdmDispatchIo,5
EXTRNP _Ki386VdmDispatchStringIo,8
EXTRNP _KiDispatchException,5
EXTRNP _VdmPrinterStatus,3
EXTRNP KfLowerIrql,1,IMPORT, FASTCALL
EXTRNP _VdmPrinterWriteData, 3
; JAPAN - SUPPORT Intel CPU/Non PC/AT machine
extrn _VdmFixedStateLinear:dword
extrn _KeI386MachineType:dword
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
_DATA 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
public _ExVdmOpcodeDispatchCounts,_ExVdmSegmentNotPresent
_ExVdmOpcodeDispatchCounts dd MAX_VDM_INDEX dup(0)
_ExVdmSegmentNotPresent dd 0
_DATA 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
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
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,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
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
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
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
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
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
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
; JAPAN - SUPPORT Intel CPU/Non PC/AT compatible machine
; Get Hardware Id, PC_AT_COMPATIBLE is 0x00XX
test _KeI386MachineType, MACHINE_TYPE_MASK
jnz oib_reflect
; 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
oib20:
xor eax, eax ; not handled
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
; JAPAN - SUPPORT Intel CPU/Non PC/AT compatible machine
; Get Hardware Id, PC_AT_COMPATIBLE is 0x00XX
test _KeI386MachineType, MACHINE_TYPE_MASK
jnz oob_reflect
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,[ebp].TsEFlags
and eax,NOT EFLAGS_INTERRUPT_MASK
call SetVirtualBits
inc dword ptr [ebp].TsEip
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
mov eax,[ebp].TsEFlags
or eax,EFLAGS_INTERRUPT_MASK
call SetVirtualBits
inc dword ptr [ebp].TsEip
mov eax,_VdmFixedStateLinear
mov eax,dword ptr [eax]
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
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
mov ecx,_VdmFixedStateLinear ; get pointer to Teb
mov ecx,dword ptr [ecx] ; get virtual int flag
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
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
mov ecx,_VdmFixedStateLinear
mov ecx,dword ptr [ecx]
and ecx,VDM_VIRTUAL_AC
and eax,NOT EFLAGS_ALIGN_CHECK
or eax,ecx
or eax,EFLAGS_IOPL_MASK
ret
gvb50: test _KeI386VirtualIntExtensions, PM_VIRTUAL_INT_EXTENSIONS
jz gvb10
jmp gvb40
gvb60: test eax,EFLAGS_V86_MASK
jz gvb10
mov ecx,_VdmFixedStateLinear
mov ecx,dword ptr [ecx]
and ecx,VDM_VIRTUAL_AC
and eax,NOT EFLAGS_ALIGN_CHECK
or eax,ecx
or eax,EFLAGS_IOPL_MASK
ret
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
mov ebp,esp
sub esp,4
push edx
mov Flags,eax
mov edx,_VdmFixedStateLinear ; get pointer to Teb
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: pop edx
mov esp,ebp
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 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 enable 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]
push ebp
mov ebp,esp
sub esp,REGINFOSIZE
pushad
mov esi,_VdmFixedStateLinear
; Look to see if the debugger wants exceptions
test dword ptr [esi],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 dword ptr [esi],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 dword ptr [esi],VDM_BREAK_DEBUGGER
jz vrevdm ; no debug events, reflect to vdm
mov ebx,DBG_SINGLESTEP
cmp word ptr [ebp + 8],1
jnz @f
test dword ptr [esi],VDM_USE_DBG_VDMEVENT
jnz vrexc_event
jmp vrexc1
@@:
mov ebx,DBG_BREAK
cmp word ptr [ebp + 8],3
jnz vrevdm
test dword ptr [esi],VDM_USE_DBG_VDMEVENT
jnz vrexc_event
jmp vrexc3
; reflects 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 xyzzy1
inc _ExVdmSegmentNotPresent
xyzzy1:
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[PcPrcbData+PbCurrentThread]
mov ecx,VDM_FAULT_HANDLER_SIZE * 0Bh
mov edi,[edi]+ThApcState+AsProcess
mov edi,[edi].EpVdmObjects
mov edi,[edi].VpVdmTib ; get pointer to VdmTib
xor ebx, ebx
lea esi,[edi].VtDpmiInfo ; (edi)->dpmi info struct
lea edi,[edi+ecx].VtFaultHandlers ; (edi)->FaultHandler
cmp word ptr [esi].VpLockCount, 0 ; switching stacks?
jz short @f ; yes, we can handle it
; no, let normal code check
; for stack faults
pop eax ; (eax) = return addr
push 0bh
push eax
jmp _Ki386VdmReflectException
@@:
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
mov esi,_VdmFixedStateLinear ; get pointer to Teb
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
mov eax, 1
stdRET _Ki386VdmSegmentNotPresent
stdENDP _Ki386VdmSegmentNotPresent
page ,132
subttl "Dispatch UserMode Exception to a Vdm"
; Routine Description:
; Dispatches exception for vdm in from 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 apc's 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
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
pi100:
; Handle dispatching interrupts directly to the handler, rather than
; to the dos extender
; Get a the information on the interrupt handler
.errnz (VDM_INTERRUPT_HANDLER_SIZE - 8)
mov eax,PCR[PcTeb]
mov eax,[eax].TbVdm
lea eax,[eax].VtInterruptHandlers[ecx*8]
; Get SP
mov edi,[ebp].TsHardwareEsp
test [esi].RiSsFlags,SEL_TYPE_BIG
jnz pi110
movzx edi,di ; zero high bits for 64k stack
; Update SP
pi110: test [eax].ViFlags,dword ptr VDM_INT_32
jz pi120
; 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
pi120: 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: mov ebx,_VdmFixedStateLinear
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: pop edi
pop ebx
ret
pierr: xor eax,eax
jmp pi90
PushInt endp
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 curret user mode processor mode.
; Arguments:
; esi = reg info
; Returns:
; reg info updated
public CsToLinear
CsToLinear proc
test [esi].RiEFlags,EFLAGS_V86_MASK
jz ctl10
;;; selector now passed in eax
;;; movzx eax,word ptr [esi].RiSegCs
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
ctl40: ret
ctlerr: xor eax,eax
jmp ctl40
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 curret 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
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
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
@@:
inc word ptr [edi].VpLockCount ; maintain lock count
mov eax,1
ret
shserr:
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 sepcified interrupt
; Arguments:
; ecx = interrupt number
; esi = address of reg info
; Returns:
; reg info updated
public GetHandlerAddress
GetHandlerAddress proc
push ecx
push edx
mov eax,VDM_FAULT_HANDLER_SIZE
mul ecx
mov edi,PCR[PcPrcbData+PbCurrentThread]
mov edi,[edi]+ThApcState+AsProcess
mov edi,[edi].EpVdmObjects
mov edi,[edi].VpVdmTib ; get pointer to VdmTib
lea edi,[edi].VtFaultHandlers
movzx ecx,word ptr [edi + eax].VfCsSelector
mov [esi].RiSegCs,ecx
mov ecx,[edi + eax].VfEip
mov [esi].RiEip,ecx
pop edx
pop ecx
mov eax,1
ret
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
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
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
; Push PM exception
pe40:
push [esi].RiEsp ; save for stack frame
push [esi].RiSegSs
mov edi,PCR[PcPrcbData+PbCurrentThread]
mov edi,[edi]+ThApcState+AsProcess
mov edi,[edi].EpVdmObjects
mov edi,[edi].VpVdmTib ; get pointer to VdmTib
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
@@:
test word ptr [edi].VpFlags, 1 ; 32 bit app?
jnz short 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
pop eax ; ss
mov [ebx+edx+14], ax
pop eax ; esp
mov [ebx+edx+12], ax
mov eax,[esi].RiEFlags
push ecx
call GetVirtualBits
pop ecx
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
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
pop eax ; ss
mov [ebx+edx+28], eax
pop eax ; esp
mov [ebx+edx+24], eax
mov eax,[esi].RiEFlags
push ecx
call GetVirtualBits
pop ecx
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
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
mov edi,PCR[PcTeb]
mov edi,[edi].TbVdm
lea edi,[edi].VtFaultHandlers
add edi,eax
mov eax,[esi].RiEFlags ;WARNING 16 vs 32
test dword ptr [edi].VfFlags,VDM_INT_INT_GATE
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