SCCSID equ "@(#)em86int.asm     6.25 92/03/23"

PAGE    ,132
TITLE   EM86INT - INT Instruction 8086 Emulation
NAME    EM86INT
.386p

;***    EM86INT.ASM
;
;        Version 1.24.1.5, for src/dos/mvdm/em86int.asm, em86, mer.krnl, 960610.1
;
;       Title:
;
;       8086 emulation support for INT instructions
;
;       Description:
;
;       This routine contains the emulation and support routines
;       for the software interrupt emulation.
;
;       Public routines:
;
;       VDHPushInt
;       VDHPopInt
;       em86opINTO
;       em86opINTnn
;       EM86ReflectException
;       EM86ReflectV86Exception
;       EM86ReflectVPMException
;       em86ReflectInt
;       em86V86ReflectionHook
;       em86ReflectV86Int
;       em86IntHook
;       em86CHookStubINTH
;       em86CHookStubPreINTH
;       em86VPMExcBPTerminate
;       em86V86ExcBPTerminate    149007
;       em86VPMExcBPReflect
;       em86VPMIntBPHdlr
;       em86VPMInt21Hdlr
;       em86VPMInt31Hdlr
;       EM86Int23Hook
;
;       Modification History:
;
;       07-31-91        Bill Madden     PTR B725180
;         Fixed em86ReflectVPMInt to use the virtual int flag
;       08-06-91        Bill Madden     PTR B725374     Bx001
;         Fixed VPMIntDispatcher to call em86endVPMExecution if int 23 not hooked
;       09-25-91        Bill Madden     DCR 1531
;         Fixed em86ReflectVPMInt and em86ReflectVPMException to check accesses
;         to user stack.  Changed VDHPushInt and VDHPopInt to have a return
;         values.
;       10-01-91        Bill Madden     PTR B725792     Bx002
;         Changed em86opINTnn to skip over two more instructions in trap0d.
;       10-21-91        Bill Madden     PTR B728503
;         Fixed em86VPMExcBPReflect to not pop values off user stack.
;       10-24-91        Bill Madden     PTR B728028     Bx003
;         Changed em86VPMInt2FHdlr to not reflect XMS calls to real mode.
;       10-29-91        Steve Best      PTR B729110
;         Remove perfview counter
;       11-02-91        Bill Madden     PTR B728804     Bx004
;         Fixed problem in em86ReflectVPMException validation of user stack.
;       12-07-91        Bill Madden     PTR B729861
;         Fixed VPMIntDispatcher to allocate a selector for device header.
;       12-15-91        Bill Madden     PTR B730556     Bx005
;         Fixed em86VPMExcRetHook to use VDHReadUBuf to read client data.
;       01-15-92        Bill Madden     PTR B731393
;         Changed EM86ReflectVPMException and EM86VPMExcRetHook to issue
;         a hard error if the client stack is invalid.
;       02-28-92        Bill Madden     PTR B733208
;         Changed EM86ReflectVPMException to work for nested exceptions.
;       03-16-92        Bill Madden     PTR AZ09818     Bx006
;         Disable interrupts when messing with client's flags.
;       03-23-92        Bill Madden     PTR B734959     Bx007
;         Have flag on interrupt stack match virtual IF.
;       07-08-92        Bill Madden     DEF   24741
;         Always use VDHRead/WriteUBuf when accessing DPMI client stack.
;       08-14-92        Bill Madden     DEF   24624     Bx008
;         Insure vectors in IVT don't point inside IVT.
;       09-02-92        Bill Madden     DEF   53395     Bx009
;         Save entire CRF for Int 23, 24 in protect mode.
;       10-12-92        Bill Madden     DEF   55694     Bx010
;         HPO uses ints 250-252 for int 1C handler.
;       11-10-92        Bill Madden     DEF   56890     Bx011
;         Added em86Int23Hook
;       01-18-93        Bill Madden     DEF   60491     Bx012
;         Added support for VPM Int 2f 4010 and 4011
;       02-20-93        Bill Madden     DEF   61782     Bx013
;         Use em86AllocSel routine.
;       03-19-93        OS/2 Change Team  DEF 62577     Bx014
;         Compute the interrupt address during the 'slow' stack wrap
;       03-20-92        Jon Grimm         DEF 63248     Bx015
;         Added MMIO perf hooks to VDHPushInt, VDHPopInt
;       03-24-92        Bill Madden       DEF xxxxx     Bx016
;         Added P5 support.
;       08/23/93        Change Team       DEF 72717     Bx017
;         Changed to reflect int23 to real mode if we don't have it hooked.
;       06/16/94        Liren Ji        DEF   86206     WIN32
;         Added code to call Win32s registered fault handler if it installed
;       07/12/94        Liren Ji        DEF   88529     WIN32
;         Moved the fault handler code to intercept exception sooner
;       09/19/94        bjn
;         Changed segment names for page tuning.
;       04/10/96        Julie Tran      DEF  151118    WIN32S
;         Save content of CR2 register for use in win32s Exception Handler routine.


INCL_NONE       equ     1                       ; don't include everything
INCL_TYPES      equ     1                       ; include basic types
INCL_DEF        equ     1                       ; include typedef macros
INCL_VDHALL     equ     1                       ; include VDH services

.xlist
        include fnomvdm.inc
        include dosseg.inc
        include osmaca.inc
        include osconst.inc
        include infoseg.inc
        include dossymc.inc
        include sigdef.inc
        include except.inc
        include pgexport.inc
        include vmexport.inc
        include selxport.inc
        include tkexport.inc
        include dirent.inc
        include curdir.inc
        include find.inc
        include screen.inc
        include sft.inc
        include sem.inc
        include tkptda.inc
        include kmode.inc
        include seldesc.inc
        include mvdm.inc
        include vdmvdh.inc
        include em86.inc
        include mi.inc
;b729110        include perfvw.inc
        include int2f.inc
        include dpmi.inc
        include vpmxport.inc
        include vpm.inc
        include mmpha.inc
        include dbgex.inc              ; 149007
.list
        ModName  em86int, FNO_EM86INT_ASM

        CpuMode 386

       IFDEF   PMDEBUG
        ReferGlobal segDebugCS,WORD
        EXTRN   TRAPDebugFault:NEAR
       ENDIF

        EXTRN   KMCHECKEVENTSIZE:ABS
        EXTRN   GPTTFCHECKSIZE:ABS                                      ;BN002


        ReferFlat _flGlobalActions,dword

; Local constants
IVT_FOR_CODE_LEN        equ     18h     ; Apps run code in ints 250-256 ;BN010


DefCode EXPORT, SWAP, PASCAL
DefFn   VDHPushInt
DefFn   VDHPopInt
DefFn   em86IntHook
DefFn   em86CHookStubINTH
DefFn   em86CHookStubPreINTH
DefFn   em86V86ReflectionHook
DefFn   em86VPMReflectionHook
DefFn   em86VPMExcBPTerminate
DefFn   em86V86ExcBPTerminate                  ; 149007
DefFn   em86VPMExcBPReflect
DefFn   em86VPMIntBPHdlr
DefFn   EM86Int23Hook                                                   ;BN011
DefFn   em86VPMInt21Hdlr
DefFn   em86VPMInt31Hdlr
DefFn   EM86ReflectException
DefFn   em86VPMInt2FHdlr
DefFn   VPMIntDispatcher
DefFn   EM86VPMExcRetHook
EndCode

DefCode EXPORT, SWAP
DefFn   em86ReflectInt                          ; 149007
DefFn   EM86ReflectV86Exception
DefFn   EM86ReflectVPMException
EndCode


DefCode IMPORT, SWAP
DefFn   em86IRET16                              ; em86if.asm
DefFn   em86PopVPMIRET                          ; em86if.asm
DefFn   em86DispatchVDMBP                       ; em86misc.asm
DefFn   em86CheckVPMBP                          ; em86misc.asm
EndCode

DefCode IMPORT, SWAP, C                                                 ;BN012
DefFn   int2fGetVDDAPI                          ; int2f.c               ;BN012
DefFn   em86AllocSel                            ; em86vpm.c             ;BN013
DefFn   em86FreeSel                             ; em86vpm.c             ;BN013
DefFn   EM86ReflectV86ExpException              ; em86vpmx.c            ;149007
DefFn   EM86V86INTtoVPM                         ; em86vpmx.c            ;149007
DefFn   em86GetDr6                              ; em86vpmx.c            ;149007
EndCode                                                                 ;BN012

DefCode IMPORT, SWAP, PASCAL
DefFn   INT2FV86Dispatcher                      ; int2f.c
DefFn   VDHArmReturnHook                        ; em86.c
DefFn   VDHSwitchToVPM                          ; em86misc.asm
DefFn   VDHSwitchToV86                          ; em86misc.asm
DefFn   VDHGetVPMIntVector                      ; em86vpm.c
DefFn   VDHSetVPMIntVector                      ; em86vpm.c
DefFn   VDHBeginUseVPMStack                     ; em86vpmx.c
DefFn   VDHEndUseVPMStack                       ; em86vpmx.c
DefFn   VDHChangeVPMIF                          ; em86vpmx.c
DefFn   VDHPushFarCall                          ; em86.c
DefFn   VDHRaiseException                       ; em86vpmx.c
DefFn   em86EndVPMExecution                     ; em86vpm.c
DefFn   VDHCheckVPMIntVector                    ; em86vpmx.c
DefFn   VDHReadUBuf                             ; em86vpmx.asm
DefFn   VDHWriteUBuf                            ; em86vpmx.asm
DefFn   VDHPushStack                            ; em86misc.asm
DefFn   VDHPopStack                             ; em86misc.asm
DefFn   VDHSetFlags                             ; em86if.asm   ; 149007
EndCode

DefCode IMPORT, GLOBAL
DefFn   KMDispatchHook                          ; km
EndCode

DefCode IMPORT, GLOBAL, PASCAL
DefFn   VDHAssertVDMTaskOnly                    ; vdmm
EndCode

DefCode IMPORT, GLOBAL, C
DefFn   TRAPProcessFatalFault                   ; trap
DefFn   SELSetDescInfo                          ; memory\selmgra.asm
EndCode


DefData IMPORT, GLOBAL, C
PVOID   pTCBCur                                 ; tk
PVOID   pfndpmInt31Rte                          ; em86vpm.c
EndData

DefData IMPORT, INSTANCE, C
PVOID   pvsfFrameBase                           ; em86.c
PVOID   hookheadSTIH                            ; em86.c
HVDM    vdmid_HVDM                              ; vdmm.c
EndData

