SCCSID equ "@(#)em86if.asm      6.10 92/03/16"

PAGE    ,132
TITLE   EM86IF.ASM - IF Instruction 8086 Emulation
NAME    EM86IF
.386p

;***    EM86IF.ASM
;
;        Version 1.18.2.2, for src/dos/mvdm/em86if.asm, em86, mer.krnl, 960610.1
;
;       Title:
;
;       8086 emulation support for IF instructions
;
;       Description:
;
;       This module contains the emulation routines for all the
;       IF instructions (CLI, STI, PUSHF, POPF, IRET) executed
;       only when IOPL < 3.
;
;       Public routines:
;
;       EM86DispatchSTIHooks
;       em86opPUSHF
;       em86opPOPF
;       em86opIRET
;       em86opCLI
;       em86opSTI
;       em86PopVPMIRET
;
;       Modification History:
;
;       07-31-91        Bill Madden     PTR B725180
;         Fixed to always use virtual int flag for DPMI apps.
; 6.5   09/15/91  CP20 B726841  Jeff Muir  Delete IOPL property
;       09-25-91        Bill Madden     DCR 1531
;         Fixed em86PopVPMIRET to use VDHReadUBuf to access user stack.
; Bx001 03-08-92        Bill Madden     PTR AZ09818
;         Added cli and sti to em86SetFlags
; Bx002 07-10-92        Bill Madden     DEF 24741
;         Insure DPMI apps always have IOPL = 2
; Bx003 08-17-92        Bill Madden     DEF 46529
;         Changed em86EnabledInterrupts to always set TK_FF_STIH if ints enabled
; Bx004 09-03-92        Bill Madden     DEF 53580
;         Changed em86SetFlags to clear STI hook force flag if ints disabled
; Bx005 03-20-93        Jon Grimm
;         Added MMIO perf hooks to VDHSetFlags
; Bx006 03-24-93        Bill Madden     DEF 63842
;         Added P5 support.
; Bx007 08-31-93        Bill Madden     DEF 73423
;         Removed EM86STITest
; Bx008 10-13-93        Bob Zybach      DEF 73166
;         Added P5 support.
; Bx009 10-28-93        Bob Zybach
;         Minor P5/VME/DPMI fix.
; 93273 11-AUG-1994   ChangeTeam
;         Added VDHGetFlags and em86GetFlags
;       09-19-94        bjn
;         Changed segment names for page tuning
; 94571 14-SEP-1994   ChangeTeam
;         Added check for protect mode to em86opIRET.
; 92699 29-SEP-1994   ChangeTeam (Bob Zybach)
;         Fixed hole in em86SetFlags which a DPMI/VME case would not mask
;         out all the flags (except IOPL and Trace) in the current vsf_eflags
;         before OR'ing in the new given eflags value.
; 17  NOV 94  Merged defects 94571 and 92699  from r206 to r207  ChangeTeam
;
; 108549 18-JAN-95    ChangeTeam (Vincent Villamizar)
;         Removed code which ignored all high word flags in EFLAG. em86opPUSHF

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
        include mmpha.inc
.list
        ModName  em86if, FNO_EM86IF_ASM

        CpuMode 386

DefCode EXPORT, SWAP, PASCAL
DefFn   em86POPF16
DefFn   em86SetFlags
DefFn   em86GetFlags
DefFn   em86EnabledInterrupts
DefFn   VDHSetFlags       ;149007
EndCode

DefCode EXPORT, SWAP
DefFn   em86PopVPMIRET
EndCode

DefCode EXPORT, GLOBAL
;BD007 DefFn   EM86STITest
DefFn   EM86DispatchSTIHooks
EndCode


DefData IMPORT, SWAPINST
ULONG   flPrefix                                ; in em86inst.asm
EndData

DefData IMPORT, SWAPINST, C
PVOID   pvdmArpl                                ; em86.c
ULONG   flVdmStatus                             ; em86vpm.c
SEL     selVPMBP                                ; em86vpm.c
EndData

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

DefData IMPORT, GLOBAL, C
PVOID   pTCBCur                                 ; tk
EndData


DefCode IMPORT, GLOBAL, PASCAL
DefFn   VDHAssertVDMTaskOnly                    ; vdmm
DefFn   VDHReadUBuf                             ; em86vpmx.c
EndCode

DefCode IMPORT, GLOBAL
DefFn   KMDispatchHook                          ; km
EndCode