DefData IMPORT, SWAPINST, C
PVOID   pvdmArpl                                ; em86.c
PVOID   apinthHead                              ; em86.c
ULONG   flVdmStatus                             ; em86vpm.c
ULONG   cr2_buf                                 ; em86vpmx.c   ;149007
HHOOK   hhookV86ReflectionHook                  ; em86vpm.c
HHOOK   hhookVPMReflectionHook                  ; em86vpm.c
HHOOK   hhookVPMExcRetHook                      ; em86vpm.c
HHOOK   hhookVPMExpExcRetHook                   ; em86vpm.c    ;149007
HHOOK   hhookV86ExpExcRetHook                   ; em86vpm.c    ;149007
HHOOK   hhookV86ExpExc9RetHook                  ; em86vpm.c    ;149007
SEL     selVPMBP                                ; em86vpm.c
PVOID   papfnVPMBP                              ; em86vpm.c
USHORT  usEIPincr                               ; em86vpm.c
PVOID   pFaultHandler                           ; em86vpm.c             ;WIN32
UCHAR   flrestart                               ; em86vpmx.c
PDHD    pdhdHostData                            ; em86vpm.c
PVPMD   pvpmData                                ; em86vpm.c
VPVOID  vpV86Int23vect                          ; em86vpm.c             ;BN011
VPVOID  vpOurV86Int23vect                       ; em86vpm.c             ;72717
EndData

DefData PRIVATE, SWAPINST
ULONG   ulClientESP                             ; int reflected from real -> prot
EndData

        FARCODE HIGH32
DefCode PRIVATE, SWAP, PASCAL
SWAP32_18 segment
;***EP  VDHPushInt - Call V86 or VPM interrupt code
;
;       Simulate interrupt to specified V86 interrupt vector, as if
;       a DOS program has executed an "INT n" instruction.  Any VDD
;       hooked on this interrupt with VDHInstallIntHook will get control
;       as expected.  The VDHArmReturnHook service can be used after
;       this service is called to regain control when the V86 code
;       executes the IRET.
;
;       ENTRY
;           iVector - interrupt vector number (0 - 255)
;
;       EXIT-SUCCESS
;           Returns TRUE
;
;       EXIT-FAILURE
;           Returns FALSE if fault would occur accessing user stack
;           If iVector is invalid
;               System Halt.
;
;       VDM TERMINATION IMPLICATIONS
;           None.
;
;       CONTEXT
;           VDM Task
;
;       NOTES
;           (1) This call does not take effect until OS/2 returns to V86 mode.
;           (2) This call will always return TRUE for V86 mode tasks
;
;       PSEUDO-CODE
;
;       validate parameter
;       em86ReflectInt(iVector)
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure VDHPushInt,near

ArgVar  iVector,DWORD

        EnterProc
        SaveReg <ebx, esi, edi>
        ASSERTVDMTASKONLY               ; validate the calling context
        mov     eax,[iVector]           ; (EAX) = vector number
        MMPHPreVDHPushInt       eax
       IFDEF VDHSTRICT
        cmp     eax,NUM_INTS            ; validate parameters
        jbe     short vpi10
        em86InvalidParameter, <"VDHPushInt: iVector">
        jmp     short vpix
       ENDIF
vpi10:  mov     ebx,[pvsfFrameBase]     ; (EBX) = pvsf
        em86AssertVSF pTCBCur
        call    em86ReflectInt          ; reflect interrupt
vpix:
        MMPHPostVDHPushInt
        RestoreReg <edi, esi, ebx>
        ExitProc
EndProc   VDHPushInt
SWAP32_18 ends

SWAP32_18 segment
;***EP  VDHPopInt - Remove interrupt frame from client's stack
;
;       This function reverses the effects of VDHPushInt.  It
;       removes the IRET frame from the client's stack and restores
;       the client's CS:IP to what was in the IRET frame.
;
;       ENTRY
;           None.
;
;       EXIT-SUCCESS
;           Returns TRUE
;
;       EXIT-FAILURE
;           Returns FALSE
;
;       VDM TERMINATION IMPLICATIONS
;           None.
;
;       CONTEXT
;           VDM Task
;
;       NOTES
;           Always returns TRUE for V86 mode tasks
;
;       PSEUDO-CODE
;
;       call 16 bit iret emulation routine
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure VDHPopInt,near
        MMPHPreVDHPopInt                ; KCK - Added MMIO hooks
        SaveReg <ebx, esi, edi>
        ASSERTVDMTASKONLY               ; validate the calling context
        mov     ebx,[pvsfFrameBase]     ; (EBX) = pvsf
        em86AssertVSF pTCBCur
        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC
        jnz     short vpo10             ; jump if VDM protected mode
        call    em86IRET16              ; pop V86 iret off of stack
        mov     eax,TRUE                ; return SUCESS
        jmp     short vpox

vpo10:  call    em86PopVPMIRET          ; pop VPM iret off of stack
vpox:   RestoreReg <edi, esi, ebx>
        MMPHPostVDHPopInt               ; KCK - Added MMIO hooks
        ExitProc
EndProc   VDHPopInt
SWAP32_18 ends

;***LP  em86opINTO - Emulate trap on overflow interrupt instruction
;
;       This function emulates the trap on overflow software
;       interrupt by reflecting it back to the VDM.  It called
;       by the opcode decoder for the INTO instruction.
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI+EDI = pointer to faulting opcode
;               Client's CS:IP points to faulting opcode
;
;       EXIT    NONE
;
;       USES    EAX, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if overflow flag set
;           em86ReflectException(4)
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING
        ALIGN   4

Procedure em86opINTO,near
        inc     edi
        mov     [ebx].vsf_eip,edi               ; adjust EIP

        testb   [ebx].vsf_eflag,F_OVERFLOW      ; is there overflow?
        jz      short eio10                     ;  no, jump to exit
        mov     eax,4                           ;  yes, reflect interrupt 4
        call    EM86ReflectException
eio10:  ret
EndProc   em86opINTO

SWAP32_25 segment
;***EP  EM86ReflectException - Reflect VDM V86 or protected mode exception
;***EP  EM86ReflectVPMException - Reflect VDM protected mode exception
;
;       Exceptions are handled differently from software interrupts
;       in protected mode.  Exceptions have their own shadow table
;       of VPM app handlers.  If the VPM app has not hooked an exception
;       the VDM is terminated on some and reflected to V86 mode on others.
;       V86 mode exceptions and software interrupts are reflected the
;       same way (thru the IVT).
;       Exceptions 0 - 5, and 7 are reflected to V86 mode
;
;       ENTRY   EAX = interrupt number
;               EBX = pointer client register frame (CRF)
;               EDX = error code
;               if EXCEPTION is EXCPG (page fault)       ;149007
;                  ECX = CR2                             ;149007
;
;       EXIT    NONE
;
;       USES    EAX, ECX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if V86 mode execution
;           go do v86 mode exception
;       else
;           call VDM protected mode exception handler
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure EM86ReflectException,near
        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC
        jz   TUNESWP  ;  EM86ReflectV86Exception

Entry   EM86ReflectVPMException,near
LocalVar        pOffset, DWORD
LocalVar        us_excep, WORD                              ; 149007
LocalVar        excstack, <size exexcst_s>                  ; 149007
LocalVar        usStackSize, DWORD                          ; 149007

        EnterProc

        cmp     eax,EXCPG                        ; Page Fault?    149007
        jnz     erve01                           ; NO, Do nothing ;149007
        mov     cr2_buf,ecx                      ; Put CR2 in cr2_buf ;149007

erve01:                                         ;149007
        ; Win32s ring-0 fault handler support   ; DEFECT 88529
        cmp     [pFaultHandler],0               ; is win32 handler registered
        je      rfe09                           ;   no, let system handle
        push    eax                             ; set parameters
        push    ebx                             ;

        push    eax                             ;
        push    ebx                             ;
        push    ecx                             ; provide CR2_BUF for VW32S; JT-151118
                                                ; 151795
        call    [pFaultHandler]                 ; and call win32 handler
        mov     ecx,eax                         ; save return value in ecx
        pop     ebx                             ;
        pop     eax                             ;
        or      ecx,ecx                         ; is the handle OK
        jne     rfeexit                         ;   yes, let get out
rfe09:
        mov     esi,eax                         ; ESI = Interrupt Number
        mov     us_excep,ax                     ; us_excep = interrupt Number
                                                ;149007
        imul    esi,esi,(size vpmexc_s)         ; ESI = offset of VPMExcept
        mov     edi,pvpmData                    ; (EDI) = ptr to host data
        add     esi,[edi.vpmd_pavpmexc]         ; (ESI) = shadow table pointer
                                                ;  ESI = vpmd_pavpmexc[int] GK
       IFDEF   EM86STRICT
        em86AssertP VPMEXC,esi
       ENDIF

;       Default exception handler VPM breakpoints are checked here.  If the
;       the breakpoint belongs to this exception, then push the iret, etc.
;       and popping the iret frame off, etc. is bypassed.

        mov     cx,[esi].vpmexc_sel             ; (CX) = handler selector
        cmp     cx,selVPMBP                     ; is it the BP selector?
                                                ; if yes, no exception handler GK
        je      rfe20                           ;  yes, go check the offset

rfe10:
        push    DWORD PTR [ebx].vsf_ss          ; save client's SS in krnl stack
        push    [ebx].vsf_esp                   ; save client's ESP
        call    VDHBeginUseVPMStack

        testb   [esi].vpmexc_fb, VPMXCPT10SET   ;149007
                                                ; is it an expanded stack?
        jnz     EXP1                        ; Yes, jmp expanded stack.;149007

        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?;149007
        jne     EXP0_1                          ; yes. Jmp 32 bit    ;149007
        mov     usStackSize,(size excst_s)      ; sizeof 16bit exception stack ;149007
        jmp     EXP2                            ;149007
EXP0_1:                                         ;149007
        mov     usStackSize,(size exc32_s)      ; sizeof 32bit exception stack ;149007
        jmp     EXP2                            ;149007

EXP1:                                           ;149007
; mov expanded stack data                       ;149007
        mov     cx,[ebx].vsf_es                 ; move ES to expanded stack
        mov     excstack.exexcst_es,cx          ;;149007
        mov     cx,[ebx].vsf_ds                 ; move DS to expanded stack
        mov     excstack.exexcst_ds,cx          ;;149007
        mov     cx,[ebx].vsf_fs                 ; move FS to expanded stack
        mov     excstack.exexcst_fs,cx          ;;149007
        mov     cx,[ebx].vsf_gs                 ; move GS to expanded stack
        mov     excstack.exexcst_gs,cx          ;;149007