DefCode IMPORT, SWAP
DefFn   em86CheckVDMBP                          ; em86misc.asm
DefFn   em86CheckVPMBP                          ; em86misc.asm
DefFn   em86opGPFault                           ; em86inst.asm          ;94571
EndCode

;**     IF simulation routine equates
;
;       This are the flags that are forced on or off when emulating
;       a POPF instruction.  The IRET instruction basicly does a POPF
;       for the flags so the emulation routine uses the POPF_OFF/POPF_ON
;       equates also.

POPF_OFF        equ     (not (0FFFF0000H + F_NT + F_IOPL3))
POPF_ON         equ     (F_VM)

P5_POPF_OFF     equ     (not (0FFC00000H + F_IOPL3))                    ;BN006

VPM_POPF_OFF    equ     (not (0FFFF0000H + F_NT + F_IOPL3))
VPM_POPF_ON     equ     (0)

P5_VPM_POPF_OFF     equ     (not (0FFC00000H + F_IOPL3))                ;BN009

        FARCODE HIGH32
DefCode PRIVATE, GLOBAL, PASCAL

;***EP  EM86STITest - Check if interrupts enabled and STI hook
;
;       ENTRY   EAX - Force Flags
;       ENTRY   ESI = pPTDACur
;               EDI = pTCBCur
;
;       EXIT    EAX - Force Flags - might have TK_FF_STIH removed
;
;       USES    EAX, EBX
;
;       PSEUDO-CODE
;       If interrupts Disabled
;          Ignore TK_FF_STIH this time
;       else continue

;BD007 Procedure EM86STITest, near
;BD007        test    eax,TK_FF_STIH          ; VDM STI Hook pending?
;BD007        jz      short sti020            ; No-> continue as normal
;BD007
;6.5    test    vdmid_flVDM,VDM_IOPL3   ; is VDM forced to stay at IOPL3?
;6.5    jz      short sti020            ; no, handle STI force flag normally
;BD007        jmp     short sti020            ; no, handle STI force flag normally
;BD007
;BD007        mov     ebx,[pvsfFrameBase]     ; (EBX) = pvsf
;BD007        test    [flVdmStatus], VDM_STATUS_VME   ; Check if on P5        ;BN006
;BD007        jz      sti005                          ; No -> normal proc.    ;BN006
;BD007
;BD007        test    [ebx].vsf_eflag,F_VIF           ; virtual IF enabled?   ;BN006
;BD007        jz      sti010                          ; No -> leave FF        ;BN006
;BD007        jmp     sti020                                                  ;BN006
;BD007sti005:
;BD007
;BD007        test    [ebx].vsf_eflag,F_INTERRUPT     ; Interrupts Enabled ?
;BD007        jz      short sti010                    ; No -> leave FF for next time
;BD007
;BD007        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC       ; in VPM mode?
;BD007        jz      short sti020                            ; no, process FF
;BD007
;BD007        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG    ; virtual int enabled?
;BD007        jnz     short sti020                            ; yes, process FF
;BD007
;BD007sti010:
;BD007        and     eax,not TK_FF_STIH      ; No -> leave the FF for next time
;BD007sti020: ret
;BD007EndProc   EM86STITest

;***EP  EM86DispatchSTIHooks - Process STI hooks
;
;       ENTRY   ESI = pPTDACur
;               EDI = pTCBCur
;
;       EXIT    NONE
;
;       USES    EAX, EBX, ECX, EDX, ESI, EDI, FS, GS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       set iopl to 3 (disables IF instruction trapping)
;       call each VDD hook handler on stih list
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure EM86DispatchSTIHooks,near
        em86AssertVSF pTCBCur
        clrb    [edi].TCBForcedActions,TK_FF_STIH
        mov     ebx,[pvsfFrameBase]             ; (EBX) = pvsf
        mov     edi,offset FLAT:hookheadSTIH    ; (EDI) = hook head address
        add     edi,[vdmid_HVDM]                ; (EDI) = hvdm relative pointer
        jmp     KMDispatchHook                  ; go dispatch hooks
EndProc   EM86DispatchSTIHooks

EndCode

        FARCODE HIGH32
DefCode PRIVATE, SWAP, PASCAL
SWAP32_12 segment
;***EP  VDHSetFlags - sets the VDM's flags to the specified value
;
;       VDDs must use the interface to change the VDM's flags instead
;       of using the CRF pointer.  Changes to the interrupt flag and
;       the IOPL field must be under the control of 8086 emulation so
;       VDHArmSTIHook works correctly.
;
;       The NT and RF flags are cleared, the VM flag is set and
;       the IOPL field is left unchanged.
;
;       ENTRY
;           ulFlags
;               VDM flag value
;
;       EXIT
;           None.
;
;       VDM TERMINATION IMPLICATIONS
;           None.
;
;       CONTEXT
;           VDM Task
;
;       NOTES
;           (1) This call does not take effect until OS/2 returns to V86 mode.
;
;       PSEUDO-CODE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure VDHSetFlags,near

ArgVar  ulFlags,DWORD

        EnterProc
        SaveReg <ebx, esi, edi>
        ASSERTVDMTASKONLY
        mov     ebx,[pvsfFrameBase]             ; (EBX) = pvsf
        em86AssertVSF pTCBCur
        mov     eax,[ulFlags]                   ; (EAX) = flags to be set
        MMPHPreVDHSetFlags      eax
        call    em86SetFlags
        MMPHPostVDHSetFlags
        RestoreReg <edi, esi, ebx>
        ExitProc
EndProc   VDHSetFlags
SWAP32_12 ends

;***EP  VDHGetFlags - gets the VDM's flags
;
;       VDDs must use the interface to get the VDM's flags instead
;       of using the CRF pointer.  Changes to the interrupt flag and
;       the IOPL field must be under the control of 8086 emulation so
;       VDHArmSTIHook works correctly.  Getting the interrupt flag must
;       be under 8086 emulation control due to VME (virtual mode extensions)
;       and DPMI.
;
;
;       *** ADDED FOR DEFECT 93273 ***
;
;       ENTRY
;           pulEFlags = addr to store eflags (ptr to ulong)
;
;       EXIT
;           pulEFlags = client's eflags
;
;       VDM TERMINATION IMPLICATIONS
;           None.
;
;       CONTEXT
;           VDM Task
;
;       PSEUDO-CODE
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure VDHGetFlags,near

ArgVar  pulEFlags,DWORD

        EnterProc
        SaveReg <ebx, ecx, esi, edi>
        ASSERTVDMTASKONLY
        mov     ebx,[pvsfFrameBase]                ; (EBX) = pvsf
        em86AssertVSF pTCBCur
        mov     ecx,pulEFlags                      ; ECX = addr to store EFLAGS
;;TRACE LATER?        MMPHPreVDHGetFlags      ecx  ;
        call    em86GetFlags
;;TRACE LATER?        MMPHPostVDHGetFlags
        RestoreReg <edi, esi, ecx, ebx>
        ExitProc
EndProc   VDHGetFlags

;***LP  em86GetFlags - get client's eflags into [ecx]
;
;       *** ADDED FOR DEFECT 93273 ***
;
;       ENTRY   EBX = pointer to client register frame (CRF)
;               ECX = addr of ulong to place eflags into  (ptr to ulong)
;
;       EXIT    [ECX] = client's eflags
;
;       USES    ECX
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       get client's eflags (from CRF) into eax
;       IF DPMI app
;           place VPM_IF_FLAG value into IF
;       ELSE
;           IF VME enabled
;               place VIF value into IF
;           ENDIF
;       ENDIF
;       place eflags into [ecx]
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86GetFlags,near

        push    eax
        mov     eax,[ebx].vsf_eflag                  ; (EAX) = client's eflags

        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC    ; is this a DPMI app?
        jz      egf010                               ; no - go check for VME

        ;DPMI app - get IF from VPM_IF_FLAG
        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG ;VPM IF set?
        jz       egfClrIF                            ;no - clear IF flag
        jmp      short egfSetIF                      ;yes - set IF flag

        ;
        ;  If VME is enabled, then save the VIF state in the IF Flag.
        ;
egf010:
        test    [flVdmStatus], VDM_STATUS_VME        ; VME Supported?
        jz      egf020                               ; No - EFLAGS ready
        test    eax, F_VIF                           ; VIF Set?
        jz      egfClrIF                             ; No - Clear IF

egfSetIF:
        or      eax, F_INTERRUPT                     ; Set IF
        jmp     short egf020

egfClrIF:
        and     eax, not F_INTERRUPT                 ; Clear IF

egf020:
        mov     [ecx],eax                            ;store client's eflags

        pop     eax
        ret