;set information bits. Default 00  ?? GK         ;149007
        mov     excstack.exexcst_info,00        ;;149007

; set CR2 and PTE
        cmp     us_excep,EXCPG                  ; page fault?
        jne     EXP1_0                          ; no, jmp ok

; Set CR2 and PTE

        mov     ecx,[cr2_buf]                   ;149007
        mov     excstack.exexcst_cr2,ecx        ;149007

; all the memory are fully virtualized by OS/2 kernel. If page fault
; the page is not allocated(committed)          ;149007
        mov     excstack.exexcst_pte,0          ; The only chance that user
                                                ; get this is memory uncommited
                                                ; set it as zero
EXP1_0:                                         ;149007

        mov     usStackSize,(size exexcst_s)    ; make room for expanded stack ;149007
EXP2:                                           ;149007
; usStackSize = size of exception stack frame( 16 bit, 32 bit and expanded
        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?;149007
        jnz     rfe30                           ;  yes, do 32 bit stack frame

;       16 bit stack frame or Expanded stack frame
        movzx   edi,[ebx].vsf_sp                ; (EDI) = client's SP           ;BN004
        sub     edi,usStackSize                 ; make room for stack ;149007
        jc      rfeerr1                         ; if not enough room, kill app
        mov     [ebx].vsf_sp,di                 ; update client's SP            ;BC004
        mov     pOffset,edi                     ; pOffset is the APP stack now
                                                ;149007

;       Build 16 bit DPMI exception frame on VPM client's stack
;
;       ([ebx].vsf_ss:vsf_sp = ES:EDI) = client's SS:SP

        mov     excstack.excst_errcode, dx      ; get error code
        mov     excstack.exexcst_errcode, edx   ; get error code

; if it's a break point or trap                 ;149007
        cmp     us_excep,01h                    ; BreakPoint? ;149007
        jne     EXP2_1                          ; no, jmp ok  ;149007

;set error code                                               ;149007
        push    ebx                                           ;149007
        CCall   em86GetDr6                      ; get DR6 value;149007
        pop     ebx                                            ;149007
        and     eax,000ffh                      ; only dr0-dr3(bit0-3);149007
        testb   [ebx].vsf_eflag,F_TRACE         ; Trace Flag set?     ;149007
        je      EXP2_1_0                        ; NO, jmp ok          ;149007
        or      ax,08000h                       ; Set bit 15          ;149007
EXP2_1_0:                                                             ;149007
        mov     excstack.excst_errcode, ax     ; get error code       ;149007
        mov     excstack.exexcst_errcode,eax                          ;149007
                                                                      ;149007
EXP2_1:                                                               ;149007
                                                                      ;149007
        movzx   eax,[ebx].vsf_ip                ; (EAX) = IP          ;149007

        cmp     flrestart, 0                    ; reexecute the faulting inst?
        jz      short rfe15                     ; if zero, don't
        clrb    flrestart, VPM_RESTART_INST     ; clear restart flag
        sub     ax,usEIPincr                    ; back up IP
; Who and when was ths usEIPincr updated?? Was it always updated? GK ;149007
;        mov     usEIPincr, 0                    ; GK clear the used value??
rfe15:                                          ;149007
        mov     excstack.excst_ip, ax           ; put ip in Exception Stack;149007
        mov     excstack.exexcst_eip, eax       ; put eip in Expanded Stack;149007

        mov     ax,[ebx].vsf_cs                 ; (AX) = CS         ;149007
        mov     excstack.excst_cs, ax           ; put cs in Exception Stack;149007
        mov     excstack.exexcst_cs, ax         ; put cs in Expanded stack ;149007

        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags
        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short rfe151                    ; not P5
        test    eax, F_VIF                      ; set IF from VIF
        jz      short rfe150
        or      eax, F_INTERRUPT                ; set IF
        jmp     short rfe16
TUNESWP: jmp    EM86ReflectV86Exception
rfe150:
        and     eax, not F_INTERRUPT            ; clear IF
        jmp     short rfe16
rfe151:                                                                 ;BN016 end
        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG    ; virt if enabled?
        jnz     short rfe16                             ; yes, continue
        and     eax,NOT F_INTERRUPT                     ; clear int flag
rfe16:
;       mov     ax,[esi].vpmexc_usFlags         ; update flags for the exception
        mov     excstack.excst_flags,ax         ; put flags on client's stack
        mov     excstack.exexcst_eflags,eax     ; put eflags on expanded stack
                                                ;149007
        pop     eax                             ; get client's original ESP
        mov     excstack.excst_sp, ax           ; put in exception stack
        mov     excstack.exexcst_esp, eax       ; put in expanded stack;149007
        pop     eax                             ; get client's original SS
        mov     excstack.excst_ss, ax           ;
        mov     excstack.exexcst_ss, ax         ;149007

        jmp     rfe40                           ; jump to exit

rfe20:  mov     edi,eax                         ; (EDI) = exception number
        add     edi,VPM_EXC_BP_START            ; add in start of exceptions
        cmp     edi,[esi].vpmexc_off            ; does the BP offset == excnum?
        jne     rfe10                           ;  no, go build iret frame
        mov     eax,[papfnVPMBP]                ; (EAX) = VPM BP table address
        leave                                   ; clean up stack
        jmp     [eax+edi*4]                     ; execute BP function

;       32 bit stack frame
;       usStackSize = sizeof 32bit stack or Expanded stack
rfe30:
        mov     edi,[ebx].vsf_esp               ; (EDI) = client's SP           ;BN004
        sub     edi,usStackSize      ;149007    ; make room for exception stack ;BC004
        jc      rfeerr1                         ; no room on stack, kill app
        mov     [ebx].vsf_esp,edi               ; update client's ESP           ;BC004
        mov     pOffset,edi          ;149007    ; pOffset is the APP stack now

;       Build 32 bit DPMI exception frame on VPM client's stack
;
;       ([ebx].vsf_ss:vsf_esp = ES:EDI = client's SS:ESP )

        mov     excstack.exc32_errcode, edx     ; store error code
        mov     excstack.exexcst_errcode, edx   ; store error code;149007

        cmp     us_excep,01h                    ; BreakPoint?     ;149007
        jne     EXP3_1                          ; no, jmp ok      ;149007
;set error code                                                   ;149007
        push    ebx                                               ;149007
        CCall   em86GetDr6                      ; Get DR6 registers;149007
        pop     ebx                                                ;149007
        and     ax,000ffh                       ; only dr0-dr3(bit0-3);149007
        testb   [ebx].vsf_eflag,F_TRACE         ; Trace Flag set?     ;149007
        je      EXP3_1_0                        ; NO, jmp ok          ;149007
        or      ax,08000h                       ; Set bit 15          ;149007
EXP3_1_0:                                                             ;149007
        mov     excstack.exexcst_errcode,eax                          ;149007
        mov     excstack.exc32_errcode,eax                            ;149007
                                                                      ;149007
EXP3_1:                                                               ;149007

        mov     eax,[ebx].vsf_eip               ; (EAX) = EIP

        cmp     flrestart, 0                    ; reexecute the faulting inst?
        jz      short rfe35                     ; no
        clrb    flrestart, VPM_RESTART_INST     ; clear restart flag
        movzx   edx,usEIPincr                   ; get EIP adjustment
        sub     eax,edx                         ; adjust EIP
;        mov     usEIPincr,0
rfe35:
        mov     excstack.exc32_eip, eax         ; store fauling EIP
        mov     excstack.exexcst_eip, eax       ; store fauling EIP ;149007

        mov     ax,[ebx].vsf_cs                 ; (AX) = CS
        mov     excstack.exc32_cs, ax           ; store faulting CS
        mov     excstack.exexcst_cs, ax         ; store faulting CS ;149007

        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags
        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short rfe350                    ; not P5
        test    eax, F_VIF                      ; set IF from VIF
        jz      short rfe351
        or      eax, F_INTERRUPT                ; set IF
        jmp     short rfe36
rfe351:
        and     eax,not F_INTERRUPT             ; clear IF
        jmp     short rfe36

rfeerr1:       ; this is a far jmp to referr only to avoid out of range error
        jmp     rfeerr                         ;149007

rfe350:                                                                 ;BN016 end
        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG    ; virt if enabled?
        jnz     short rfe36                             ; yes, continue
        and     eax,NOT F_INTERRUPT                     ; clear int flag
rfe36:
;       mov     ax,[esi].vpmexc_usFlags         ; (EAX) = flags
        mov     excstack.exc32_eflags, eax      ; store flags
        mov     excstack.exexcst_eflags, eax   ; store flags ;149007

        pop     eax                             ; get client's original ESP
        mov     excstack.exc32_esp, eax         ; store original ESP
        mov     excstack.exexcst_esp, eax       ; store original ESP;149007
        pop     eax                             ; get client's original SS
        mov     excstack.exc32_ss, ax           ; store original SS
        mov     excstack.exexcst_ss, ax         ; store original SS ;149007


rfe40:                                                             ;149007
                                                                   ;149007
; Save the return hook in expanded stack                           ;149007
        cmp     usStackSize, (size exexcst_s)  ; Is it an Expanded Stack? ;149007
        jne     no_expanded                                        ;149007
                                                                   ;149007
        ; save CS:EIP for later use                                ;149007
        push    [ebx].vsf_cs                                       ;149007
        push    [ebx].vsf_eip                                      ;149007
                                                                   ;149007
        push    ebx                                                ;149007
        PCall   VDHArmReturnHook, <hhookVPMExpExcRetHook, \
                                   VDHARH_CSEIP_HOOK or VDHARH_ALWAYS_ARM_HOOK>
        pop     ebx                                                ;149007

        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?;149007
        jnz     expand32                        ;  yes, do 32 bit stack frame
                                                                    ;149007
        mov     ax,[ebx].vsf_cs                 ; EAX = RetHook Sel ;149007
        mov     excstack.exexcst_ret_cs,ax                          ;149007
        shl     eax,16                          ; EAX HI-16 bit = sel;149007
        mov     ecx,[ebx].vsf_eip               ;                    ;149007
        and     ecx,0ffffh                      ; get 16 bit offset  ;149007
        mov     ax,cx                           ; eax = SEL:OffSET   ;149007
        mov     excstack.exexcst_ret_eip,eax                         ;149007
        ; restore CS:eip for later VDHArmReturnHook                  ;149007
        pop     [ebx].vsf_eip                                        ;149007
        pop     [ebx].vsf_cs                                         ;149007
                                                                     ;149007
        SSToDS  eax, excstack                   ; (EAX) = temp stack frame;149007
        SSToDS  edi, pOffset                    ; (EDI) = ptr to client's SP;149007
                                                                     ;149007
        PCall   VDHWriteUBuf, <eax, usStackSize, DWORD PTR [ebx].vsf_ss, \
                               edi, VPM_SEL_IS_SS OR VPM_SEL_PRESENT OR  \
                               VPM_NO_SIM_EXCPT OR VPM_FAULT_IF_SU_SET>    ;149007

        or      eax,eax                         ; wrote everything OK?     ;149007
        jz      short rfeerr2                   ; no, kill app             ;149007

; if Expanded stack and 16 bit, the 16 bit is 4 byte less than 32 bit  ;149007
; stack after VDHPushFarCall. We need to compensate the shortage       ;149007
; use no_expanded to store the excst 4 byte lower                      ;149007
        mov     eax, [ebx].vsf_esp                                     ;149007
        sub     eax, 4                                                 ;149007
        jc      rfeerr2                         ; no room on stack, kill app

        mov     [ebx].vsf_esp,eax                                      ;149007
        mov     dword ptr pOffset, eax                                 ;149007
        mov     dword ptr usStackSize,(size excst_s)                   ;149007
                                                                       ;149007
        jmp     no_expanded                     ; store the excst again;149007
rfeerr2:       ; this is a far jmp to referr only to avoid out of range error
        jmp     rfeerr                                                ;149007
                                                                      ;149007
expand32:                                                             ;149007
        mov     ax,[ebx].vsf_cs                 ; EAX = RetHook Sel   ;149007
        mov     excstack.exexcst_ret_cs,ax                            ;149007
        mov     ecx,[ebx].vsf_eip               ;                     ;149007
        mov     excstack.exexcst_ret_eip,ecx                          ;149007
                                                                      ;149007
        ; restore CS:EIP for later VDHArmReturnHook                   ;149007
        pop     [ebx].vsf_eip                                         ;149007
        pop     [ebx].vsf_cs                                          ;149007
                                                                      ;149007
        SSToDS  eax, excstack                   ; (EAX) = temp stack frame;149007
        SSToDS  edi, pOffset                    ; (EDI) = ptr to client's SP;149007

        PCall   VDHWriteUBuf, <eax, usStackSize, DWORD PTR [ebx].vsf_ss, \
                               edi, VPM_SEL_IS_SS OR VPM_SEL_PRESENT OR  \
                               VPM_NO_SIM_EXCPT OR VPM_FAULT_IF_SU_SET>    ;149007
                                                                           ;149007
        or      eax,eax                         ; wrote everything OK?     ;149007
        jz      short rfeerr                    ; no, kill app             ;149007
        jmp     arm_old_ret_csip                                           ;149007
no_expanded:                                                               ;149007
                                                                           ;149007
        SSToDS  eax, excstack                   ; (EAX) = temp stack frame ;149007
        SSToDS  edi, pOffset                    ; (EDI) = ptr to client's SP;149007

        PCall   VDHWriteUBuf, <eax, usStackSize, DWORD PTR [ebx].vsf_ss, \
                               edi, VPM_SEL_IS_SS OR VPM_SEL_PRESENT OR  \
                               VPM_NO_SIM_EXCPT OR VPM_FAULT_IF_SU_SET>    ;149007
                                                                           ;149007
        or      eax,eax                         ; wrote everything OK?     ;149007
        jz      short rfeerr                    ; no, kill app             ;149007
arm_old_ret_csip:                                                          ;149007
        PCall   VDHArmReturnHook, <hhookVPMExcRetHook, \
                                   VDHARH_CSEIP_HOOK or VDHARH_ALWAYS_ARM_HOOK>

        PCall   VDHPushFarCall, <DWORD PTR [esi].vpmexc_sel, [esi].vpmexc_off>

        clrb    [ebx].vsf_eflag, F_TRACE        ; clear trace flag
        PCall   VDHChangeVPMIF, <FALSE>         ; disable interrupts
        leave                                   ; clean up stack frame
        jmp     em86CheckVPMBP                  ; check for any VPM BPs and EXIT

rfeerr:
        NullContext <fs>,eax                    ; clear FS
        CCall   TRAPProcessFatalFault, <0ch, 0> ; cause hard error (trap 0xC)
rfeexit:
        ExitProc

EndProc   EM86ReflectException
SWAP32_25 ends

SWAP32_12 segment
;***LP  em86opINTnn - Emulate software interrupt instruction
;
;       This function emulates the two byte software interrupt
;       by reflecting it back to the VDM.  It called by the opcode
;       decoder for the INT nn instruction.
;
;       This is a highly optimized version of what we used to "FallInto"
;       in em86ReflectInt.  Some key differences are (1) we call
;       em86DispatchVDMBP directly instead of setting TK_FF_VDMBP in the VDM's
;       forceflags if the target is a VDM BP, and (2) we adjust the return
;       address to skip over the forceflag tests in the trap0d handler if the
;       target is NOT a VDM BP.
;
;       Due to these dependencies, this can ONLY be called from the trap0d
;       handler in trap.asm!
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI+EDI = pointer to faulting opcode
;               Client's CS:IP points to faulting opcode
;
;       EXIT    NONE
;
;       USES    EAX, ESI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       get interrupt number byte at CS:IP
;       increment CS:IP past interrupt number byte
;       em86ReflectInt(interrupt number byte)
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86opINT,near,local

int01:  xchg    eax,esi                         ; (EAX) = int number
        add     [ebx].vsf_eip,2                 ; update IP
        jmp     EM86ReflectVPMInt

int02:  xchg    eax,esi                         ; (EAX) = int number
        add     [ebx].vsf_eip,2                 ; adjust IP
        jmp     em86ReflectV86Int


        ALIGN   4
Entry     em86opINTnn,near

        movzx   esi,byte ptr fs:[esi+edi+1]     ; (ESI) = int number

        mov     usEIPincr, 2                    ; size that EIP will be changed

        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC
        jnz     short int01                     ; go to em86ReflectVPMInt

        testb   apinthHead[esi*4],INT_PRE_HOOK  ; pre-reflection hooks exist?
        jnz     short int02                     ; yes, handle out-of-line

        em86AssertPVSF ebx
;b729110 PvwCnt  vdm,Int,0,strict                ; perfview hook

;       Get address from interrupt vector table

        mov     eax,[esi*4]                     ; (EAX) = addr from int vector
        lea     ecx,[edi+2]                     ; save new IP

;       Get client's SS:SP pointer

        mov     si,[ebx].vsf_ss                 ; (ESI) = client's SS
        shl     esi,4                           ; (ESI) = linear SS
        mov     di,[ebx].vsf_sp                 ; (EDI) = client's SP

;       Make room for IRET frame, checking for client stack wrap

        sub     di,(size iret16_s)              ; did the client stack wrap?
        mov     [ebx].vsf_esp,edi               ; update client's SP
        jc      int20                           ; yes, handle stack wrap

;       Build 16 bit return IRET frame on client's stack
;
;       (EAX) = address from interrupt vector table
;       (ESI+EDI) = linear version of client's SS:SP

        add     esi,edi
        mov     [esi].iret16_ip,cx              ; put old IP on client's stack
        mov     di,ax                           ; save new IP
        mov     [ebx].vsf_ip,ax                 ; set new IP

        shr     eax,16                          ; (AX) = seg of int address
        mov     edx,eax                         ; save new CS
        xchg    ax,[ebx].vsf_cs                 ; (AX) = CS, set new CS
        shl     edx,4
        mov     [esi].iret16_cs,ax              ; put CS on client's stack

        pushfd                                  ; Save flags            BN006
        cli                                     ; disable ints          BN006
        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags
        add     edi,edx                         ; (EDI) = linear CS:IP

        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short int101                    ; No -> no VIF bit
        push    eax                             ; save current eflag
        test    eax, F_VIF
        jz      short int102
        or      eax, F_INTERRUPT                ; copy VIF to IF
        jmp     short int103
int102:
        and     eax, not F_INTERRUPT            ; copy VIF to IF
int103:
        mov     [esi].iret16_flag,ax            ; put flags on client's stack
        pop     eax                             ; get current eflag

;       Clear the trace and VIF client flags

        and     eax,NOT (F_TRACE OR F_VIF)
        mov     [ebx].vsf_eflag,eax             ; set eflag
        jmp     short int104
int101:                                                                 ;BN016 end
        mov     [esi].iret16_flag,ax            ; put flags on client's stack

;       Clear the trace and interrupt client flags

        and     eax,NOT (F_TRACE OR F_INTERRUPT)
        mov     [ebx].vsf_eflag,eax
int104:
        popfd                                   ; Restore flags         BN006

;       Perform em86CheckVDMBP (in em86misc.asm) in-line,
;       since we can compute the linear address faster here,
;       and also because we know we can dispatch any hooks immediately...

        cmp     edi,[pvdmArpl]                  ; is the new CS:IP a VDM BP?
;BD008  je      short int30                     ; yes, dispatch
        je      TUNE; em86DispatchVDMBP               ; yes, dispatch

        cmp     edi, IVT_LEN - IVT_FOR_CODE_LEN ; is address above IVT? ;BC010
        jb      short int30                     ; no, kill vdm          ;BN008

        cli
        add     dword ptr [esp],GPTTFCHECKSIZE  ; skip trace flag check in trap0d BN002
        add     dword ptr [esp],KMCHECKEVENTSIZE; skip other checks in trap0d
        cmp     [_flGlobalActions],0            ; and just check global forceflags
        ret

int20:  mov     [ebx].vsf_eip,ecx               ; adjust IP
        jmp     rfv30                           ; now go handle stack wrap
TUNE:   jmp    em86DispatchVDMBP
;BD008 int30:  jmp     em86DispatchVDMBP               ; perform 32-bit jump out-of-line
int30:
        NullContext <fs>,eax                    ; clear FS              ;BN008
        CCall   TRAPProcessFatalFault, <6, 0>   ; kill vdm (trap 6)     ;BN008
        ret

EndProc   em86opINT
SWAP32_12 ends

SWAP32_18 segment
;***LP  em86ReflectInt - Reflect interrupt
;***LP  em86ReflectV86Int - Reflect V86 mode interrupt
;***EP  EM86ReflectV86Exception - Reflect V86 mode exception
;
;       This function changes the V86 control flow to the address
;       the interrupt vector table selected by the interrupt number
;       passed.  A 16 bit IRET frame is build on the client's stack.
;
;       ENTRY   EAX = interrupt number
;               EBX = pointer client register frame (CRF)
;               if EXCEPTION is EXCPG (page fault)       ;149007
;                  ECX = CR2                             ;149007
;
;       EXIT
;               SUCCESS
;                  Returns TRUE
;               FAILURE
;                  Returns FALSE if fault would occur accessing user stack
;
;       USES    EAX, ECX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       NOTES
;               Always returns TRUE for V86 mode tasks
;
;       PSEUDO-CODE
;
;       get the client's CS:IP & flags from client register frame
;       put a 16 bit IRET frame on client's stack with this CS:IP & flags
;       get address from interrupt vector table
;       change the client's CS:IP on the kernel stack to this address
;       clear the trace and interrupt client flags
;       check new CS:IP for a VDM breakpoint address
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure EM86ReflectV86Exception,near           ;149007
        cmp     eax,EXCPG                        ; Page Fault?    149007
        jnz     er8e01                           ; NO, Do nothing ;149007
        mov     cr2_buf,ecx                      ; Put CR2 in cr2_buf;149007
er8e01:                                          ;149007
        push  eax                                ;149007
        push  ebx                                ;149007
        push  edx                                ;149007

        CCall EM86ReflectV86ExpException, <eax, ebx, edx>;149007
        or    ax,ax                              ;149007
                                                 ;149007
        pop   edx                                ;149007
        pop   ebx                                ;149007
        pop   eax                                ;149007
                                                 ;149007
        jz    rv86int                            ;149007
        ret                                      ;149007
rv86int:                                         ;149007
                                                 ;149007
Entry   em86ReflectInt,near                      ;149007
        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC
        jnz    TUNESWP2 ;  EM86ReflectVPMInt

Entry   em86ReflectV86Int,near

        em86AssertPVSF ebx

       IFDEF PMDEBUG
        mov     si,[eax*4].Segmt                ; (SI) = para from int vector
        cmp     si,[segDebugCS]                 ; is it kernel debugger CS?
        jne     short rfv10                     ;  no, reflect int
        or      ebx,-1                          ; (EBX) = user stack frame
        jmp     TRAPDebugFault                  ; go to debugger
rfv10:
       ENDIF

        call    em86CallPreIntHooks             ; call any existing prehooks
        jnc     rfvret                          ; int was emulated

; This is a temporary fix. According to DPMI 1.0 spec, INT 1Ch, INT 23h
; INT 24h which happens in V86 mode has to be sent to its VPM INT Handler
; if any. But, this sounds incompatiable to a lot of Game Program.
; For SVT to begin test ASAP, We just bypass this feature.
; Wait for further servey.

        jmp     rfv15                           ; 153566


;       Get address from interrupt vector table ;149007
        cmp  eax,1ch                            ;149007
        je   checkvpmhndlr                      ;149007
        cmp  eax,23h                            ;149007
        je   checkvpmhndlr                      ;149007
        cmp  eax,24h                            ;149007
        jne  rfv15      ; it's not int 1Ch, 23h, 24h

checkvpmhndlr:          ; V86 INT 1C, 23, 24 with a INT handler in VPM;149007
        push eax                                ;149007
        push ebx                                ;149007
        CCall VDHCheckVPMIntVector, <eax>       ;149007
        or   ax,ax                              ;149007
        pop  ebx                                ;149007
        pop  eax                                ;149007
        jz   normalint                          ;149007
                                                ;149007
;Reflect to VPM INT handler                     ;149007
        CCall EM86V86INTtoVPM, <eax, ebx>       ;149007
                                                ;149007
        ret                                     ;149007
normalint:                                      ;149007

rfv15:  mov     eax,[eax*4]                     ; (EAX) = addr from int vector

;       Get client's SS:SP pointer

        movzx   esi,[ebx].vsf_ss                ; (ESI) = client's SS
        shl     esi,4                           ; (ESI) = linear SS
        movzx   edi,[ebx].vsf_sp                ; (EDI) = client's SP

;       Make room for IRET frame, checking for client stack wrap

        sub     di,(size iret16_s)              ; did the client stack wrap?
        mov     [ebx].vsf_sp,di                 ; update client's SP
        jc      rfv30                           ;  yes, handle stack wrap

;       Build 16 bit return IRET frame on client's stack
;
;       (EAX) = address from interrupt vector table
;       (ESI+EDI) = linear version of client's SS:SP

        add     esi,edi
        mov     di,ax                           ; save new IP
        xchg    ax,[ebx].vsf_ip                 ; (AX) = IP, set new IP
        mov     [esi].iret16_ip,ax              ; put IP on client's stack

        shr     eax,16                          ; (AX) = seg of int address
        mov     edx,eax                         ; save new CS
        xchg    ax,[ebx].vsf_cs                 ; (AX) = CS, set new CS
        shl     edx,4
        mov     [esi].iret16_cs,ax              ; put CS on client's stack

        pushfd                                  ; Save flags            BN006
        cli                                     ; disable ints          BN006
        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags
        add     edi,edx                         ; (EDI) = linear CS:IP

        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short rfv151                    ; No -> no VIF bit
        push    eax                             ; save current eflag
        test    eax, F_VIF
        jz      short rfv152
        or      eax, F_INTERRUPT                ; copy VIF to IF
        jmp     short rfv153
TUNESWP2:  jmp  EM86ReflectVPMInt
rfv152:
        and     eax, not F_INTERRUPT            ; copy VIF to IF
rfv153:
        mov     [esi].iret16_flag,ax            ; put flags on client's stack
        pop     eax                             ; get current eflag

;       Clear the trace and VIF client flags

        and     eax,NOT (F_TRACE OR F_VIF)
        mov     [ebx].vsf_eflag,eax             ; set eflag
        jmp     short rfv201
rfv151:                                                                 ;BN016 end
        mov     [esi].iret16_flag,ax            ; put flags on client's stack

;       Clear the trace and interrupt client flags

rfv20:  and     eax,NOT (F_TRACE OR F_INTERRUPT)
        mov     [ebx].vsf_eflag,eax
rfv201:
        popfd                                   ; restore flags         BN006

;       Perform em86CheckVDMBP (in em86misc.asm) in-line,
;       since we can compute the linear address faster here

        mov     esi,[pTCBCur]                   ; (ESI) = current tcb pointer
        cmp     edi,[pvdmArpl]                  ; is the new CS:IP a VDM BP?
        je      short rfv25                     ; yes, so mark VDM

        cmp     edi, IVT_LEN - IVT_FOR_CODE_LEN ; is address above IVT? ;BC010
        jb      short rfv26                     ; no, kill vdm          ;BN008

        clrb    [esi].TCBForcedActions,TK_FF_VDMBP
        ret

rfv25:  orb     [esi].TCBForcedActions,TK_FF_VDMBP
        ret

rfv26:                                                                  ;BN008
        NullContext <fs>,eax                    ; clear FS              ;BN008
        CCall   TRAPProcessFatalFault, <6, 0>   ; kill vdm (trap 6)     ;BN008
rfvret: ret

;       Client stack wrapped, build the IRET the slow way
;
;       (EAX) = address from interrupt vector table
;       (ESI) = client's shifted SS
;       (EDI) = client's SP

rfv30:  movzx   ecx, ax                         ; Save the IP of ISR    BN014
        xchg    ax,[ebx].vsf_ip                 ; (AX) = IP, set new IP
        mov     [esi+edi],ax                    ; put IP on client's stack
        add     di,2                            ; increment SP with wrap

        shr     eax,16                          ; (AX) = seg of int address
        mov     edx, eax                        ; Save the CS of ISR    BN014
        shl     edx, 4                          ; Linear CS for int     BN014
        add     ecx, edx                        ; (ECX) = ISR lin addr  BN014
        xchg    ax,[ebx].vsf_cs                 ; (AX) = CS, set new CS
        mov     [esi+edi],ax                    ; put CS on client's stack
        add     di,2                            ; increment SP with wrap

        pushfd                                  ; Save flags            BN006
        cli                                     ; disable interrupts    BN006
        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags

        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short rfv301                    ; No -> no VIF bit
        push    eax                             ; save current eflag
        test    eax, F_VIF
        jz      short rfv302
        or      eax, F_INTERRUPT                ; copy VIF to IF
        jmp     short rfv303
rfv302:
        and     eax, not F_INTERRUPT            ; copy VIF to IF
rfv303:
        mov     [esi+edi],ax                    ; put flags on client's stack
        pop     eax                             ; get current eflag

;       Clear the trace and VIF client flags

        and     eax,NOT (F_TRACE OR F_VIF)
        mov     [ebx].vsf_eflag,eax             ; set eflag
        mov     edi, ecx                        ; Reset int addr in edi BN014
        jmp     rfv201
rfv301:                                                                 ;BN016 end
        mov     [esi+edi],ax                    ; put flags on client's stack
        mov     edi, ecx                        ; Reset int addr in edi BN014
        jmp     rfv20
EndProc   EM86ReflectV86Exception               ;149007
SWAP32_18 ends

SWAP32_24 segment
;***EP  EM86ReflectVPMInt - Reflect VDM protected mode interrupt
;
;       ENTRY   EAX = interrupt number
;               EBX = pointer client register frame (CRF)
;
;       EXIT
;               SUCCESS - returns TRUE
;               FAILURE - returns FALSE
;
;       USES    EAX, ECX, EDX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure EM86ReflectVPMInt,near
LocalVar        pOffset, DWORD
LocalVar        iretframe, <size iret32_s>

        EnterProc

        mov     edi,pvpmData                    ; (EDI) = ptr to vpm data
       IFDEF   EM86STRICT
        mov     esi,eax
        imul    esi,esi,(size vpmint_s)
        add     esi,[edi.vpmd_pavpmint]         ; (ESI) = shadow table pointer
        em86AssertP VPMINT,esi
       ELSE
        mov     esi,[edi.vpmd_pavpmint]
        lea     esi,[esi+eax*type vpmint_s]     ; (ESI) = shadow table pointer
       ENDIF

;       Default interrupt handler VPM breakpoints are checked here.  If the
;       the breakpoint belongs to this interrupt, then push the iret, etc.
;       and popping the iret frame off, etc. is bypassed.

        mov     cx,[esi].vpmint_sel             ; (CX) = handler selector
        cmp     cx,selVPMBP                     ; is it the BP selector?
        je      rfi20                           ;  yes, go check the offset

rfi10:
        mov     eax,[esi].vpmint_off            ; (EAX) = handler offset
        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?
        jnz     rfi30                           ;  yes, do 32 bit stack frame

;       16 bit stack frame

        movzx   edi,[ebx].vsf_sp                ; (EDI) = client's SP
        sub     di,(size iret16_s)              ; update client's SP
        mov     [ebx].vsf_sp,di                 ; store client's updated SP
        jc      rfierr                          ; no room, return error

;       Build 16 bit return IRET frame on VPM client's stack
;
;       (CX) = selector
;       (AX) = 16 bit offset
;       (ES:EDI) = client's SS:SP

        xchg    ax,[ebx].vsf_ip                 ; (AX) = IP, set new IP
        mov     iretframe.iret16_ip, ax         ; store IP

        xchg    cx,[ebx].vsf_cs                 ; (AX) = CS, set new CS
        mov     iretframe.iret16_cs, cx         ; put CS on client's stack

        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags

        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short rfi102
        test    eax, F_VIF                      ; copy VIF to IF
        jz      short rfi101
        or      eax, F_INTERRUPT                ; set IF
        jmp     short rfi15
rfi101:
        and     eax,not  F_INTERRUPT            ; clear IF
        jmp     short rfi15
rfi102:                                                                 ;BN016 end
        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG    ; virt if enabled?
        jnz     short rfi15                             ; yes, continue
        and     eax,NOT F_INTERRUPT                     ; clear int flag
rfi15:
        mov     iretframe.iret16_flag, ax
        push    eax
        mov     pOffset, edi                    ; get client's SP
        SSToDS  eax, iretframe                  ; (ESI) = temp stack frame
        SSToDS  edi, pOffset                    ; (EDI) = ptr to client's SP

        PCall   VDHWriteUBuf, <eax, <size iret16_s>, DWORD PTR [ebx].vsf_ss, \
                               edi, VPM_SEL_IS_SS OR VPM_SEL_PRESENT OR      \
                               VPM_FAULT_IF_SU_SET>

        or      eax,eax                         ; everything OK?
        pop     eax
        jz      rfierr                          ; no, exit

        jmp     rfi40                           ; jump to exit

rfi20:  cmp     eax,[esi].vpmint_off            ; does the BP offset == intnum?
        jne     rfi10                           ;  no, go build iret frame
        mov     edi,eax                         ; (EDI) = interrupt number
        mov     eax,[papfnVPMBP]                ; (EAX) = VPM BP table address
        call    [eax+edi*4]                     ; execute BP function
        mov     eax,TRUE
        ExitProc premature

;       32 bit stack frame
rfi30:
        mov     edi,[ebx].vsf_esp               ; (EDI) = client's ESP

;       Build 32 bit return IRET frame on VPM client's stack
;
;       (CX) = selector
;       (EAX) = 32 bit offset
;       (ES:EDI) = client's SS:ESP

        sub     edi,(size iret32_s)             ; update client's ESP
        mov     [ebx].vsf_esp,edi               ; store updated client's ESP
        jc      rfierr                          ; no room, return error

        xchg    eax,[ebx].vsf_eip               ; (EAX) = EIP, set new EIP
        mov     iretframe.iret32_eip, eax
        xchg    cx,[ebx].vsf_cs                 ; (AX) = CS, set new CS
        mov     iretframe.iret32_cs, cx

        mov     eax,[ebx].vsf_eflag             ; (EAX) = flags

        test    [flVdmStatus], VDM_STATUS_VME   ; check for P5          ;BN016 begin
        jz      short rfi302
        test    eax, F_VIF                      ; copy VIF to IF
        jz      rfi301
        or      eax, F_INTERRUPT                ; set IF
        jmp     short rfi35
rfi301:
        and     eax, not F_INTERRUPT            ; clear IF
        jmp     short rfi35
rfi302:                                                                 ;BN016 end
        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG    ; virt if enabled?
        jnz     short rfi35                             ; yes, continue
        and     eax,NOT F_INTERRUPT                     ; clear int flag
rfi35:
        push    eax
        mov     iretframe.iret32_eflag, eax
        mov     pOffset, edi                    ; get client's SP
        SSToDS  eax, iretframe                  ; (ESI) = temp stack frame
        SSToDS  edi, pOffset                    ; (EDI) = ptr to client's SP

        PCall   VDHWriteUBuf, <eax, <size iret32_s>, DWORD PTR [ebx].vsf_ss, \
                               edi, VPM_SEL_IS_SS OR VPM_SEL_PRESENT OR      \
                               VPM_FAULT_IF_SU_SET>

        or      eax,eax                         ; everything OK?
        pop     eax
        jz      short rfierr                    ; no, exit

rfi40:
        and     ax,[esi].vpmint_usFlagMask              ; mask out flags

        btsx    ax,F_INTERRUPT                          ; test and set int flag
        jc      short rfi45
        push    FALSE
        jmp     short rfi50
rfi45:
        push    TRUE
rfi50:
        mov     [ebx].vsf_flag,ax                       ; save changed flags
        call    VDHChangeVPMIF

        leave                                   ; clean up stack frame
        jmp     em86CheckVPMBP                  ; check for any VPM BPs and EXIT

rfierr:
        xor     eax,eax                                 ; return error
        ExitProc

EndProc   EM86ReflectVPMInt
SWAP32_24 ends

SWAP32_12 segment
;***LP  em86IntHook - interrupt hook vdm breakpoint handler
;
;       This routine is called when the VDM BP address placed
;       in a interrupt vector table entry is executed.  This
;       happens at the end of the chain of V86 interrupt handlers.
;
;       ENTRY   (EDX) = pointer to apinthHead pointer (reference data)
;               (EBX) = pointer client register frame (pvsf)
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, FS, GS, Flags
;
;       CONTEXT VDM Task
;
;       NOTE    This routine depends on the em86opARPL routine
;               dispatching to this VDM BP routine with EDX and
;               EBX registers set appropriately.  This routine
;               ignores the stack base parameters and uses these
;               registers.  It still has to do the proper RET n
;               to clean off the stack.
;
;       PSEUDO-CODE
;
;       for each interrupt handler entry
;           call VDD int handler
;           if VDD return don't chain indication
;               break
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86IntHook,near
        SaveReg <esi>
        em86AssertPVSF ebx
        mov     esi,[edx]                       ; (ESI) = *pinthHead
        mov     esi,[esi]                       ; (ESI) = pinthHead
        and     esi,NOT 03h
        em86AssertP INTH, esi
eih10:  or      esi,esi                         ; end of linked list?
        jz      short eihx                      ;  yes, jump to exit
        cmp     [esi].inth_pfnhook,NULL         ; is it a postreflection hook?
        je      short eih20                     ; must be!
        cmp     [esi].inth_pfn,FLAToffset em86CHookStubINTH
        jne     short eih30                     ; nope!
eih20:  call    [esi].inth_pfn                  ; call VDD handler
        jnc     short eihx                      ; jump if no VDD chaining
        em86AssertP INTH, esi
eih30:  mov     esi,[esi].inth_pinth            ; (ESI) = next inth entry
        jmp     short eih10                     ;  no, jump to begining of loop

eihx:   RestoreReg <esi>
        ret     8                               ; clean off parameters
EndProc  em86IntHook
SWAP32_12 ends

SWAP32_12 segment
;***LP  em86CHookStubINTH - stub for "C" interface int hooks
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI = pointer to apinthHead entry (PINTH)
;
;       EXIT    if carry set (C function returns FALSE),
;                   chain to the next VDD
;               if carry clear (C function returns TRUE),
;                   don't chain to the next VDD
;
;       USES    EAX, ECX, EDX, FS, GS, Flags
;
;       CONTEXT VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86CHookStubINTH,near
        em86AssertP INTH, esi
        PCall   [esi].inth_pfnhook, <ebx>
        cmp     eax,1                           ; set carry if FALSE
        ret
EndProc   em86CHookStubINTH
SWAP32_12 ends

SWAP32_20 segment
;***LP  em86CHookStubPreINTH - stub for "C" interface pre-reflection int hooks
;
;       Note that this is an intentionally redundant routine.  We use
;       the stub address itself to help differentiate between pre-reflection
;       and post-reflection hooks, to save space in the INTH structures
;       allocated for *every* interrupt hook.
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI = pointer to apinthHead entry (PINTH)
;
;       EXIT    if carry set (C function returns FALSE),
;                   chain to the next VDD
;               if carry clear (C function returns TRUE),
;                   don't chain to the next VDD
;
;       USES    EAX, ECX, EDX, FS, GS, Flags
;
;       CONTEXT VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86CHookStubPreINTH,near
        em86AssertP INTH, esi
        PCall   [esi].inth_pfnhook, <ebx>
        cmp     eax,1                           ; set carry if FALSE
        ret
EndProc   em86CHookStubPreINTH
SWAP32_20 ends

SWAP32_18 segment
;***LP  em86CallPreIntHooks - Call pre-reflection interrupt hook(s)
;
;       ENTRY   EAX = interrupt number
;               EBX = pointer client register frame (CRF)
;
;       EXIT    Carry clear if interrupt was emulated, set if not
;
;       USES    ECX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86CallPreIntHooks,near,local
        mov     esi,apinthHead[eax*4]
        test    esi,INT_PRE_HOOK                ; pre-reflection hooks exist?
        jnz     short cph05                     ; yes
        stc
        ret

cph05:  SaveReg <eax>
        and     esi,NOT 03h                     ; strip flag bits from addr
        em86AssertP INTH, esi
cph10:  or      esi,esi                         ; end of linked list?
        stc
        jz      short cph30                     ; yes, jump to exit
        cmp     [esi].inth_pfnhook,NULL         ; is it a postreflection hook?
        je      short cph20                     ; yes, skip it
        cmp     [esi].inth_pfn,FLAToffset em86CHookStubINTH
        je      short cph20
        call    [esi].inth_pfn                  ; call VDD handler
        jnc     short cph30                     ; jump if call emulated
        em86AssertP INTH, esi
cph20:  mov     esi,[esi].inth_pinth            ; (ESI) = next inth entry
        jmp     short cph10                     ; no, jump to begining of loop

cph30:  RestoreReg <eax>
        ret
EndProc   em86CallPreIntHooks
SWAP32_18 ends

;***LP  em86VPMExcBPTerminate - VDM protected mode exception breakpoint handler
;
;       This routine gets control at the end of the VDM protected
;       mode exception chain via a VPM breakpoint.  The VDM is
;       terminated.
;
;       VOID PASCAL em86VPMExcBPTerminate();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = exception number + VPM_EXC_BP_START
;
;       EXIT    NONE
;
;       USES    EAX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       get exception number
;       display registers and terminated VDM
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86VPMExcBPTerminate,near
        sub     edi,VPM_EXC_BP_START
        CCall   TRAPProcessFatalFault, <edi, [ebx].vsf_errcode>
        ret
EndProc   em86VPMExcBPTerminate

;***LP  em86V86ExcBPTerminate - VDM V86 mode exception breakpoint handler;149007
;                                                                    ;149007
;       This routine gets control at the end of the VDM protected    ;149007
;       mode exception chain via a VPM breakpoint.  The VDM is       ;149007
;       terminated.                                                  ;149007
;                                                                    ;149007
;       VOID PASCAL em86V86ExcBPTerminate();                         ;149007
;                                                                    ;149007
;       ENTRY   (EBX) = pvsf                                         ;149007
;               (EDI) = exception number + VPM_EXC_BP_START          ;149007
;                                                                    ;149007
;       EXIT    NONE                                                 ;149007
;                                                                    ;149007
;       USES    EAX, ESI, EDI, Flags                                 ;149007
;                                                                    ;149007
;       CONTEXT VDM Task                                             ;149007
;                                                                    ;149007
;       PSEUDO-CODE                                                  ;149007
;                                                                    ;149007
;       get exception number                                         ;149007
;       display registers and terminated VDM                         ;149007
;                                                                    ;149007
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING ;149007
                                                                     ;149007
Procedure em86V86ExcBPTerminate,near                                 ;149007
        sub     edi,VPM_V86EXC_BP_START                              ;149007
        CCall   TRAPProcessFatalFault, <edi, [ebx].vsf_errcode>      ;149007
        ret                                                          ;149007
EndProc   em86V86ExcBPTerminate                                      ;149007

;***LP  em86VPMExcBPReflect - VDM protected mode exception breakpoint handler
;
;       This routine gets control at the end of the VDM protected
;       mode exception chain via a VPM breakpoint.  The exception
;       is reflected to V86 mode.
;
;       VOID PASCAL em86VPMExcBPReflect();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = exception number + VPM_EXC_BP_START
;
;       EXIT    NONE
;
;       USES    EAX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       get exception number
;       reflect as V86 interrupt
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86VPMExcBPReflect,near
        cmp     edi,VPM_V86EXC_BP_START         ; if it's a V86 INT? ;149007
        jc      eve01                           ; No, it's VPM       ;149007
                                                                     ;149007
        sub     edi,VPM_V86EXC_BP_START                              ;149007
        mov     eax,edi                         ; (EAX) = exception number;149007
        jmp     em86ReflectV86Int                                   ;149007

eve01:
        sub     edi,VPM_EXC_BP_START
        mov     eax,edi                         ; (EAX) = exception number
        jmp     EM86ReflectVPMInt

EndProc   em86VPMExcBPReflect

SWAP32_24 segment
;***LP  em86VPMIntBPHdlr - VDM protected mode interrupt breakpoint handler
;
;       This routine gets control at the end of the VDM protected
;       mode interrupt chain via a VPM breakpoint.  The interrupt
;       is reflected to V86 mode.
;
;       VOID PASCAL em86VPMIntBPHdlr();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = interrupt number
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       switch to V86 mode
;       arm return hook
;       reflect interrupt in v86 mode
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86VPMIntBPHdlr,near
        CCall   VDHSwitchToV86
        PCall   VDHArmReturnHook, <[hhookV86ReflectionHook], \
                                   VDHARH_RECURSIVE_CSEIP_HOOK>
        mov     eax,edi                         ; (EAX) = interrupt number
        jmp     em86ReflectV86Int
EndProc   em86VPMIntBPHdlr
SWAP32_24 ends


SWAP32_24 segment
;***LP  em86VPMInt2FHdlr - VDM protected mode interrupt 2F handler
;
;       This routine gets control when an Int 2Fh is executed in protect
;       mode app.  It tests if this is a get cpu mode request, and if so
;       clears the users AX register to indicate that the app is in VPM.
;
;       VOID PASCAL em86VPMInt2FHdlr();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = interrupt number
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if client's AX == 1686 then
;          clear client's AX register
;       else if client's AX == 4300 or 4310                             ;BN003
;          don't reflect interrupt to V86 mode                          ;BN003
;       else
;          reflect interrupt to V86 mode
;

Procedure em86VPMInt2FHdlr,near
        mov     ax,[ebx].vsf_ax                 ; get client's AX       ;BN003
        cmp     ax,1686h                        ; Query mode function   ;BN003
        je      SHORT VPMI2f_1686                                       ;BN003
        cmp     ax,INT2F_GETOS2VER              ; Get OS/2 version?     ;BN012
        je      SHORT VPMI2f_GETVER                                     ;BN012
        cmp     ax,INT2F_GETVDDAPI              ; Get VDD API Handler?  ;BN012
        je      SHORT VPMI2f_VDDAPI                                     ;BN012
        cmp     ax,4300h                        ; XMS Detect Call       ;BN003
        je      SHORT VPMI2f_Exit                                       ;BN003
        cmp     ax,4310h                        ; Get XMS Address Call
        je      SHORT VPMI2f_Exit
        jmp     short em86VPMIntBPHdlr          ;  no, reflect to V86 mode
VPMI2f_GETVER:                                                          ;BN012 begin
        mov     [ebx].vsf_ax,0
        mov     [ebx].vsf_bx,(MAJOR_VERSION * 100h) OR MINOR_VERSION
        mov     eax,TRUE
        jmp     short VPMI2f_ret
VPMI2f_VDDAPI:
        CCall   int2fGetVDDAPI, <ebx>           ; get VDD API handler
        mov     eax,TRUE
        jmp     short VPMI2f_ret                                        ;BN012 end
VPMI2f_1686:
        mov     [ebx].vsf_ax,0                  ; AX = 0 means in prot mode
VPMI2f_Exit:
        sub     eax, eax
VPMI2f_ret:
        ret
ExitProc

EndProc   em86VPMInt2FHdlr
SWAP32_24 ends

SWAP32_25 segment
;***LP  em86VPMInt21Hdlr - VDM protected mode INT 21 handler
;
;       This routine gets control at the end of the protected mode
;       INT 21 chain via a VPM breakpoint.
;
;       VOID PASCAL em86VPMInt21Hdlr();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = interrupt number (21)
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, FS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if DOS terminate (4c)
;          end VDM protected mode execution
;          reflect INT 21h to V86 mode
;       else
;          switch to V86 mode and reflect
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86VPMInt21Hdlr,near
        cmp     [ebx].vsf_ah,4ch                ; DOS terminate function?
        jne     TUNEBN                          ;  no, reflect to V86 mode
        NullContext <fs>,esi                    ; get rid of user's CS in FS
        CCall   em86EndVPMExecution             ; cleans up/switches to V86 mode
        mov     eax,21h                         ; now do the INT 21 in V86 mode
        jmp     em86ReflectV86Int
TUNEBN: jmp     em86VPMIntBPHdlr          ;  no, reflect to V86 mode
EndProc   em86VPMInt21Hdlr
SWAP32_25 ends

SWAP32_24 segment
;***LP  em86VPMInt31Hdlr - VDM protected mode INT 31 handler
;
;       This routine gets control at the end of the protected mode
;       INT 31 chain via a VPM breakpoint.
;
;       VOID PASCAL em86VPMInt31Hdlr();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = interrupt number (31H)
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, FS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86VPMInt31Hdlr,near
        push    ebx
        call    [_pfndpmInt31Rte]
        ret
EndProc   em86VPMInt31Hdlr
SWAP32_24 ends

SWAP32_24 segment
;***LP  em86V86ReflectionHook - V86 mode reflection return hook
;
;       ENTRY   (p) = reference data pointer
;               (pcrf) = pointer client register frame (CRF)
;
;       EXIT    NONE
;
;       USES    EAX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86V86ReflectionHook,near

ArgVar  vrh_p, PVOID
ArgVar  vrh_pcrf, PVOID

        EnterProc
        call    VDHSwitchToVPM
        ExitProc
EndProc   em86V86ReflectionHook
SWAP32_24 ends

SWAP32_19 segment
;***LP  em86VPMReflectionHook - VPM mode reflection return hook
;
;       ENTRY   (p) = reference data pointer
;               (pcrf) = pointer client register frame (CRF)
;
;       EXIT    NONE
;
;       USES    EAX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if int 24
;          free the selector we allocated for device header
;          Save client action code (AL)
;          restore the registers
;          if client action code (AL) = 2
;             set client action code (AL) = 3
;          restore client's action code (AL)
;       else
;          if client left flags on stack
;             increment user's stack pointer
;       switch back to the regular VPM stack
;       switch to V86 mode

Procedure em86VPMReflectionHook,near,,,esp

ArgVar  vrh_p, PVOID
ArgVar  vrh_pcrf, PVOID

        EnterProc
        SaveReg <esi>

        mov     eax, ulClientESP                ; Get client's ESP value
        or      eax,eax                         ; Z  -> Int 24
        jnz     short VPMRef_10                 ; NZ -> Int 23

        mov     eax,[ebx].vsf_ebp               ; get selector we allocated
        CCall   em86FreeSel, <eax>              ; free it               ;BC013
        mov     edx,[ebx].vsf_eax               ; get client's action code
;BD009  PCall   VDHPopRegs, <VDHREG_ALL AND NOT VDHREG_FLAG>    ; restore regs
        SaveReg <edx>                                                   ;BN009 begin
        mov     esi, [ebx].crf_eflag            ; Get current flags
        PCall   VDHPopStack, <<size crf_s>, ebx>  ; restore regs
        and     [ebx].crf_eflag, NOT (F_NT + F_RF + F_IOPL3 + F_INTERRUPT)
        and     esi, (F_NT + F_RF + F_IOPL3 + F_INTERRUPT)
        or      [ebx].crf_eflag, esi            ; restore current flags
        PCall VDHSETFLAGS, <[ebx.crf_eflag]>    ; kernel will set virt int flag
                                                ;149007
        RestoreReg <edx>                        ;BN009 end

        cmp     edx,2                           ; check for terminate code
        jne     short VPMRef_05                 ; nope, skip ahead
        mov     edx,3                           ; change it to a fail

VPMRef_05:
        mov     [ebx].vsf_eax,edx               ; restore client's action code
        jmp     short VPMRef_20

VPMRef_10:
        cmp     [ebx].vsf_esp,eax               ; did they leave flags
        je      short VPMRef_20                 ; nope, skip ahead

        mov     eax,2                           ; we'll pop at least a word
        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?
        jz      short VPMRef_15                 ; no, only pop 1 word
        mov     eax,4                           ; pop a DWORD

VPMRef_15:
        add     [ebx].vsf_esp,eax               ; pop (e)flags off stack

VPMRef_20:
        PCall   VDHEndUseVPMStack               ; switch back to normal stack

        PCall   VDHSwitchToV86                  ; return to V86 mode
        RestoreReg <esi>
        ExitProc
EndProc   em86VPMReflectionHook
SWAP32_19 ends


SWAP32_25 segment
;***LP  em86VPMExcRetHook - VPM mode exception return hook
;
;       This hook gets control after a DPMI client returns from it's exception
;       handler.
;
;       ENTRY   (p) = reference data pointer
;               (pcrf) = pointer client register frame (CRF)
;
;       EXIT    NONE
;
;       USES    EAX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       switch back to the regular VPM stack
;       if 16 bit app
;          get 16 bit parameters
;       else if 32 bit app
;          get 32 bit parameters
;       set virt int flag to match whatever handler set real int flat to
;       set real int flag on
;       if V86 bit set in flrestart, switch to client to V86 mode
;

Procedure EM86VPMExcRetHook,near

ArgVar  vrh_p, PVOID
ArgVar  vrh_pcrf, PVOID
LocalVar pOffset, DWORD
LocalVar excstret, EXC32

        EnterProc

        mov     ebx, vrh_pcrf                   ; (EBX) = PCRF
        movzx   edx,[ebx].vsf_ss                ; (EDX) = client's SS   ;BC005
        mov     eax,[ebx].vsf_esp               ; (EAX) = DPMI exc struc;BC005

        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?   ;BN005
        jnz     short erh05                     ; yes                   ;BN005

        mov     ecx,size excst_s                ; 16 bit exception structure ;BN005
        movzx   eax,ax                          ; clear top half of ESP ;BN005
        jmp     short erh10

erh05:
        mov     ecx,size exc32_s                ; 32 bit exception structure ;BN005

erh10:
        mov     pOffset, eax                    ; set up ptr for read           ;BN005
        lea     edi,excstret                    ; get pointer to buffer ;BN005
        SSToDS  edi                             ; convert to flat       ;BN005
        lea     eax,pOffset                     ; get linear address of offset  ;BN005
        SSToDS  eax

        ; set up parameters for VDHReadUBuf call
        push    edi                             ; push ptr to destination buff
        push    ecx                             ; push number of bytes to read
        push    edx                             ; push client's SS
        push    eax                             ; push ptr to offset
        push    0                               ; push ReadUBuf flags
        call    VDHEndUseVPMStack               ; switch back to normal stack   ;BN005

        ; read in the changed exception stack info (params pushed above)
        call    VDHReadUBuf                                             ;BN005
        or      eax,eax                         ; any errors?           ;BN005
        jnz     short erhOK                     ; no, continue          ;BN005

        movzx   eax,[ebx].vsf_ss                ; (EAX) = client's SS
        CCall   TRAPProcessFatalFault, <0dh, eax> ; issue hard error (trap 0xD)
        jmp     short erh50                     ; exit                  ;BN005

erhOK:
        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; 32 bit application?
        jnz     short erh25                     ; yes, skip ahead to 32 bit

;       16 Bit DPMI exception stack
        mov     ax,[edi].excst_ip               ; get changed IP
        mov     [ebx].vsf_ip,ax
        mov     ax,[edi].excst_cs               ; get changed CS
        mov     [ebx].vsf_cs,ax
        mov     eax,[ebx].vsf_eflag             ; get flags
        mov     ax,[edi].excst_flags            ; get changed flags
        PCall   VDHSETFLAGS, <eax>              ; let them adjust the flags
                                                ;149007
        mov     ax,[edi].excst_sp               ; get changed SP
        mov     [ebx].vsf_sp,ax
        mov     ax,[edi].excst_ss               ; get changed SS
        mov     [ebx].vsf_ss,ax
        jmp     short erh40

erh25:
;       32 Bit DPMI exception structure
        mov     eax,[edi].exc32_eip             ; get changed EIP
        mov     [ebx].vsf_eip,eax
        mov     ax,[edi].exc32_cs               ; get changed CS
        mov     [ebx].vsf_cs,ax
        mov     eax,[edi].exc32_eflags          ; get changed flags
        PCall   VDHSETFLAGS, <eax>              ; let user adjust flags
                                                ;149007
        mov     eax,[edi].exc32_esp             ; get changed ESP
        mov     [ebx].vsf_esp,eax
        mov     ax,[edi].exc32_ss               ; get changed SS
        mov     [ebx].vsf_ss,ax

erh40:
;BD005  FlatContext <es>,eax                    ; restore ES for flatcontext
        btr     flrestart,VPM_RETV86_BIT        ; V86 flag set?
        jnc     short erh50                     ; no, just exit
        call    VDHSwitchToV86                  ; switch to V86 mode
erh50:
        ExitProc
EndProc   EM86VPMExcRetHook
SWAP32_25 ends

;***LP  VPMIntDispatcher - VDM protected interrupt dispatcher
;
;       This routine gets control when a DPMI application issues an
;       Int 23 or 24 via an interrupt hook.
;
;       VOID PASCAL VPMIntDispatcher();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = interrupt number (21)
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, FS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if not DPMI application set carry and exit (to chain to next handler)
;       if not the default handler
;          switch VDM to VPM mode
;          switch to locked stack
;          if int 24
;             save client registers
;             allocate selector for device header
;             set client's BP to new selector
;          else
;             save client's ESP in ulClientESP
;          Arm the return hook for user's int handler
;          push the interrupt (23 or 24)

Procedure VPMIntDispatcher, near
LocalVar sel, SEL
LocalVar usIntNum, WORD
        EnterProc
        testb   [flVdmStatus],VDM_STATUS_VPM_APP ; see if it's a DPMI app
        jz      vpm40                            ; not DPMI app, skip to next handler ;BC001

        mov     usIntNum, ax                     ; save away int number      ;72717 (moved)

        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC ; see if it's in prot mode ;72717
        jnz     short int_to_vpm                  ; yes, protect mode int    ;72717

        cmp     usIntNum,23h                      ; int 23?                  ;72717
        jne     short int_to_vpm                  ; no, so chk vpm hooks.    ;72717

        push    eax                               ; save eax                 ;72717
        mov     eax,[eax*4]                       ; (EAX)=addr from int23 vec;72717
        cmp     eax,vpOurV86Int23vect             ; em86vpm.c                ;72717
        pop     eax                               ; restore eax              ;72717
        jne     vpm40                             ; reflect to real mode.    ;72717

int_to_vpm:

        ; Get the interrupt entry from prot mode IDT
        mov     usIntNum, ax                    ; save away int number

        PCall   VDHCheckVPMIntVector, <eax>     ; is it hooked?
        or      eax,eax
        jz      vpm30                           ; no, not hooked

        PCall   VDHSwitchToVPM                  ; switch to prot mode

        PCall   VDHBeginUseVPMStack             ; use locked stack

        cmp     usIntNum,23h                    ; int 23?
        je      short vpm10                     ; nope, don't convert dev header

        movzx   edi,[ebx].vsf_bp                ; get segment

;BD009  PCall   VDHPushRegs, <VDHREG_ALL AND NOT VDHREG_FLAG>   ; save registers
        PCall   VDHPushStack, <<size crf_s>, ebx>   ; save CRF           BN009
        or      eax,eax                         ; error?
        jz      short vpm30                     ; yes, exit

        shl     edi,4                           ; convert to linear address

        mov     sel,-1                          ; get any selector
        lea     eax,sel                         ; get addr of sel
        SSToDS  eax                             ; convert to flat
        movzx   ecx,[ebx].vsf_si                ; get offset
        mov     [ebx].vsf_esi,ecx               ; zero out high word
        add     ecx,18                          ; limit = off + size dev header
        CCall   em86AllocSel, <edi, ecx, eax, D_DATA3, 0>               ;BN013
        or      eax,eax                         ; error?
        jz      short vpm40                     ; if zero -> error
        movzx   eax,sel                         ; EAX = new selector
        mov     [ebx].vsf_ebp,eax               ; update client's BP to new sel
        mov     ulClientESP,0                   ; clear for post routine
        jmp     short vpm20

vpm10:
        mov     eax,[ebx].vsf_esp               ; get current ESP value
        mov     ulClientESP,eax                 ; save for post routine

vpm20:
        ; arm recursive CSEIP return hook
        PCall   VDHArmReturnHook, <[hhookVPMReflectionHook], \
                                   VDHARH_RECURSIVE_CSEIP_HOOK>

        movzx   eax,usIntNum                    ; get interrupt number
        PCall   VDHPushInt, <eax>               ; call protect mode handler
        clc                                     ; don't chain to next handler
        jmp short vpmExit

vpm30:
;BD011  cmp     usIntNum, 23h                   ; CTRL C?                        ;BN001
;BD011  jne     short vpm40                     ; if not, chain to next handler  ;BN001
;BD011  CCall   em86EndVPMExecution             ; cleans up/switches to V86 mode ;BN001

vpm40:
        stc                                     ; chain to next handler
vpmExit:
        ExitProc
EndProc VPMIntDispatcher
;***EP  EM86Int23Hook - int 23 hook                                     ;BN011
;
;       This routine gets control at the end of the int 23 chain.
;
;       VOID PASCAL EM86Int23Hook();
;
;       ENTRY   (EBX) = pvsf
;               (EDI) = interrupt number (21)
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, FS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       end VPM mode
;       chain to original int 23 vector

Procedure EM86Int23Hook, near                                           ;BN011
ArgVar  vrh_p, PVOID
ArgVar  vrh_pcrf, PVOID
        EnterProc
        mov     ebx,vrh_pcrf                    ; EBX = pointer to CRF

        CCall   em86EndVPMExecution             ; exit protect mode

        mov     eax, vpV86Int23vect             ; chain to old int 23 handler
        mov     [ebx].vsf_ip, ax                ; set IP
        shr     eax,16                          ; get segment
        mov     [ebx].vsf_cs, ax                ; set CS

        ExitProc
EndProc EM86Int23Hook

EndCode

        end