EndProc   em86GetFlags

;***LP  em86opPUSHF - Emulate push flags IOPL sensitive instruction
;
;       This function emulates the push flags IOPL sensitive
;       instruction.  It called by the opcode decoder for the
;       PUSHF/PUSHFD instructions.
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI+EDI = pointer to faulting opcode
;               Client's CS:IP points to faulting opcode
;               [flPrefix] = instruction prefix flags
;
;       EXIT    NONE
;
;       USES    EAX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       get pointer to client's stack
;       get client's flags
;       mask off VM, RF and IF bits
;       adjust client's stack pointer based on operand override
;       put flags/eflags on client's stack
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

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

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

        ;                                                                 ;BN008
        ;  If VME is enabled, then save the VIF state in the IF Flag.     ;BN008
        ;                                                                 ;BN008
        test    [flVdmStatus], VDM_STATUS_VME   ; VME Supported?          ;BN008
        jz      @F                              ; No - Normal PUSHF       ;BN008
        test    eax, F_VIF                      ; VIF Set?                ;BN008
        jz      ClearIF                         ; No - Clear IF           ;BN008
        or      eax, F_INTERRUPT                ; Set IF                  ;BN008
        jmp     short @F                                                  ;BN008
ClearIF:                                                                  ;BN008
        and     eax, not F_INTERRUPT            ; Clear IF                ;BN008
@@:                                                                       ;BN008

        testb   [flPrefix],PREFIX_OPER32        ; is this a pushfd?
        jnz     short epu10                     ;  yes, jump to push eflags

;       Must decrement DI (16 bits) instead of EDI to handle
;       stack wrapping correctly.

        sub     di,2                            ; adjust client's SP
        mov     [ebx].vsf_sp,di
        mov     [esi+edi],ax                    ; put flags on client stack
        ret

epu10:  sub     di,4                            ; adjust client's SP
        mov     [ebx].vsf_sp,di

;NOTE: If we want to maintain any processor specific reserved          ;108549
;      registers, etc, we should do that when popping. em86opPOPF.     ;108549
; movzx   eax,ax                         ; all high word flags ignored ;108549

        mov     [esi+edi],eax                   ; put eflags on client stack
        ret
EndProc   em86opPUSHF

;***EP  em86POPF16 - emulate a 16 bit popf instruction
;
;       This routine is called by C code to emulate a 16 bit
;       popf instruction.  It has PASCAL calling conventions.
;
;       ENTRY   NONE
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, FS, GS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       get VSF pointer from tcb
;       call em86popf16 entry
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86POPF16,near
        SaveReg <ebx, esi, edi>
        mov     ebx,[pvsfFrameBase]             ; (EBX) = pvsf
        em86AssertVSF pTCBCur
        call    em86POPF16Entry                 ; pop flags off of stack
        RestoreReg <edi, esi, ebx>
        ExitProc
EndProc   em86POPF16

;***LP  em86opPOPF - Emulate pop flags IOPL sensitive instruction
;***LP  em86POPF16Entry - entry for em86POPF16
;
;       This function emulates the pop flags IOPL sensitive
;       instruction.  It called by the opcode decoder for the
;       POPF/POPFD instructions.
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI+EDI = pointer to faulting opcode
;               Client's CS:IP points to faulting opcode
;               [flPrefix] = instruction prefix flags
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       NOTE    This routine may change the IOPL to 0.
;
;       PSEUDO-CODE
;
;       get pointer to client's stack
;       get flags/eflags from client's stack
;       adjust client's stack pointer based on operand override
;       force NT and RF flags off and IOPL = 0
;       force VM flag on
;       put into client's flag register
;       if IF in flags from client's stack is set
;           jump to em86EnabledInterrupts
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

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

        testb   [flPrefix],PREFIX_OPER32        ; is this a popfd?
        jnz     short epo10                     ;  yes, jump to pop eflags

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

        movzx   eax,[esi+edi].loword            ; (EAX) = flags on client stack
        add     [ebx].vsf_sp,2                  ; adjust client's SP
        jmp     em86SetFlags

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

        mov     eax,[esi+edi]                   ; (EAX) = eflags on client stack
        add     [ebx].vsf_sp,4                  ; adjust client's SP
        jmp     em86SetFlags
EndProc   em86opPOPF

;SWAP32_12 segment  ;*************************************
;***LP  em86opIRET - Emulate return from interrupt IOPL sensitive instruction
;***LP  em86IRET16 - Entry that emulates 16 bit IRET for VDHPopInt
;
;       This function emulates the return from interrupt IOPL sensitive
;       instruction.  It called by the opcode decoder for the IRET/IRETD
;       instructions.
;
;       ENTRY   EBX = pointer client register frame (CRF)
;               ESI+EDI = pointer to faulting opcode
;               Client's CS:IP points to faulting opcode
;               [flPrefix] = instruction prefix flags
;
;       EXIT    NONE
;
;       USES    EAX, ECX, EDX, ESI, EDI, Flags
;
;       CONTEXT VDM Task
;
;       NOTE    This routine may change the IOPL to 0.
;
;       PSEUDO-CODE
;
;       if no operand size override
;           get pointer to client's stack pointer
;           adjust client's stack pointer (3 words)
;           move IP from stack to client's IP register
;           move CS from stack to client's CS register
;           get flags from stack
;       else
;           get pointer to client's stack pointer
;           adjust client's stack pointer (3 dwords)
;           move EIP from stack to client's EIP register
;           move CS from stack to client's CS register
;           get eflags from stack
;       force NT and RF flags off and IOPL = 0
;       force VM flag on
;       put into client's flag register
;       if IF in flags from client's stack is set
;           em86EnabledInterrupts()
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86opIRET,near
        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC; protect mode?        ;94571
        jnz     em86opGPFault                   ;  yes, jump to gpfault ;94571
        inc     edi
        mov     [ebx].vsf_eip,edi               ; adjust EIP

        testb   [flPrefix],PREFIX_OPER32        ; is this a iretd?
        jnz     eir110                          ;  yes, jump to iretd code

;       16 bit IRET frame

Entry   em86IRET16,near
        em86AssertPVSF ebx
IFDEF   EM86STRICT
        movzx   esi,[ebx].vsf_cs                ; (ESI) = client's CS
        shl     esi,4                           ; (ESI) = linear CS
        add     esi,[ebx].vsf_eip               ; (ESI) = linear CS:EIP
        cmp     esi,[pvdmArpl]                  ; is the new CS:IP a VDM BP?
        jne     short eir10                     ;  no, don't print anything
        Panic   <"em86IRET16: CS:IP is a VDM BP">
ENDIF
eir10:  movzx   esi,[ebx].vsf_ss                ; (ESI) = client's SS
        shl     esi,4                           ; (ESI) = linear SS
        movzx   edi,[ebx].vsf_sp                ; (EDI) = client's SP

        add     [ebx].vsf_sp,(size iret16_s)    ; adjust client's SP
        movzx   eax,[esi+edi].loword            ; (EAX) = IP from IRET frame
        mov     [ebx].vsf_eip,eax               ; set client's IP
        add     di,2

        mov     ax,[esi+edi]                    ; (AX) = CS from IRET frame
        mov     [ebx].vsf_cs,ax                 ; set client's CS
        add     di,2
        movzx   eax,[esi+edi].loword            ; (EAX) = flags from IRET frame
eir20:  call    em86CheckVDMBP                  ; check for VDM BP's

;       Set client's flags and check if interrupts were enabled.  Preserves
;       the IOPL field and trace flag state.

Entry   em86SetFlags,near

;                                                                       ;92699
;       Preserve only the IOPL and Trace state of the current eflags    ;92699
;       in the VSF.  This value will be OR'ed with the given eflags     ;92699
;       value later in em86SetFlags.                                    ;92699
;                                                                       ;92699
        andb    [ebx].vsf_eflag,%(F_IOPLMASK + F_TRACE)                 ;92699

        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC ; is this a DPMI app?
        jnz     eir60

;92699        andb    [ebx].vsf_eflag,%(F_IOPLMASK + F_TRACE)

        test    [flVdmStatus], VDM_STATUS_VME   ; check if P5           ;BN006 begin
        jz      short eir50

        and     eax, P5_POPF_OFF                ; force off some flags
        or      eax, POPF_ON                    ; force on some flags
eirVME:
        pushfd                                  ; save flags
        cli                                     ; disable ints
        test    eax, F_INTERRUPT                ; copy of VIF from IF
        jz      short eir30

        orb     [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
        or      eax, F_VIF                      ; Set VIF bit
        jmp     short eir40
eir30:
        and     eax,not F_VIF                   ; clear VIF bit
        mov     esi,offset FLAT:hookheadSTIH    ; (ESI)=hook head address ;BN008
        add     esi,[vdmid_HVDM]                ; (ESI)=hvdm relative ptr ;BN008
        cmp     [esi].hook_dll.dll_pdllNext,esi ; Any pending Ints?       ;BN008
        je      short eir35                     ; No                      ;BN008
        or      eax,F_VIP                       ; Yes, Set VIP Flag       ;BN008
eir35:                                                                    ;BN008
        or      eax,F_INTERRUPT                 ; enable Phys interrupt   ;BN008
        clrb    [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
eir40:
        or      [ebx].vsf_eflag, eax
        popfd                                   ; restore flags
        test    eax, F_VIF                      ; check IF status
        jz      short eir100
        jmp     em86EnabledInterrupts                                   ;BN006 end

eir50:
        and     eax, POPF_OFF                   ; force off some flags
        or      eax, POPF_ON                    ; force on some flags
        or      [ebx].vsf_eflag,eax             ; set client's flags
        test    eax,F_INTERRUPT                 ; are interrupts enabled?
        jz      short eir100                    ; no, return
        jmp     em86EnabledInterrupts           ; do STI processing

eir60:
        test    [flVdmStatus], VDM_STATUS_VME   ; check if P5           ;BN006
        jz      short eir70                                             ;BN006

        and     eax, P5_POPF_OFF                ; force off some flags
        jmp     short eirVME
eir70:
        and     eax,VPM_POPF_OFF                ; force off some flags
        pushfd                                  ; save flags            BN001
        cli                                     ; disable ints          BN001
        btsx    eax,F_INTERRUPT                 ; get IF status and set it
        jnc     short eir80
        orb     [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
        jmp     short eir90
eir80:
        clrb    [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
eir90:
;92699        andb    [ebx].vsf_eflag,%(F_IOPLMASK + F_TRACE)

        or      [ebx].vsf_eflag,eax             ; set client's flags
        popfd                                   ; restore flags         BN001
        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG    ; virtual int enabled?
        jnz    Tune1 ; em86EnabledInterrupts           ;  yes, do sti hook processing

eir100:
        mov     esi,[_pTCBCur]                  ; clear STI force flag  ;BN004
        clrb    [esi].TCBForcedActions,TK_FF_STIH                       ;BN004
        ret                                     ;  no, exit

;       32 bit IRETD frame

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

        add     [ebx].vsf_sp,(size iret32_s)    ; adjust client's SP
        mov     eax,[esi+edi]                   ; (EAX) = IP from IRET frame
        mov     [ebx].vsf_eip,eax               ; set client's IP
        add     di,4

        mov     eax,[esi+edi]                   ; (EAX) = CS from IRET frame
        mov     [ebx].vsf_cs,ax                 ; set client's CS
        add     di,4
        mov     eax,[esi+edi]                   ; (EAX) = flags from IRET frame
        jmp     eir20
Tune1:  jmp     em86EnabledInterrupts
EndProc   em86opIRET
;SWAP32_12 ends *****************************

SWAP32_24 segment
;***LP  em86PopVPMIRET - pop a 16 or 32 bit VDM protected mode IRET frame
;
;       ENTRY   EBX = pointer client register frame (CRF)
;
;       EXIT
;         SUCCESS - returns TRUE
;         ERROR - returns FALSE (fault will be simulated into VDM)
;
;       USES    EAX, ECX, EDX, ESI, FS, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if 16 bit DPMI app
;           get pointer to client's stack pointer
;           adjust client's stack pointer (3 words)
;           move IP from stack to client's IP register
;           move CS from stack to client's CS register
;           get flags from stack
;       else
;           get pointer to client's stack pointer
;           adjust client's stack pointer (3 dwords)
;           move EIP from stack to client's EIP register
;           move CS from stack to client's CS register
;           get eflags from stack
;       force NT and RF flags off and IOPL = 0
;       put into client's flag register
;       if IF in flags from client's stack is set
;           em86EnabledInterrupts()
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86PopVPMIRET,near
LocalVar  iret_stack, <size iret32_s>
LocalVar  uloffset, DWORD
EnterProc

        em86AssertPVSF ebx
IFDEF   EM86STRICT
        mov     si,[ebx].vsf_cs                 ; (SI) = client's CS
        cmp     si,[selVPMBP]                   ; is the new CS:IP a VDM BP?
        jne     short pvi10                     ;  no, don't print anything
        cmp     [ebx].vsf_eip,VPM_EXC_BP_END    ; past the end of int & exc BPs?
        jbe     short pvi10                     ;  no, skip the panic
        Panic   <"em86PopVPMIRET: CS:EIP is a VPM BP">
ENDIF
pvi10:
        lea     esi,iret_stack
        SSToDS  esi
        lea     eax,uloffset
        SSToDS  eax
        testb   [flVdmStatus],VDM_STATUS_VPM_32 ; is this a 32 bit iret frame?
        jnz     pvi30                           ;  yes, jump to iretd code

;       16 bit IRET frame

        movzx   ecx,[ebx].vsf_sp                ; get client's SP
        mov     uloffset, ecx                   ; store initial offset
        add     cx,(size iret16_s)              ; adjust client's SP
        mov     [ebx].vsf_sp,cx
        PCall   VDHReadUBuf, <esi, <size iret16_s>, DWORD PTR [ebx].vsf_ss, \
                              eax, VPM_SEL_IS_SS>
        or      eax,eax                         ; check for errors
        jz      short pviexit

        lods    word ptr [esi]
        movzx   eax,ax                          ; (EAX) = IP from IRET frame
        mov     [ebx].vsf_eip,eax               ; set client's IP

        lods    word ptr [esi]                  ; (AX) = CS from IRET frame
        mov     [ebx].vsf_cs,ax                 ; set client's CS

        lods    word ptr [esi]
        movzx   eax,ax                          ; (EAX) = flags from IRET frame

pvi20:
;BN009        and     eax,VPM_POPF_OFF                ; force off some flags
        .errnz  VPM_POPF_ON
        andb    [ebx].vsf_eflag,%(F_IOPLMASK + F_TRACE)
        test    [flVdmStatus], VDM_STATUS_VME   ; check if P5           ;BN006 begin
        jnz     short pvi201                    ;  Yes-Coninue with VME ;BN009
        and     eax,VPM_POPF_OFF                ;  No-force off some flags BN009
        jmp     pvi2002                                                 ;BN009
pvi201:                                                                 ;BN009
        and     eax,P5_VPM_POPF_OFF             ; force off some flags  ;BN009
        test    eax, F_INTERRUPT                ; copy of VIF from IF
        jz      short pvi2001
        or      eax, F_VIF                      ; Set VIF bit
        orb     [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
        jmp     short pvi2002
pvi2001:
        and     eax,not F_VIF                   ; clear VIF bit
        or      eax,F_INTERRUPT                 ; enable Phys interrupt   ;BN008
        clrb    [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
pvi2002:                                                                ;BN006 end
        or      [ebx].vsf_eflag,eax             ; set client's flags
        call    em86CheckVPMBP                  ; check for VPM BP's
        mov     eax,TRUE                        ; indicate success

        testb   [flVdmStatus],VDM_STATUS_VPM_IF_FLAG
        jz      short pviexit
        call    em86EnabledInterrupts
pviexit:
        ExitProc

;       32 bit IRETD frame

pvi30:
        mov     ecx,[ebx].vsf_esp               ; uloffset = client's ESP
        mov     uloffset, ecx
        add     [ebx].vsf_esp,(size iret32_s)   ; adjust client's ESP
        PCall   VDHReadUBuf, <esi, <size iret32_s>, DWORD PTR [ebx].vsf_ss, \
                              eax, VPM_SEL_IS_SS>
        or      eax,eax                         ; check for errors
        jz      short pviexit

        lods    dword ptr [esi]                 ; (EAX) = EIP from IRET frame
        mov     [ebx].vsf_eip,eax               ; set client's EIP

        lods    dword ptr [esi]                 ; (EAX) = CS from IRET frame
        mov     [ebx].vsf_cs,ax                 ; set client's CS

        lods    dword ptr [esi]                 ; (EAX) = flags from IRET frame
        jmp     pvi20

EndProc   em86PopVPMIRET
SWAP32_24 ends

SWAP32_24 segment
;***LP  em86opCLI - Emulate disable interrupt IOPL sensitive instruction
;
;       This function emulates the disable interrupt instruction.  It
;       called by the opcode decoder for the CLI 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    NONE
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       clear the interrupt flag
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

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

        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC ; see if this is a DPMI app
; BN008 - Begin
        jz      short cli01                           ; nope, skip ahead

        clrb    [flVdmStatus],VDM_STATUS_VPM_IF_FLAG  ; clear VPM int flag
        test    [flVdmStatus], VDM_STATUS_VME         ; VME Supported?
        jz      short cli10                           ; No - Done
        and     [ebx].vsf_eflag, not F_VIF            ; Clear VIF
        or      [ebx].vsf_eflag, F_INTERRUPT          ; Enable Phys Interrupts
        jmp     short cli10                           ; Done

cli01:
        test    [flVdmStatus], VDM_STATUS_VME         ; VME Supported?
        jz      cli05                                 ; No - Normal CLI
        and     [ebx].vsf_eflag, not F_VIF            ; Clear VIF
        or      [ebx].vsf_eflag, F_INTERRUPT          ; Enable Phys Interrupts
        jmp     short cli10                           ; Done
; BN008 - End

cli05:
        clrb    [ebx].vsf_eflag,F_INTERRUPT           ; Normal CLI
cli10:
        ret
EndProc   em86opCLI
SWAP32_24 ends

SWAP32_12 segment
;***LP  em86opSTI - Emulate enable interrupt IOPL sensitive instruction
;
;       This function emulates the enable interrupt instruction.  It
;       called by the opcode decoder for the STI 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    ESI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       set the interrupt flag
;       fall thru into em86EnabledInterrupts
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

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

        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC ; see if this is a DPMI app
; BN008 - Begin
        jz      short sti01                           ; nope, skip ahead

        orb     [flVdmStatus],VDM_STATUS_VPM_IF_FLAG  ; Set VPM int flag
        test    [flVdmStatus], VDM_STATUS_VME         ; VME Supported?
        jz      short sti10                           ; No - Done
        or      [ebx].vsf_eflag, F_VIF                ; Set VIF
        jmp     short sti10                           ; Done

sti01:
        test    [flVdmStatus], VDM_STATUS_VME         ; VME Supported?
        jz      sti05                                 ; No - Normal STI
        or      [ebx].vsf_eflag, F_VIF                ; Set VIF
        jmp     short sti10                           ; Done
; BN008 - End

sti05:
        orb     [ebx].vsf_eflag,F_INTERRUPT           ; Normal STI
sti10:
        FallInto em86EnabledInterrupts
EndProc   em86opSTI

;***LP  em86EnabledInterrupts - common function when interrupts are enabled
;
;       This is the common function called by the IOPL sensitive
;       instruction emulation routines when interrupts in a VDM
;       have been enabled.  This routine calls the VDD handlers
;       for this VDM.
;
;       ENTRY   EBX = pointer client register frame (CRF)
;
;       EXIT    NONE
;
;       USES    ESI, Flags
;
;       CONTEXT VDM Task
;
;       PSEUDO-CODE
;
;       if iopl is 0 (emulating)
;           set iopl to 3 (disables IF instruction trapping)
;           call each VDD hook handler on stih list
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure em86EnabledInterrupts,near
        em86AssertPVSF ebx
        pushfd                                  ; Save flags            BN001
        cli                                     ; disable ints          BN001
        testb   [flVdmStatus],VDM_STATUS_VPM_EXEC ; DPMI app?           BN002
        jnz     short ei20                      ; yes, set IOPL to 2    BN002

        test    [flVdmStatus],VDM_STATUS_VME    ; if running on P5      ;BN006
        jnz     short ei20                      ; YES->don't set IOPL=3 ;BN006

        testb   [ebx].vsf_eflag,F_IOPLMASK      ; emulating IF instructions?
;BD003  jnz     short eitx                      ;  no, exit
        jnz     short ei30                      ;  no, exit

        orb     [ebx].vsf_eflag,F_IOPL3         ;  yes, disable IF inst trapping
        jmp     short ei30
ei20:
        orb     [ebx].vsf_eflag,F_IOPL2         ;  if in VPM, set IOPL to 2
        and     [ebx].vsf_eflag, not F_VIP      ; disable VIP (IF inst trapping)

ei30:
        mov     esi,[_pTCBCur]                  ; set STI force flag
        orb     [esi].TCBForcedActions,TK_FF_STIH
eitx:   popfd                                   ; restore flags         BN001
        ret
EndProc   em86EnabledInterrupts
SWAP32_12 ends
EndCode

        end
