
#define SCCSID "@(#)em86vpmx.c  6.7 92/01/22"

/***    EM86VPMX.C
 *
 *     Version 1.16.2.6, for src/dos/mvdm/em86vpmx.c, em86, mer.krnl, 960610.1
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      Title:
 *
 *      DOS Protected mode VDM support
 *
 *      Description:
 *
 *      This file contains frequently called support routines for
 *      DPMI.
 *
 *      Public routines:
 *
 *      VDHGetSelBase
 *      VDHChangeVPMIF
 *      VDHReadUBuf
 *      VDHWriteUBuf
 *      VDHStartHWInt
 *      VDHCheckPagePerm
 *      VDHRaiseException
 *      VDHChangeVPMEM
 *      VDHCheckVPMExcept
 *      VDHGetVPMExcept
 *      VDHSetVPMExcept
 *      em86DPMITaskSwitch
 *      VDHCheckVPMIntVector
 *      VDHGetVPMIntVector
 *      VDHSetVPMIntVector
 *      VDHArmVPMBPHook
 *      VDHBeginUseVPMStack
 *      VDHEndUseVPMStack
 *      VDHProbeUBuf
 *      VDHPopVPMFarRet
 *      VDHPrepVPMIret
 *
 *      Local routines:
 *
 *      em86PGMoveStub
 *      em86PGGetAccessStub
 *
 *      Modification History:
 *
 *    - Bill Madden 07/18/91
 *      Changed VDHSetVPMIntVector to update flVDMStatus with whether the app
 *      has hooked protect mode int x1C or not.
 *
 *    - Bill Madden 09/25/91
 *      Removed VDHPopVPMInt and changed VHDPopVPMFarRet and VDHPrepVPMIRet to
 *      return errors that occur accessing user stack space.
 *
 *    - Bill Madden 01/21/92
 *      Added VDHCheckVPMExcept.
 *
 *    - Ken Luo     03/20/93
 *      Added MMIO dekko hooks
 *    - Bx001  Bill Madden    03/24/93    FEA 63842
 *      Added P5 support.
 *    - Bx002  Lisa Primm     04/21/93    DEF 64131
 *      Fixed problems in multiple DPMI client support.
 *    - Bx003  Change Team    08/23/93    Def 73188
 *      Changed SelSwitchVdmLDT to accept additional paramater and update
 *      bitmap of valid LDT page before switching LDT's
 *
 *    - bjn         09/19/94
 *      Changed segment names for page tuning.
 *
 *    - Gordon Kuo  02/23/96      149007
 *      Add Extended Exception Handler for VDPMI 1.0 Subset
 *
 *     03-27-96 Gordon Kuo -- Fix Defect 149895
 *        Add dhd_ppDosX address to switch VDPX puxtd when switch DPMI client
 *
 *
 *    - @V3.0RV01 147884 - 01-31-96 - @IBM - Code fix for IBM Japan
 *      Added check for VDM_STATUS_VPM_EXEC before switching the VPM IDT.
 *
 *     05-03-96 Gordon Kuo -- Fix Defect 153566
 *        Modify INT 1Ch, 23h, 24h functions
 *
 */
#define FNO_NUM  FNO_EM86VPMX_C
#include <fnomvdm.h>

#define INCL_NONE               // for mvdm.h
#define INCL_TYPES              // include base types
#define INCL_MVDMTYPES          // include mvdm types
#define INCL_VDHALL             // include VDH services
#define INCL_ROMBIOS            // for Int 1C equates

#include <vdmvdh.h>
#include <seldesc.h>
#include <sft.h>
#include <kmode.h>
#include <em86.h>
#include <vpm.h>
#include <vpmxport.h>
#include <dpmi.h>
#include <pdb.h>
// #include <tkptda.h>
#include <dbgex.h>        /* 149007 */
#ifdef MMIOPH
  #include <mmph.h>
#endif


/* External and misc definitions */
typedef struct desctab * PDESC;
extern VPVOID vpVdmBpArpl;
extern PVSF   pvsfFrameBase;
extern SEL    selVPMBP;
extern ULONG  cVPMHWInt;                                                //BN002
extern VOID   em86UpdateIDT(ULONG);
extern SEL    SELMaxGDT;
extern HHOOK  hhookVPMExpExcRetHook; /* 149007 Hook for Expanded stack return */
extern HHOOK  hhookV86ExpExcRetHook; /* 149007 Hook V86 Expanded stack return */
extern HHOOK  hhookV86ExpExc9RetHook;/* 149007 Hook V86 Expanded stack return */
extern HHOOK  hhookBacktoV86RetHook; /* 149007 V86 1c,23,24 to VPM ret hook   */
extern USHORT usEIPincr;             /* em86vpm.c GK       149007         */

extern BOOL PASCAL HandleExc(VOID);

/* Internal routine prototypes */

INT em86PGMoveStub(ULONG,PVOID,ULONG,PVOID,INT,USHORT);
INT em86PGGetAccessStub(ULONG,PVOID,INT,INT,PCHAR);
INT em86DPMITaskSwitch(PVOID);
ULONG em86GetDr6(VOID);       /* 149007 */

/* External Routines */
extern VOID PASCAL EM86ReflectException(VOID);
extern VOID PASCAL EM86ReflectVPMInt(VOID);

#pragma BEGIN_MVDM_SWAP_DATA

extern PDHD  pdhdHostData;
extern PDHD  pdhdHostLast;
extern PVPMD pvpmData;
// PDHD   pdhdBeforeHWInt;     /* 149007: It's an instance data 02/23/96 */

extern PFNDPMQUERY pfndpmQuery;
            /* ULONG (PASCAL *PFNDPMQUERY)(ULONG,PULONG) GK */

#pragma END_MVDM_SWAP_DATA


#pragma BEGIN_MVDM_SWAP_INSTANCE

ULONG  cr2_buf;          /* 149007 CR6 register in PageGault Exception */
ULONG  pfntrapD;
UCHAR  flrestart;
PDHD   pdhdBeforeHWInt;  /* GK: The DPMI task(client) before HW INT  */
                         /* GK: I don't like the way it's implemented*/

PLDHD  pldhdVPMSaveCurTask = NULL; /* 149007: The Current DPMI task(client)     */
/***    cVPMSaveCurTask -                                        149007
 *        VDM Save Current Client for switching Primary Client   149007
 *                                                               149007
 *      This is the count of VDM Save Current Client for switching 149007
 *      Primary Client                                             149007
 */
ULONG   cVPMSaveCurTask = 0;                                    /* 149007 */


#pragma END_MVDM_SWAP_INSTANCE

#pragma BEGIN_MVDM_SWAP_CODE

#pragma END_MVDM_SWAP_CODE

#pragma code_seg("SWAP32_24","CODE")
/***EP+ VDHGetSelBase - get flat base address for selector
 *
 *      This routine returns the base address for an LDT selector.
 *      The only checking done is to ensure the selector is allocated.
 *
 *      ENTRY
 *          sel
 *              selector
 *          pBase
 *              pointer for returned address
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *             handler address and flag information returned
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *      get selector/offset from exception shadow table
 */
BOOL VDHENTRY VDHGetSelBase(SEL sel, PULONG pBase)
/*end*/
{
    register PDESC pdesc;
    BOOL rc = TRUE;

#ifdef MMIOPH
    MMPHPreVDHGetSelBase()
#endif
    // Get descriptor information
    if (sel & TABLE_MASK) {
       pdesc = ((PDESC)pdhdHostData->dhd_laddrLDT) + (sel >> 3);
    } else if (sel <= SELMaxGDT) {
       pdesc = ((PDESC)SELGDTLaddr) + (sel >> 3);
    } else {
       pdesc = NULL;
    }

    // If valid descriptor, get selector base
    if (pdesc &&
        ((pdesc->d_access & D_PRES+D_DPL3+D_SEG) == D_PRES+D_DPL3+D_SEG)) {
       *pBase =    (ULONG)pdesc->d_loaddr
                | ((ULONG)pdesc->d_hiaddr << 16)
                | ((ULONG)pdesc->d_extaddr << 24);

    // Otherwise return error
    } else {
       rc = FALSE;
    }

#ifdef MMIOPH
    MMPHPostVDHGetSelBase()
#endif
    return(rc);
} // end VDHGetSelBase


#pragma code_seg("SWAP32_24","CODE")
/***EP+ VDHChangeVPMIF - change the virtual interrupt enable flag
 *
 *      This routine changes the virtual IF flag, enabling
 *      or disabling protect mode interrupts.  This change
 *      is reflected in a bit in flVDMStatus.  If STI hooks
 *      are waiting and interrupts are enabled, the hooks
 *      are called.
 *
 *      ENTRY
 *          fSetIF  if non zero, set IF
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          never fails
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *      set virtual interrupt flag in flVDMStatus
 *      if enabling interrupts
 *          call STI hooks
 *      return success
 */
BOOL VDHENTRY VDHChangeVPMIF(BOOL fSetIF)
/*end*/
{

#ifdef MMIOPH
    MMPHPreVDHChangeVPMIF()
#endif
    if (fSetIF) {
        if (flVdmStatus &  VDM_STATUS_VME) {                            //BN013
            VSF_EFLAG(pvsfFrameBase) |= F_VIF;     /* Enable VIF bit */ //BN013
        }                                                               //BN013
       flVdmStatus |= VDM_STATUS_VPM_IF_FLAG;      /* Enable ints, set IF bit */
       pTCBCur->TCBForcedActions |= TK_FF_STIH;    /* Call any pending STI    */
    } else {
        if (flVdmStatus &  VDM_STATUS_VME) {                            //BN013
            VSF_EFLAG(pvsfFrameBase) &= ~F_VIF;    /* Clear VIF bit */  //BN013
        }                                                               //BN013
       flVdmStatus &= ~VDM_STATUS_VPM_IF_FLAG;     /* Disable ints, clear IF  */
    }

#ifdef MMIOPH
    MMPHPostVDHChangeVPMIF()
#endif
    return(TRUE);
} // end VDHChangeVPMIF


#pragma code_seg()
#pragma BEGIN_MVDM_SWAP_CODE

/***LP  em86PGMoveStub - Stub for PGMove. Called by DPMI VDD
 *
 *      This function fills in the pointers to the current PTDA
 *      and calls PGMove. It is required because the DPMI VDD does
 *      not have access to the PTDA pointers.
 *
 *      ENTRY   pagesrc - source virtual page
 *              pptda1 - null, filled in by stub with ptr to current PTDA
 *              pagedst - destination virtual page
 *              pptda1 - null, filled in by stub with ptr to current PTDA
 *              npages - number of pages
 *              hob - object handle for destination
 *
 *      EXIT    0 on success, else error code
 *
 *      CONTEXT VDM Task
 *
 */

INT em86PGMoveStub(ULONG pagesrc, PVOID pptda1, ULONG pagedst,
                   PVOID pptda2, INT npages, USHORT hob)
{
    pptda1; pptda2; // just to avoid warning
    // Call PGMove with passed parameters plus pointers to current PTDA
    return (PGMove (pagesrc, pPTDACur, pagedst, pPTDACur, npages, hob));

}

/***LP  em86PGGetAccessStub - Stub for PGGetAccess. Called by DPMI VDD
 *
 *      This function fills in the pointers to the current PTDA
 *      and calls PGGetAccess. It is required because the DPMI VDD does
 *      not have access to the PTDA pointers.
 *
 *      ENTRY:  page - target virtual page number
 *              reserved - target context
 *              npages - number of pages to query
 *              fl - PG_SKIPFREE - don't stop and return error
 *                                     for invalid (free) pages
 *              pbuf - pointer to return array of bytes
 *      EXIT:   0 if success, else error code
 *
 *      CONTEXT VDM Task
 *
 */

INT em86PGGetAccessStub(ULONG page, PVOID reserved, INT npages,
                                     INT fl, PCHAR pbuf)
{
    reserved; // just to avoid warning
    // Call PGGetAccess with passed parameters plus pointer to current PTDA
    return (PGGetAccess (page, pPTDACur, npages, fl, pbuf));

}

#pragma END_MVDM_SWAP_CODE
#pragma code_seg("SWAP32_24","CODE")
/***EP VDHReadUBuf - read from protect mode user buffer
 *
 *      Read from protect mode address space as if read
 *      was done at ring 3.  This means trapping
 *      any other faults.  All faults are passed on
 *      to the VDM application handler through
 *      VDHRaiseException.  When the routine returns
 *      failure, the caller must clean up and exit
 *      so that the exception can be simulated to
 *      the user.
 *
 *      Supervisor pages are allowed to be read from
 *      without faults to avoid the overhead of checking.
 *
 *      HandleExc depends on the order the arguments are passed to
 *      VDHReadUbuf.  HandleExc will intercept any fatal exceptions
 *      (Trap 0D, 0E) that occur and will pass the fault on to the
 *      applications fault handler, if it has one.
 *
 *      ENTRY
 *          pDstBuf
 *              destination buffer to copy to
 *          cb
 *              count of bytes
 *          sel
 *              application selector
 *
 *          pulOffSet
 *              address of variable containing offset for start of read
 *          fl
 *              controls on what to check for:
 *               VPM_PROT_READ       -- Check for read
 *               VPM_PROT_WRITE      -- Check for write
 *               VPM_FAULT_IF_RW_SET -- Fault if R/W bit set
 *               VPM_FAULT_IF_SU_SET -- Fault if S/U bit set
 *               VPM_SEL_WRITEABLE   -- Caller knows descriptor is writable
 *               VPM_SEL_IS_SS       -- Selector is client's stack
 *               VPM_SEL_PRESENT     -- Caller knows descriptor is present
 *               VPM_FAULT_IF_RO     -- Caller does not know if descriptor
 *                                      is read only (Do not convert
 *                                      to flat address without checking)
 *               VPM_XCPTRET_ALT     -- After exception, return to
 *                                      alternate mode (e.g. if
 *                                      client was in protect mode
 *                                      when the service was called,
 *                                      return in V86 mode after
 *                                      the exception is handled
 *               VPM_NO_SIM_EXCPT    -- Don't reflect exception into VDM
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *          *pulOffset is updated with the address of the fault. ****
 *          For selector faults it is unchanged
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *
 *      err = FALSE
 *      if VPM_FAULT_IF_SU_SET is set
 *         calculate number of pages
 *         check access rights for the pages (PGVerifyPermission)
 *         if an error occurs
 *            err = TRUE
 *            pass exception to VDM (VDHRaiseException)
 *      if no error has occured
 *         set up fault handler
 *         copy the data
 *         restore original fault handler
 *         update pulOffSet with the number of bytes copied
 *
 *      return NOT err
 *
 */
BOOL VDHENTRY VDHReadUBuf(PVOID pDstBuf, ULONG cb, SEL sel,
                          PULONG pulOffSet, ULONG fl)
{
    ULONG SelBase;
    ULONG err = FALSE;
    ULONG ultemp, page, flperm;

#ifdef MMIOPH
    MMPHPreVDHReadUBuf()
#endif
    VDHGetSelBase (sel, SSToDS(&SelBase));

    if (fl & (VPM_FAULT_IF_SU_SET | VPM_PROT_READ)) {

       flperm = PG_U;              // set the flag to check user access
       if (fl & VPM_PROT_READ) {   // set the write flag, if neccessary
          flperm |= PG_R;
       }

       /* Calculate the number of pages */
       ultemp = (cb + PAGESIZE - 1)/PAGESIZE;

       page = (SelBase + *pulOffSet) / PAGESIZE;

       /* See if the pages are user accessable */
       if ((err = PGVerifyPermission(page, pPTDACur, ultemp, flperm))
           != NO_ERROR) {

          /* Set the restart flag so that EM86ReflectVPMException routine    */
          /* knows that it should try to reexecute the faulting instruction. */
          flrestart = VPM_RESTART_INST;               // set reexecution flag

          // If alternate flag is set, when we return from the exception
          // we need to switch from VPM to V86 from V86 to VPM
          if (!(flVdmStatus & VDM_STATUS_VPM_EXEC)) {
             VDHSwitchToVPM();                  // always reflect to prot mode
             if (!(fl & VPM_XCPTRET_ALT)) {
                flrestart |= VPM_RETV86;
             }
          } else if (fl & VPM_XCPTRET_ALT) {
             flrestart |= VPM_RETV86;
          }

          if (!(fl & VPM_NO_SIM_EXCPT)) {
             VDHRaiseException(0xD, (ULONG)sel, 0);   // simulate the exception (trap D)
          }
       }

    }

    if (err == FALSE) {

       /* Save old trap handler */
       pfntrapD = pTSDCur->TSDpfnFault;

       // Set up new trap handler
       pTSDCur->TSDpfnFault = (ULONG)HandleExc;

       em86memcpy (pDstBuf, ((PVOID)(SelBase + *pulOffSet)), cb);

       /* If we get here, no traps must have occurred, so update pulOffSet */
       *pulOffSet += cb;

       /* Restore old trap handler */
       pTSDCur->TSDpfnFault = pfntrapD;

    }

#ifdef MMIOPH
    MMPHPostVDHReadUBuf()
#endif
    return (!err);
}


#pragma code_seg("SWAP32_24","CODE")
/***EP VDHWriteUBuf - write to protect mode user buffer
 *
 *      Write to protect mode address space as if access
 *      was done at ring 3.  This means checking for
 *      supervisor and read only faults and trapping
 *      any other faults.  All faults are passed on
 *      to the VDM application handler through
 *      VDHRaiseException.  When the routine returns
 *      failure, the caller must clean up and exit
 *      so that the exception can be simulated to
 *      the user.
 *
 *      HandleExc depends on the order the arguments are passed to
 *      VDHWriteUbuf.  HandleExc will intercept any fatal exceptions
 *      (Trap 0D, 0E) that occur and will pass the fault on to the
 *      applications fault handler, if it has one.
 *
 *      ENTRY
 *          pSrcBuf
 *              source buffer to copy from
 *          cb
 *              count of bytes
 *          sel
 *              application selector
 *
 *          pulOffSet
 *              address of variable containing offset for start of write
 *          fl
 *              controls on what to check for:
 *               VPM_PROT_READ       -- Check for read
 *               VPM_PROT_WRITE      -- Check for write
 *               VPM_FAULT_IF_RW_SET -- Fault if R/W bit set
 *               VPM_FAULT_IF_SU_SET -- Fault if S/U bit set
 *               VPM_SEL_WRITEABLE   -- Caller knows descriptor is writable
 *               VPM_SEL_IS_SS       -- Selector is client's stack
 *               VPM_SEL_PRESENT     -- Caller knows descriptor is present
 *               VPM_FAULT_IF_RO     -- Caller does not know if descriptor
 *                                      is read only (Do not convert
 *                                      to flat address without checking)
 *               VPM_XCPTRET_ALT     -- After exception, return to
 *                                      alternate mode (e.g. if
 *                                      client was in protect mode
 *                                      when the service was called,
 *                                      return in V86 mode after
 *                                      the exception is handled
 *               VPM_NO_SIM_EXCPT    -- Don't reflect exception into VDM
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *          *pulOffset is updated with the address of the fault.
 *          For selector faults it is unchanged
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *
 *      err = FALSE
 *      if VPM_FAULT_IF_SU_SET is set
 *         calculate number of pages
 *         check access rights for the pages (PGVerifyPermission)
 *         if an error occurs
 *            err = TRUE
 *            pass exception to VDM (VDHRaiseException)
 *      if no error has occured
 *         set up fault handler
 *         copy the data
 *         restore original fault handler
 *         update pulOffSet with the number of bytes copied
 *
 *      return NOT err
 *
 */
BOOL VDHENTRY VDHWriteUBuf(PVOID pSrcBuf, ULONG cb, SEL sel,
                                     PULONG pulOffSet, ULONG fl)
{
    ULONG SelBase;
    ULONG err = FALSE;
    ULONG npages, page;
    ULONG flperm;

#ifdef MMIOPH
    MMPHPreVDHWriteUBuf()
#endif
    VDHGetSelBase (sel, SSToDS(&SelBase));

    if (fl & VPM_FAULT_IF_SU_SET) {

       /* Calculate the number of pages */
       npages = (cb + PAGESIZE - 1)/PAGESIZE;

       flperm = PG_U;               // set the flag to check user access
       if (fl & VPM_PROT_WRITE) {   // set the write flag, if neccessary
          flperm |= PG_W;
       }

       page = (SelBase + *pulOffSet) / PAGESIZE;

       /* See if the pages are user accessable and writable */
       if ((err = PGVerifyPermission(page, pPTDACur, npages, flperm))
            != NO_ERROR) {

          /* Set the restart flag so that EM86ReflectVPMException routine    */
          /* knows that it should try to reexecute the faulting instruction. */
          flrestart = VPM_RESTART_INST;               // set reexecution flag

          if (!(flVdmStatus & VDM_STATUS_VPM_EXEC)) {
             VDHSwitchToVPM();                  // always reflect to prot mode
             if (!(fl & VPM_XCPTRET_ALT)) {
                flrestart |= VPM_RETV86;
             }
          } else if (fl & VPM_XCPTRET_ALT) {
             flrestart |= VPM_RETV86;
          }

          if (!(fl & VPM_NO_SIM_EXCPT)) {
             VDHRaiseException(0xD, (ULONG)sel, 0);   // simulate the exception (trap D)
          }

       }

    }

    if (err == FALSE) {

       /* Save old trap handler */
       pfntrapD = pTSDCur->TSDpfnFault;

       // Set up new trap handler
       pTSDCur->TSDpfnFault = (ULONG)HandleExc;

       em86memcpy (((PVOID)(SelBase + *pulOffSet)), pSrcBuf, cb);

       /* If we get here, no traps must have occurred, so update pulOffSet */
       *pulOffSet += cb;

       /* Restore old trap handler */
       pTSDCur->TSDpfnFault = pfntrapD;

    }

#ifdef MMIOPH
    MMPHPostVDHWriteUBuf()
#endif
    return (!err);

}


#pragma code_seg("SWAP32_24","CODE")
/***EP VDHStartHWInt - hardware interrupt notification
 *
 *      This service is used in DPMI 1.0.  It is called
 *      at the beginning and end of hardware interrupt
 *      reflection to protect mode by VPIC.
 *
 *      ENTRY
 *          fStart
 *              TRUE means starting hardware interrupts
 *              FALSE means ending hardware interrupts
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          always succeeds
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *
 */
BOOL VDHENTRY VDHStartHWInt(BOOL fStart)
{
#ifdef MMIOPH
   MMPHPreVDHStartHWInt()
#endif
   if (fStart) {
      if (cVPMHWInt++ == 0) {
         if (pdhdHostData != pdhdHostLast) {
            pdhdBeforeHWInt = pdhdHostData;

            em86DPMITaskSwitch(pdhdHostLast);

            // set flag so we know we have to restore to current task
            flVdmStatus |= VDM_STATUS_VPM_TASK_SW;
         } else {
            flVdmStatus &= ~VDM_STATUS_VPM_TASK_SW;   // clear flag
         }
      }
   } else if ((--cVPMHWInt == 0) && (flVdmStatus & VDM_STATUS_VPM_TASK_SW)) {
      flVdmStatus &= ~VDM_STATUS_VPM_TASK_SW;   // clear flag

      em86DPMITaskSwitch(pdhdBeforeHWInt);

   }
#ifdef MMIOPH
   MMPHPostVDHStartHWInt()
#endif
   return(TRUE);
}

/***EP VDHPrimaryDPMITask - Switch to DPMI Primary Task(Client) or Switch Back
 *                                                                      149007
 *      This service is used in DPMI 1.0.  It is called                 149007
 *      at the beginning and end of Exception which happens while VDM   149007
 *      is in V86 mode. The exception is reflected to the VPM Primary   149007
 *      Client IDT. This function can be called in multiple nested levels.149007
 *                                                                      149007
 *      ENTRY                                                           149007
 *          fStart                                                      149007
 *              TRUE  means Switch to Primary Client                    149007
 *              FALSE means Switch back to original client              149007
 *                                                                      149007
 *      EXIT-SUCCESS                                                    149007
 *          returns TRUE                                                149007
 *                                                                      149007
 *      EXIT-FAILURE                                                    149007
 *          always succeeds                                             149007
 *                                                                      149007
 *      CONTEXT                                                         149007
 *          VDM Task                                                    149007
 *                                                                      149007
 *      PSEUDO-CODE                                                     149007
 *                                                                      149007
 */
BOOL VDHENTRY VDHPrimaryDPMITask(BOOL fStart)                     /* 149007 */
{                                                                 /* 149007 */
  PLDHD pldhdTmp;                                                 /* 149007 */
                                                                  /* 149007 */
#ifdef MMIOPH                                                     /* 149007 */
//   MMPHPreVDHStartHWInt()                                       /* 149007 */
#endif                                                            /* 149007 */
   if (fStart)                                                    /* 149007 */
   {                                                              /* 149007 */
       if( VMAllocKHB(VM_HKH_PUB_SWAPRW, sizeof(LDHD),(VMHOB)EM86MALLOCOWNER,
                      NA, SSToDS(&pldhdTmp)) != NO_ERROR)         /* 149007 */
       {                                                          /* 149007 */
          PRINTDEBUG( "Error VDHPrimaryDPMITask No memory for LDHD\n" );
          return( FALSE );                                        /* 149007 */
       }                                                          /* 149007 */
       else                                                       /* 149007 */
       {                                                          /* 149007 */
          cVPMSaveCurTask++;                                      /* 149007 */
          pldhdTmp->pDHD      = pdhdHostData;                     /* 149007 */
          pldhdTmp->pNextLDHD = pldhdVPMSaveCurTask;              /* 149007 */
          pldhdVPMSaveCurTask = pldhdTmp;                         /* 149007 */
          em86DPMITaskSwitch(pdhdHostLast);                       /* 149007 */
       }                                                          /* 149007 */
   }                                                              /* 149007 */
   else                                                           /* 149007 */
   {                                                              /* 149007 */
       cVPMSaveCurTask--;                                         /* 149007 */
       if( (pldhdTmp = pldhdVPMSaveCurTask ) != NULL )            /* 149007 */
       {                                                          /* 149007 */
          pldhdVPMSaveCurTask = pldhdTmp->pNextLDHD;              /* 149007 */
          em86DPMITaskSwitch(pldhdTmp->pDHD);                     /* 149007 */
          VMFreeKHB(VM_HKH_PUB_SWAPRW, pldhdTmp );                /* 149007 */
       }                                                          /* 149007 */
       else  /* Coding Error BUG */                               /* 149007 */
       {                                                          /* 149007 */
          PRINTDEBUG( "Error in VDHPrimaryDPMITask (%d)\n",       /* 149007 */
                      cVPMSaveCurTask );                          /* 149007 */
       }                                                          /* 149007 */
   }                                                              /* 149007 */
                                                                  /* 149007 */
#ifdef MMIOPH                                                     /* 149007 */
//   MMPHPostVDHStartHWInt()                                      /* 149007 */
#endif                                                            /* 149007 */
   return(TRUE);                                                  /* 149007 */
}                                                                 /* 149007 */

#pragma code_seg()
#pragma BEGIN_MVDM_SWAP_CODE

/***EP VDHCheckPagePerm - check ring3 page permissions
 *
 *      This service checks ring3 page permissions for a range
 *      of pages.  Fails if a ring 3 client would fault
 *      on the pages in any of the ways which checking
 *      is requested for.
 *
 *      ENTRY   page - base virtual page number
 *              reserved - must be zero
 *              npages - number of pages to verify
 *              fl - VPMPG_U - are the pages user accessible?
 *                      VPMPG_W - are the pages writable?
 *                      VPMPG_R - are the pages readable (valid)?
 *                      VPMPG_X - are the pages executable?
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 */
BOOL VDHENTRY VDHCheckPagePerm(ULONG page, PVOID reserved, ULONG npages, ULONG fl)
{
    BOOL rc;

    reserved;              // eliminate compiler warning

#ifdef MMIOPH
    MMPHPreVDHCheckPagePerm()
#endif
    rc = PGVerifyPermission(page, pPTDACur, npages, fl) == NO_ERROR;
#ifdef MMIOPH
    MMPHPostVDHCheckPagePerm()
#endif
    return(rc);

}  // end VDHCheckPagePerm


/***EP VDHRaiseException - raise exception
 *
 *      This service is used to raise an exception to be
 *      reflected to a VDM as if caused by hardware.
 *
 *      ENTRY
 *          iException
 *              Exception number
 *          ulErrorCode
 *              Error code for exception
 *          ulExtraCode
 *              Extra error code for DPMI 1.0 page faults
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *      if exception should be passed to protect mode
 *          reflect to protect mode exception chain
 *      else
 *          reflect as V86 interrupt
 */
BOOL VDHENTRY VDHRaiseException(ULONG iException, ULONG ulErrorCode,
                                                      ULONG ulExtraCode)
{
   _asm mov eax, iException
   _asm mov ebx, pvsfFrameBase
   _asm mov edx, ulErrorCode

#ifdef MMIOPH
   MMPHPreVDHRaiseException()
#endif
   EM86ReflectException();

   ulExtraCode;
#ifdef MMIOPH
   MMPHPostVDHRaiseException()
#endif
   return(FALSE);
}


/***EP VDHChangeVPMEM - change the NPX emulation flag
 *
 *      If changes in the EM bit are allowed, changes
 *      the EM bit to enable or disable coprocessor
 *      emulation.
 *
 *      ENTRY
 *          fl
 *             VPM_ENABLE_EMULATION
 *             VPM_DISABLE_EMULATION
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *          (can refuse to turn off emulation to protect against errata)
 *
 *      CONTEXT
 *          VDM Task
 *
 *      PSEUDO-CODE
 *      change the EM flag if allowed
 */

/***EP+ VDHCheckVPMExcept - returns if a VDM prot mode exception handler exists
 *
 *      This function returns TRUE if the application protect
 *      mode exception or interrupt vector is set.
 *
 *      ENTRY
 *          iVector
 *              exception number
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *              no VDM protected mode exception or interrupt handler
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *           If exception is not hooked, also checks the interrupt since default
 *           is for exceptions to be reissued as interrupts.
 *
 *      PSEUDO-CODE
 *
 *      get selector/offset from interrupt shadow table
 *      if default handler address for both exception and interrupt handler
 *          return FALSE
 *      return TRUE
 */

BOOL VDHENTRY VDHCheckVPMExcept(iVector)
ULONG iVector;
/*end*/
{
#ifdef MMIOPH
    MMPHPreVDHCheckVPMExcept()
#endif
    ASSERTVDMTASKONLY;
    if(!(flVdmStatus & VDM_STATUS_VPM_APP))   /* 149007 */
    {                                         /* 149007 */
       return( FALSE );                       /* 149007 */
    }                                         /* 149007 */
    //VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP);
    if (((*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_sel == selVPMBP) &&
        ((*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_off ==
          (iVector+VPM_EXC_BP_START)) &&
        ((*pvpmData->vpmd_pavpmint)[iVector].vpmint_sel == selVPMBP) &&
        ((*pvpmData->vpmd_pavpmint)[iVector].vpmint_off == iVector)) {
#ifdef MMIOPH
        MMPHPostVDHCheckVPMExcept()
#endif
        return(FALSE);
    }
#ifdef MMIOPH
    MMPHPostVDHCheckVPMExcept()
#endif
    return(TRUE);
}


/***EP+ VDHCheckVPMV86Except -                   149007
 *     returns if a DPMI V86 prot mode exception handler exists  149007
 *                                                               149007
 *      This function returns TRUE if the DPMI application V86   149007
 *      mode exception is set.                                   149007
 *                                                               149007
 *      ENTRY                                                    149007
 *          iVector                                              149007
 *              exception number                                 149007
 *                                                               149007
 *      EXIT-SUCCESS                                             149007
 *          returns TRUE                                         149007
 *                                                               149007
 *      EXIT-FAILURE                                             149007
 *          returns FALSE                                        149007
 *              no DPMI V86 mode exceptionhandler                149007
 *                                                               149007
 *      CONTEXT                                                  149007
 *          VDM Task                                             149007
 *                                                               149007
 *      NOTES                                                    149007
 *                                                               149007
 *      PSEUDO-CODE                                              149007
 *                                                               149007
 *      get selector/offset from V86 Exception shadow table      149007
 *      if default handler address for both exception            149007
 *          return FALSE                                         149007
 *      return TRUE                                              149007
 */

BOOL VDHENTRY VDHCheckVPMV86Except(iVector)                    /* 149007 */
ULONG iVector;                                                 /* 149007 */
/*end*/                                                        /* 149007 */
{                                                              /* 149007 */
    //VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP);         /* 149007 */
    if( !(flVdmStatus & VDM_STATUS_VPM_APP ) )                 /* 149007 */
    {                                                          /* 149007 */
       return( FALSE );                                        /* 149007 */
    }                                                          /* 149007 */
                                                               /* 149007 */
    /* The V86 exception will be sent to primary client */     /* 149007 */
    VDHPrimaryDPMITask( TRUE );    /* Swtich to Primary client */ /* 149007 */
                                                                  /* 149007 */
    if (((*pvpmData->vpmd_pav86exc)[iVector].vpmexc_sel == selVPMBP) &&
        ((*pvpmData->vpmd_pav86exc)[iVector].vpmexc_off ==        /* 149007 */
          (iVector+VPM_V86EXC_BP_START)) ){                       /* 149007 */
        /* switch back to current client */                       /* 149007 */
        VDHPrimaryDPMITask( FALSE );                              /* 149007 */
        return(FALSE);                                            /* 149007 */
    }                                                             /* 149007 */

    /* switch back to current client */                           /* 149007 */
    VDHPrimaryDPMITask( FALSE );                                  /* 149007 */
    return(TRUE);                                                 /* 149007 */
}                                                                 /* 149007 */


#pragma END_MVDM_SWAP_CODE
#pragma code_seg("SWAP32_26","CODE")
/***EP+ VDHGetVPMExcept - returns the VDM protected mode exception vector
 *
 *      This routine gets the current value from the protect mode
 *      exception table.
 *
 *      ENTRY
 *          iVector
 *              exception vector number (0-1fh)
 *          pfpfn
 *              pointer to put handler address
 *          pfb
 *             VPMXCPT32          32 bit handler
 *             VPMXCPT10          1.0 uniform frame
 *             VPMXCPTV86         1.0 V86 exception handler      149007
 *             VPMXCPT_REFLECT    reflect exception from V86 mode
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 *
 *      get selector/offset from exception shadow table
 */
BOOL VDHENTRY  VDHGetVPMExcept(ULONG iVector, PFPFN pfpfn, PBYTE  pfb)
/*end*/
{

#ifdef MMIOPH
    MMPHPreVDHGetVPMExcept()
#endif
    ASSERTVDMTASKONLY;
    if( !(flVdmStatus & VDM_STATUS_VPM_APP ) )                /* 149007 */
    {                                                         /* 149007 */
       return( FALSE );                                       /* 149007 */
    }                                                         /* 149007 */
    // VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP);       /* 149007 */
                                                              /* 149007 */
    if( (*pfb) & VPMXCPTV86 )                                 /* 149007 */
    {                                                         /* 149007 */
       SEGMENTOF32(*pfpfn) = (*pvpmData->vpmd_pav86exc)[iVector].vpmexc_sel;
                                                              /* 149007 */
       OFFSETOF32(*pfpfn) = (*pvpmData->vpmd_pav86exc)[iVector].vpmexc_off;
                                                              /* 149007 */
       *pfb = (BYTE)(*pvpmData->vpmd_pav86exc)[iVector].vpmexc_fb; /* 149007 */
    }                                                         /* 149007 */
    else                                                      /* 149007 */
    {                                                         /* 149007 */
       SEGMENTOF32(*pfpfn) = (*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_sel;
       OFFSETOF32(*pfpfn) = (*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_off;
       *pfb = (BYTE)(*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_fb; /* 149007 */
    }

#ifdef MMIOPH
    MMPHPostVDHGetVPMExcept()
#endif
    return(TRUE);
}

#pragma code_seg("SWAP32_25","CODE")
/***EP+ VDHSetVPMExcept - sets the VDM protected mode exception vector
 *
 *      This routine sets the current value from the protect mode
 *      exception table.
 *
 *      ENTRY
 *          iVector
 *              interrupt vector number
 *          fpfn
 *              far32 handler address
 *          fb
 *             VPMXCPT32          32 bit handler
 *             VPMXCPT10          1.0 uniform frame
 *             VPMXCPTV86         1.0 V86 exception handler       149007
 *             VPMXCPT_REFLECT    reflect exception from V86 mode
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 *
 *      set selector/offset into exception shadow table
 *      return success
 */
BOOL VDHENTRY  VDHSetVPMExcept(ULONG iVector, FPFN fpfn, BYTE fb)
/*end*/
{
   USHORT uFb;                                                /* 149007 */

#ifdef MMIOPH
    MMPHPreVDHSetVPMExcept()
#endif
    ASSERTVDMTASKONLY;
    VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP);
    if( fb & VPMXCPTV86 )               /* 149007 */
    {  /* Setup a V86 Extended Exception Handler 149007 */
       (*pvpmData->vpmd_pav86exc)[iVector].vpmexc_sel = SEGMENTOF32(fpfn);
                                                        /* 149007 */
       (*pvpmData->vpmd_pav86exc)[iVector].vpmexc_off = OFFSETOF32(fpfn);
                                                        /* 149007 */
       (*pvpmData->vpmd_pav86exc)[iVector].vpmexc_fb  = (USHORT)fb;
                                                        /* 149007 */
    }
    else
    {  /* Setup a VPM Extended Exception Handler */
       (*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_sel = SEGMENTOF32(fpfn);
       (*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_off = OFFSETOF32(fpfn);

       /* Once we have a Extended Exception Handler set, we always need to */
       /* provide the Expanded Stack Frame GK      149007                  */
       /* Forced send out Expanded Stack Frame    150343
       if( fb & VPMXCPT10) uFb = ((USHORT) fb) | VPMXCPT10SET;
       else                uFb = (USHORT) fb;
       */
       uFb = ((USHORT) fb) | (USHORT)VPMXCPT10SET;  /* 150343 */  /* 149007 */
       (*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_fb &= ~VPMXCPT10SET;
                                            /* 149007 */
       (*pvpmData->vpmd_pavpmexc)[iVector].vpmexc_fb |= uFb; /* 149007 */
    }

#ifdef MMIOPH
    MMPHPostVDHSetVPMExcept()
#endif
    return(TRUE);
}

#pragma code_seg()
#pragma BEGIN_MVDM_SWAP_CODE

/***EP+ em86DPMITaskSwitch - Switch DPMI task
 *
 *      This routine notifies the kernel that the DPMI task should be
 *      switched. (pdhdHostData is updated by this routine)
 *
 *      ENTRY
 *          pdhd - pointer to host data for new current task.
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 *
 */
INT em86DPMITaskSwitch(PVOID pdhd)
/*end*/
{
   PDHD pdhdnext;
   register PVSF pvsf;                                                  //BN002
   PVPMD new_pvpmData;                                                  //Bx003

   /* Get pvsf */                                                       //BN002
   pvsf = pvsfFrameBase;                                                //BN002

   /* Look for the entry in the list of tasks */
   for (pdhdnext = pdhdHostLast; pdhdnext && (pdhd != pdhdnext);
        pdhdnext = pdhdnext->dhd_pdhdParent) {
   }

   if (pdhdnext) {            // found the entry, update pdhdHostData
      if (pdhd != pdhdHostData) {
         pvpmData->vpmd_flSaveVdmStatus = (flVdmStatus &
                            ~(VDM_STATUS_VPM_EXEC | VDM_STATUS_VPM_IF_FLAG));

         // Save registers for current client (before switch)             BN002
         memcpy(&pvpmData->vpmd_aulVPMCurrentState[3],
                ((flVdmStatus & VDM_STATUS_VPM_EXEC) ?
                     DHD_VPM_SEG_START(pvsf) : DHD_VPM_ALT_SEG_START(pvsf)),
                VSF_SEG_SIZE);

         pdhdHostData = pdhd;
         *((PULONG *)pdhdHostData->dhd_ppDosX) =
                            (PULONG)pdhdHostData->dhd_pDosX;
                                // 149895 restore current puxtd for VDPX

//Bx003         pvpmData = pdhdHostData->dhd_pvpmData;
//Bx003         SELSwitchVdmLDT(&(pvpmData->vpmd_LDTswinfo));       // switch the LDT
         new_pvpmData = pdhdHostData->dhd_pvpmData;                     //Bx003
         SELSwitchVdmLDT(&(new_pvpmData->vpmd_LDTswinfo),               //Bx003
                         &(pvpmData->vpmd_LDTswinfo));        // switch the LDT
         pvpmData = pdhdHostData->dhd_pvpmData;                         //Bx003

      /* em86LoadVPMIDT(); */   /* @V3.0RV01 - 147884 */     // switch the IDT
         flVdmStatus &= (VDM_STATUS_VPM_EXEC | VDM_STATUS_VPM_IF_FLAG);
         flVdmStatus |= pvpmData->vpmd_flSaveVdmStatus;


         if (flVdmStatus & VDM_STATUS_VPM_EXEC)              /*@V3.0RV01*/
           {  /* new task must be running in VPM */          /*@V3.0RV01*/
             em86LoadVPMIDT();                               /*@V3.0RV01*/
           }                                                 /*@V3.0RV01*/


         // Restore registers for new client (after switch)               BN002
         memcpy(((flVdmStatus & VDM_STATUS_VPM_EXEC) ?
                     DHD_VPM_SEG_START(pvsf) : DHD_VPM_ALT_SEG_START(pvsf)),
                &pvpmData->vpmd_aulVPMCurrentState[3],
                VSF_SEG_SIZE);
      }
      return(TRUE);
   } else {                   // entry not found, return error
      return(FALSE);
   }

}

#pragma END_MVDM_SWAP_CODE
#pragma code_seg("SWAP32_24","CODE")
/***EP+ VDHCheckVPMIntVector - returns if a VDM protected mode handler exists
 *
 *      This function returns TRUE if the application protect
 *      mode interrupt vector is set.
 *
 *      ENTRY
 *          iVector
 *              interrupt vector number
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *              no VDM protected mode user handler
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 *
 *      get selector/offset from interrupt shadow table
 *      if default handler address (a special interrupt VPM breakpoint address)
 *          return FALSE
 *      return TRUE
 */

BOOL VDHENTRY VDHCheckVPMIntVector(iVector)
ULONG iVector;
/*end*/
{
#ifdef MMIOPH
    MMPHPreVDHCheckVPMIntVector()
#endif
    ASSERTVDMTASKONLY;
    //VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP); /* 149007 */
    if( !(flVdmStatus & VDM_STATUS_VPM_APP ) )         /* 149007 */
    {                                                  /* 149007 */
       return( FALSE );                                /* 149007 */
    }                                                  /* 149007 */

    if(((*pvpmData->vpmd_pavpmint)[iVector].vpmint_sel == selVPMBP) &&
      ((*pvpmData->vpmd_pavpmint)[iVector].vpmint_off == iVector)) {
#ifdef MMIOPH
        MMPHPostVDHCheckVPMIntVector()
#endif
        return(FALSE);
    }
#ifdef MMIOPH
    MMPHPostVDHCheckVPMIntVector()
#endif
    return(TRUE);
}

#pragma code_seg("SWAP32_24","CODE")
/***EP+ VDHGetVPMIntVector - returns the VDM protected mode interrupt vector
 *
 *      This service gets the application ring3 handler
 *      in the protect mode interrupt chain.  This should
 *      be used only for DPMI support.
 *
 *      ENTRY
 *          iVector
 *              interrupt vector number
 *          pfpfn
 *              pointer to put handler address
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE    // BUGBUG note that it only returns TRUE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 *
 *      get selector/offset from interrupt shadow table
 */

BOOL VDHENTRY VDHGetVPMIntVector(iVector, pfpfn)
ULONG iVector;
PFPFN pfpfn;
/*end*/
{
#ifdef MMIOPH
    MMPHPreVDHGetVPMIntVector()
#endif
    ASSERTVDMTASKONLY;
    if( !(flVdmStatus & VDM_STATUS_VPM_APP ) )         /* 149007 */
    {                                                  /* 149007 */
       return( FALSE );                                /* 149007 */
    }                                                  /* 149007 */
                                                       /* 149007 */
//    VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP); /* 149007 */
    SEGMENTOF32(*pfpfn) = (*pvpmData->vpmd_pavpmint)[iVector].vpmint_sel;
    OFFSETOF32(*pfpfn) = (*pvpmData->vpmd_pavpmint)[iVector].vpmint_off;
#ifdef MMIOPH
    MMPHPostVDHGetVPMIntVector()
#endif
    return(TRUE);
}

#pragma code_seg("SWAP32_25","CODE")
/***EP+ VDHSetVPMIntVector - sets the VDM protected mode interrupt vector
 *
 *      This service sets the application ring3 handler
 *      in the protect mode interrupt chain.  This should
 *      be used only for DPMI support.
 *
 *      ENTRY
 *          iVector
 *              interrupt vector number
 *          fpfn
 *              far32 handler address
 *
 *      EXIT-SUCCESS
 *          returns TRUE
 *
 *      EXIT-FAILURE
 *          returns FALSE
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 *
 *      set selector/offset into interrupt shadow table
 *      update IDT entry
 *      return success
 */

BOOL VDHENTRY VDHSetVPMIntVector(iVector, fpfn)
ULONG iVector;
FPFN fpfn;
/*end*/
{
#ifdef MMIOPH
    MMPHPreVDHSetVPMIntVector()
#endif
    ASSERTVDMTASKONLY;
    VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP);
    (*pvpmData->vpmd_pavpmint)[iVector].vpmint_sel = SEGMENTOF32(fpfn);
    (*pvpmData->vpmd_pavpmint)[iVector].vpmint_off = OFFSETOF32(fpfn);
    em86UpdateIDT(iVector);

    // Check if they are modifying Int 08 or Int 1C (timer interrupts) and set
    // the corresponding bits in flVdmStatus.
    if ((iVector == BIOSINT_CLOCKTICK) || (iVector == BIOSINT_TIMERINTERRUPT)) {
       if (VDHCheckVPMIntVector(BIOSINT_TIMERINTERRUPT)) {
          flVdmStatus |= VDM_STATUS_VPM_08_HOOK;      // They hooked Int 8
       } else {
          flVdmStatus &= ~VDM_STATUS_VPM_08_HOOK;     // They restored Int 8
       }
       if (VDHCheckVPMIntVector(BIOSINT_CLOCKTICK)) {
          flVdmStatus |= VDM_STATUS_VPM_1C_HOOK;      // They hooked 1C
       } else {
          flVdmStatus &= ~VDM_STATUS_VPM_1C_HOOK;     // They restored 1C
       }
    }
#ifdef MMIOPH
    MMPHPostVDHSetVPMIntVector()
#endif
    return(TRUE);
}



#pragma code_seg("SWAP32_26","CODE")
/***EP+ VDHArmVPMBPHook - Obtain a VDM protected mode breakpoint address
 *
 *      Obtains the address of the VDM protected mode breakpoint
 *      allocated by a previous call to VDHAllocHook with the
 *      VDH_BP_HOOK flag.  Unlike other allocated/armed hooks,
 *      breakpoint hooks are armed until explicitly disarmed by
 *      a call to VDHFreeHook.
 *
 *      When the breakpoint address is executed from VDM protected
 *      mode, the hook function is called.  Any changes made to the client
 *      register frame cause the corresponding registers to take on the
 *      values upon return to the VDM .  The PVOID parameter points to
 *      the cbRefData bytes of data allocated by VDHAllocHook.
 *
 *      The VDHArmVPMBPHook service provides a "raw" breakpoint service.
 *      Upon entry to the arm hook function, the client's CS:EIP
 *      is randomly set; hence, it is crucial that the VDD's hook handler
 *      set the CS:EIP to a valid address.  Typically, the CS:EIP is
 *      retrieved from the client's stack (via VDHPopStack).
 *
 *      This is a low-level service.  Appropriate care should be
 *      exercised to ensure that the client's CS:EIP and stack
 *      remain valid.
 *
 *      ENTRY
 *          hhook
 *              hook handle allocated with VDHAllocHook
 *
 *      EXIT-SUCCESS
 *          fpfn
 *              VDM protected mode breakpoint address
 *
 *      EXIT-FAILURE
 *          System Halt.
 *              If hhook is invalid
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *          1) Hook routine interface:
 *              VOID HOOKENTRY arm(p, pcrf)
 *                  ENTRY  p - pointer to hook-specific reference data
 *                         pcrf - pointer to client register frame
 *
 *                  EXIT   none.
 *
 *                  the function must use Pascal calling conventions.
 *
 *                  CONTEXT VDM Task
 *
 *      PSEUDO-CODE
 *
 *      validate calling context and parameters
 *      get VDM protected mode breakpoint address from the hook
 */

FPFN VDHENTRY VDHArmVPMBPHook(hhook)
HHOOK hhook;
/*end*/
{
    FPFN fpfn;

#ifdef MMIOPH
    MMPHPreVDHArmVPMBPHook()
#endif
    // Validate calling context and parameters
    ASSERTVDMTASKONLY;
    em86AssertP(HOOK, (PHOOK)hhook);
    em86AssertP(VDMBP, (PVDMBP)hhook);
    em86AssertP(RETH, (PRETH)hhook);
    VDHAssertTRUE(KMQueryHookType(hhook) == VDH_BP_HOOK);
    VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_APP);

    SEGMENTOF32(fpfn) = selVPMBP;
    OFFSETOF32(fpfn) = (ULONG)((SEGMENTOF16(((PRETH)hhook)->reth_vpvdmbp) -
      SEGMENTOF16(vpVdmBpArpl)) + VPM_VDMBP_START);
#ifdef MMIOPH
    MMPHPostVDHArmVPMBPHook()
#endif
    return(fpfn);
}

#pragma code_seg("SWAP32_24","CODE")
/***EP+ VDHBeginUseVPMStack - begin using the VDM protected mode stack
 *
 *      This service is used to switch to the VDM protected mode stack
 *      for hardware interrupts/exceptions, etc.  This call may be called
 *      repeatedly, but only the first call will switch stacks.  Subsequent
 *      calls will increment use count, but remain on the VPM stack.
 *
 *      ENTRY
 *          None.
 *
 *      EXIT-SUCCESS
 *          None.
 *
 *      EXIT-FAILURE
 *          None.
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 */

VOID VDHENTRY VDHBeginUseVPMStack()
/*end*/
{
    register PVSF pvsf;

#ifdef MMIOPH
    MMPHPreVDHBeginUseVPMStack()
#endif
    ASSERTVDMTASKONLY;
    VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_EXEC);
    if((pvpmData->vpmd_cVPMStack)++ == 0) {                             //BC002
        pvsf = pvsfFrameBase;
        pvpmData->vpmd_selOldVPMSS = VSF_SS(pvsf);                      //BC002
        pvpmData->vpmd_ulOldVPMESP = VSF_ESP(pvsf);                     //BC002
        VSF_SS(pvsf) = pvpmData->vpmd_selVPMStack;                      //BC002
        VSF_ESP(pvsf) = VPM_STACK_SIZE;
    }
#ifdef MMIOPH
    MMPHPostVDHBeginUseVPMStack()
#endif
}

#pragma code_seg("SWAP32_24","CODE")
/***EP+ VDHEndUseVPMStack - end using the VDM protected mode stack
 *
 *      This service must be called once from every call made to
 *      VDHBeginUseVPMStack.  It will switch back to the original
 *      VDM protected mode stack when the use count goes to zero.
 *
 *      ENTRY
 *          None.
 *
 *      EXIT-SUCCESS
 *          None.
 *
 *      EXIT-FAILURE
 *          None.
 *
 *      CONTEXT
 *          VDM Task
 *
 *      NOTES
 *
 *      PSEUDO-CODE
 */

VOID VDHENTRY VDHEndUseVPMStack()
/*end*/
{
    register PVSF pvsf;

#ifdef MMIOPH
    MMPHPreVDHEndUseVPMStack()
#endif
    ASSERTVDMTASKONLY;
    pvsf = pvsfFrameBase;
    VDHAssertTRUE(flVdmStatus & VDM_STATUS_VPM_EXEC);

    if((--(pvpmData->vpmd_cVPMStack) == 0)                              //BC002
           && (VSF_SS(pvsf) == pvpmData->vpmd_selVPMStack)) {           //BC002

        VSF_SS(pvsf)  = pvpmData->vpmd_selOldVPMSS;                     //BC002
        VSF_ESP(pvsf) = pvpmData->vpmd_ulOldVPMESP;                     //BC002
    }
#ifdef MMIOPH
  MMPHPostVDHEndUseVPMStack()
#endif
}

#pragma code_seg("SWAP32_26","CODE")
/***LP  VDHProbeUBuf - Check user buffer is accessible
 *
 *      This routine checks that a user buffer is accessible
 *      for the intended use at ring 3.  This routine can
 *      be called with the client in either protect mode or
 *      V86 mode, but the exception is always raised in protect
 *      mode since applications only expect exceptions in
 *      their protect mode space when in protect mode.
 *      The exception occurs in the current protect mode task.
 *      The return after an exception is handled is to the mode
 *      that the client was in when this routine was called
 *      (modifiable with a flag).
 *
 *      If an exception would occur when accessing user space,
 *      the routine restores the V86 CS:EIP for the mode that
 *      the client was in when the routine was called and then
 *      prepares to route the exception to protect mode.
 *      The kernel increments CS:EIP when traps occur,
 *      so it must save the old value to restore CS:EIP
 *      when an exception occurs.  This allows the application
 *      to repeat the instruction that generated the initial
 *      trap to ring 0 after the exception is handled.
 *
 *      The actual exception reflection to the client occurs
 *      only when returning to the client after the caller
 *      of this function returns.  The kernel needs to
 *      note that it is raising an exception and prepare for
 *      it after the caller has had a chance to clean up.
 *      The caller may also need to clean up the client's
 *      stack, so this routine cannot set up the exception
 *      before the return to ring 3.
 *
 *      If the client handles the exception condition,
 *      the original trap into ring 0 will then be repeated,
 *      but this time the call to this function will succeed.
 *      If the client's protect mode exception handler returns
 *      a different CS:EIP in its exception frame, however,
 *      the return is to that protect mode address.
 *
 *      The caller to this function should clean up and return
 *      immediately if this function returns failure.  The caller
 *      must exit in the same state as when entered so that
 *      after exception handling, it can repeat the request.
 *
 *      Exception handling in DPMI seems complex when first
 *      introduced to it.  See the DPMI spec for details.
 *
 *      ENTRY   sel = Selector of buffer
 *              ulStartOff = offset of first byte that will be accessed
 *              cCount = number of bytes to access
 *              fl
 *               VPM_PROT_READ       -- Check for read
 *               VPM_PROT_WRITE      -- Check for write
 *               VPM_FAULT_IF_RW_SET -- Fault if R/W bit set
 *               VPM_FAULT_IF_SU_SET -- Fault if S/U bit set
 *               VPM_SEL_WRITEABLE   -- Caller knows descriptor is writable
 *               VPM_SEL_IS_SS       -- Selector is client's stack
 *               VPM_SEL_PRESENT     -- Caller knows descriptor is present
 *               VPM_FAULT_IF_RO     -- Caller does not know if descriptor
 *                                      is read only (Do not convert
 *                                      to flat address without checking)
 *               VPM_XCPTRET_ALT     -- After exception, return to
 *                                      alternate mode (e.g. if
 *                                      client was in protect mode
 *                                      when the service was called,
 *                                      return in V86 mode after
 *                                      the exception is handled
 *
 *      EXIT    if success
 *                  return TRUE
 *              else
 *                  return FALSE - exception was raised
 *
 *      CONTEXT VDM Task, client in either mode
 *
 */
BOOL VDHENTRY VDHProbeUBuf(SEL sel, ULONG ulStartOff, ULONG cCount, ULONG fl)
{
    BYTE bDstOrSrc;
    ULONG ulEndOff;     // Last byte accessed
    BOOL fRet = FALSE;

#ifdef MMIOPH
    MMPHPreVDHProbeUBuf()
#endif
    VDHAssertTRUE(fl & (VPM_PROT_WRITE | VPM_PROT_READ));

    ulEndOff = ulStartOff + cCount - 1;

    // VDHWriteUBuf and VDHReadUBuf will raise an exeption if the access fails

    if (fl & VPM_PROT_WRITE) {
        fRet = VDHWriteUBuf(SSToDS(&bDstOrSrc),
                           sizeof(bDstOrSrc),
                           sel,
                           SSToDS(&ulStartOff),
                           fl)
            && VDHWriteUBuf(SSToDS(&bDstOrSrc),
                           sizeof(bDstOrSrc),
                           sel,
                           SSToDS(&ulEndOff),
                           fl);
    } else if (fl & VPM_PROT_READ) {
        fRet = VDHReadUBuf(SSToDS(&bDstOrSrc),
                           sizeof(bDstOrSrc),
                           sel,
                           SSToDS(&ulStartOff),
                           fl)
            && VDHReadUBuf(SSToDS(&bDstOrSrc),
                           sizeof(bDstOrSrc),
                           sel,
                           SSToDS(&ulEndOff),
                           fl);
    }

#ifdef MMIOPH
    MMPHPostVDHProbeUBuf()
#endif
    return(fRet);
}

#pragma code_seg("SWAP32_26","CODE")
/***LP  VDHPopVPMFarRet - Pop from user's stack to user's CS:(E)IP.
 *
 *      This routine pops the far return address from the user's
 *      stack into the user's CS:(E)IP in the CRF.  Accessing the
 *      client's protect mode stack could cause a fault.  If a fault
 *      would occur at ring 3, failure is returned to the caller
 *      and the exception is routed to the client in protect mode
 *      when returning to ring 3.
 *
 *      On a 386, whether IP or EIP is used depends on the B bit
 *      of the client stack segment.
 *
 *      If an exception would occur when accessing user space,
 *      the routine restores the CS:EIP and then prepares
 *      to route the exception.
 *
 *      The kernel increments CS:EIP when traps occur,
 *      so it must save the old value to restore CS:EIP
 *      when an exception occurs.  This allows the application
 *      to repeat the instruction that generated the initial
 *      trap to ring 0 after the exception is handled.
 *
 *      The actual exception reflection to the client occurs
 *      only when returning to ring 3 after the caller
 *      of this function returns.  The kernel needs to
 *      note that it is raising an exception and prepare for
 *      it after the caller has had a chance to clean up.
 *      The caller may also need to clean up the client's
 *      stack, so this routine cannot set up the exception
 *      until the client is about to return to ring 3.
 *
 *      If the client handles the exception condition,
 *      the original trap into ring 0 will then be repeated,
 *      but this time the call to this function will succeed.
 *      If the client's protect mode exception handler returns
 *      a different CS:EIP in its exception frame, however,
 *      the return is to that protect mode address.
 *
 *      The caller to this function should clean up and return
 *      immediately if this function returns failure.  The caller
 *      must exit in the same state as when entered so that
 *      after exception handling, it can repeat the request.
 *
 *      Exception handling in DPMI seems complex when first
 *      introduced to it.  See the DPMI spec for details.
 *
 *  ENTRY   none
 *
 *  EXIT    if success
 *              return TRUE
 *          else
 *              return FALSE - exception was raised
 *
 *  CONTEXT VDM Task, client in protect mode
 *
 */
BOOL VDHENTRY VDHPopVPMFarRet()
{

PCRF  pcrf;
int   rc;

    // Get pointer to client register frame

#ifdef MMIOPH
    MMPHPreVDHPopVPMFarRet()
#endif
    pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);

    if (flVdmStatus & VDM_STATUS_VPM_32) {
        rc = VDHPopStack(8, &(pcrf->crf_eip));
    } else {
        if (rc = VDHPopStack(2, &IP(pcrf))) {
           rc = VDHPopStack(2, &CS(pcrf));
        }
    }

#ifdef MMIOPH
    MMPHPostVDHPopVPMFarRet()
#endif
    return(rc);

}   // end VDHPopFarRet


#pragma code_seg()
#pragma BEGIN_MVDM_SWAP_CODE

/***LP  VDHPrepVPMIret - Prepare for a hooked call to VPM
 *
 *      This routine sets up for a call to protect mode from V86
 *      mode for an application.  It traps the far return in protect
 *      mode.  This routine does not set the destination address
 *      for the protect mode call.  It does the stack preparation
 *      on the user's protect mode stack that could generate
 *      and exception.  This is called by ring 0 code when
 *      the client is in V86 mode.
 *
 *      Switches the client to protect mode
 *      Switches to the locked protect mode stack
 *      Arms the hook to catch the return from VPM
 *      Pushes a iret return frame onto the client's stack.
 *
 *      The CS:EIP in the client's register frame is undefined
 *      when this routine returns.  The caller will fill in
 *      CS:EIP.
 *
 *      If an exception would occur when accessing user space,
 *      the routine restores the V86 CS:EIP and then
 *      prepares to route the exception to protect mode.
 *      The kernel increments CS:EIP when traps occur,
 *      so it must save the old value to restore CS:EIP
 *      when an exception occurs.  This allows the application
 *      to repeat the instruction that generated the initial
 *      trap to ring 0 after the exception is handled.
 *
 *      The actual exception reflection to the client occurs
 *      only when returning to the client after the caller
 *      of this function returns.  The kernel needs to
 *      note that it is raising an exception and prepare for
 *      it after the caller has had a chance to clean up.
 *      The caller may also need to clean up the client's
 *      stack, so this routine cannot set up the exception
 *      before the return to ring 3.
 *
 *      If the client handles the exception condition,
 *      the original trap into ring 0 will then be repeated,
 *      but this time the call to this function will succeed.
 *      If the client's protect mode exception handler returns
 *      a different CS:EIP in its exception frame, however,
 *      the return is to that protect mode address.
 *
 *      The caller to this function should clean up and return
 *      immediately if this function returns failure.  The caller
 *      must exit in the same state as when entered so that
 *      after exception handling, it can repeat the request.
 *
 *      Exception handling in DPMI seems complex when first
 *      introduced to it.  See the DPMI spec for details.
 *
 *      ENTRY   hhookReturnHook = hook to catch return from VPM
 *
 *      EXIT    if success
 *                  return TRUE
 *              else
 *                  return FALSE - exception was raised
 *
 *      CONTEXT VDM Task, task in V86 mode
 *
 */

BOOL VDHENTRY VDHPrepVPMIret(HHOOK hhookReturnHook)

{

IRET16 iret16;
IRET32 iret32;
PCRF   pcrf;
int    rc;

#ifdef MMIOPH
    MMPHPreVDHPrepVPMIret()
#endif
    // Get pointer to client register frame

    pcrf = (PCRF)VDHQuerySysValue(CURRENT_VDM, VDHLSV_PCRF);

    // Switch client to protect mode

    VDHSwitchToVPM();

    // Switch to protect mode locked stack

    VDHBeginUseVPMStack();

    // Set up to catch return from the protect mode routine

    VDHArmReturnHook(hhookReturnHook, VDHARH_RECURSIVE_CSEIP_HOOK);

    // Save the return address that's in CS:IP onto client's stack
    // and the flags, since we are going to return from the Vpm routine
    // with an IRET

    if (flVdmStatus & VDM_STATUS_VPM_32) {

        iret32.iret32_eflag = (ULONG)FL(pcrf);
        iret32.iret32_cs = CS(pcrf);
        iret32.iret32_eip = pcrf->crf_eip;
        rc = VDHPushStack(sizeof(IRET32), SSToDS(&iret32));

    } else {

        iret16.iret16_flag = FL(pcrf);
        iret16.iret16_cs = CS(pcrf);
        iret16.iret16_ip = IP(pcrf);
        rc = VDHPushStack(sizeof(IRET16), SSToDS(&iret16));

    }

#ifdef MMIOPH
    MMPHPostVDHPrepVPMIret()
#endif
    return (rc);
}

/***ET+ VPMPgMapPhys - map physical page
 *
 *      This function receives requests to map physical pages
 *      in the VDM for use by the client.  The kernel can decide
 *      whether honoring a request is safe and refuse to honor
 *      those that are not.
 *
 *      ENTRY:  pladdr    - pointer to target page index
 *                          *pladdr == -1 means any arbitrary address
 *                          (must be on page boundary)
 *              ulPhys    - physical address to map
 *              cb        - count of bytes
 *
 *      EXIT:   TRUE     - indicates success
 *              FALSE    - indicates request was refused
 */
BOOL VPMPgMapPhys(VMAC *pvmac, ULONG ulPhys, ULONG cb)
/*end*/
{
   ULONG fl, ulcount, ulpgend, ulpgbegin;
   VPMINF vpminf;

   // Set allocation flags
   if (pvmac->ac_va != -1) {
      fl = VMAC_LOCSPECIFIC;
   } else {
      pvmac->ac_va = _4MEG;         // allocate above 4 meg
      fl = VMAC_LOCABOVE;
   }

   ulpgbegin = ulPhys / PAGESIZE;
   ulpgend = (ulPhys+cb) / PAGESIZE;

   // Check if request is in physical RAM
   if (SELGetVdmInfo(SSToDS(&vpminf)) == NO_ERROR) {

      // Check if request overlaps physical memory, and if so fail the request
      for (ulcount = 0; ulcount < vpminf.vpmsel_cphysranges; ulcount++) {
         if (((ulpgbegin <= vpminf.vpmsel_physranges[ulcount].pr_lastframe) &&
              (ulpgbegin >= vpminf.vpmsel_physranges[ulcount].pr_firstframe)) ||
             ((ulpgend <= vpminf.vpmsel_physranges[ulcount].pr_lastframe) &&
              (ulpgend >= vpminf.vpmsel_physranges[ulcount].pr_firstframe)) ||
             ((ulpgend > vpminf.vpmsel_physranges[ulcount].pr_lastframe) &&
              (ulpgbegin < vpminf.vpmsel_physranges[ulcount].pr_firstframe))) {
           return(FALSE);
         }
      }

      fl |= VMAC_ARENAPRV | VMAC_VDM | VMAC_ALIGNPAGE | PG_R | PG_W | PG_X |
            PG_U | PG_UVIRT;

      if (VMAllocMem(cb, cb, fl, 0, 0, 0, 0, ulPhys, pvmac) == NO_ERROR) {
         return(TRUE);
      }
   }

   return(FALSE);
} // end VPMPgMapPhys




/*** EM86VPMExpExcRetHook - The Exceptional handler Return process
 *                           Return from Expand Return address  149007
 *      ENTRY:  pData     - pointer to Hook data                149007
 *              pcrf      - pointer of client register frame    149007
 *                                                              149007
 *      EXIT:   None                                            149007
 *                                                              149007
 *      Metho:                                                  149007
 *       Read in the Expanded Stack Frame                       149007
 *       set them to the corresponding CRF registers            149007
 *                                                              149007
 */
void HOOKENTRY EM86VPMExpExcRetHook( PVOID pData, PCRF pcrf )   /* 149007 */
{                                                               /* 149007 */
   EXEXCST exexcst;                                             /* 149007 */
   ULONG   ulOffset;                                            /* 149007 */
                                                                /* 149007 */
   PRINTDEBUG( "EM86VPMExpExcRetHook\n" );                      /* 149007 */
   ulOffset = (flVdmStatus & VDM_STATUS_VPM_32)? pcrf->crf_esp :/* 149007 */
                     (ULONG)(SP( pcrf ) + 4);                   /* 149007 */
   pData; /* Avoid warning */                                   /* 149007 */
   if( !VDHReadUBuf( SSToDS( &(exexcst.exexcst_errcode)),       /* 149007 */
                     sizeof(EXEXCST) - sizeof(EXC32) - 8, SS( pcrf ), /* 149007 */
                     SSToDS( &ulOffset),  0  ) )                /* 149007 */
   {   /* VDHRaedUBuf error */                                  /* 149007 */
      TRAPProcessFatalFault( 0xd, SS(pcrf ) );                  /* 149007 */
      return;                                                   /* 149007 */
   }                                                            /* 149007 */
   PRINTDEBUG( "EM86VPMExpExcRetHook1\n" );                     /* 149007 */
                                                                /* 149007 */
   VDHEndUseVPMStack();    /* End use VPM stack */              /* 149007 */
                                                                /* 149007 */
   PRINTDEBUG( "EM86VPMExpExcRetHook1\n" );                     /* 149007 */
   if(flVdmStatus & VDM_STATUS_VPM_32)                          /* 149007 */
   {  /* 32 Bit */                                              /* 149007 */
      pcrf->crf_cs  = exexcst.exexcst_cs;                       /* 149007 */
      pcrf->crf_eip = exexcst.exexcst_eip;                      /* 149007 */
      VDHSetFlags( pcrf->crf_eflag = exexcst.exexcst_eflags );  /* 149007 */
      pcrf->crf_esp = exexcst.exexcst_esp;                      /* 149007 */
      pcrf->crf_ss  = exexcst.exexcst_ss;                       /* 149007 */
      pcrf->crf_es  = exexcst.exexcst_es;                       /* 149007 */
      pcrf->crf_ds  = exexcst.exexcst_ds;                       /* 149007 */
      pcrf->crf_fs  = exexcst.exexcst_fs;                       /* 149007 */
      pcrf->crf_gs  = exexcst.exexcst_gs;                       /* 149007 */
   }                                                            /* 149007 */
   else                                                         /* 149007 */
   {  /* 16 bit Task */                                         /* 149007 */
      pcrf->crf_cs  = exexcst.exexcst_cs;                       /* 149007 */
      *((USHORT *)&(pcrf->crf_eip)) = (USHORT)exexcst.exexcst_eip;/* 149007 */
      VDHSetFlags( pcrf->crf_eflag = exexcst.exexcst_eflags );     /* 149007 */
      *((USHORT *)&(pcrf->crf_esp)) = (USHORT)exexcst.exexcst_esp; /* 149007 */
      pcrf->crf_ss  = exexcst.exexcst_ss;                          /* 149007 */
      pcrf->crf_es  = exexcst.exexcst_es;                          /* 149007 */
      pcrf->crf_ds  = exexcst.exexcst_ds;                          /* 149007 */
      pcrf->crf_fs  = exexcst.exexcst_fs;                          /* 149007 */
      pcrf->crf_gs  = exexcst.exexcst_gs;                          /* 149007 */
   }                                                               /* 149007 */
                                                                   /* 149007 */
   PRINTDEBUG( "EM86VPMExpExcRetHook 2\n" );                       /* 149007 */
   return;                                                         /* 149007 */
}                                                                  /* 149007 */
                                                                   /* 149007 */
                                                                   /* 149007 */
                                                                   /* 149007 */
/*** EM86V86ExpExcRetHook - The Exceptional handler Return process 149007
 *                           Return from Expand Return address    149007
 *      ENTRY:  pData     - pointer to Hook data                149007
 *              pcrf      - pointer of client register frame    149007
 *                                                              149007
 *      EXIT:   None                                            149007
 *                                                              149007
 *      Metho:                                                  149007
 *       Read in the Expanded Stack Frame                       149007
 *       set them to the corresponding CRF registers            149007
 *                                                              149007
 *
 */
void HOOKENTRY EM86V86ExpExcRetHook( PVOID pData, PCRF pcrf )       /* 149007 */
{                                                                 /* 149007 */
   EXEXCST exexcst;                                               /* 149007 */
   ULONG   ulOffset;                                              /* 149007 */
                                                                  /* 149007 */
   pData; /* Avoid warning */                                     /* 149007 */
   ulOffset = (flVdmStatus & VDM_STATUS_VPM_32)? pcrf->crf_esp :  /* 149007 */
                     (ULONG)(SP( pcrf ) + 4);                     /* 149007 */
                                                                  /* 149007 */
   if( !VDHReadUBuf( SSToDS( &(exexcst.exexcst_errcode)),         /* 149007 */
                     sizeof(EXEXCST) - (sizeof(EXC32) + 8), SS( pcrf ),
                     SSToDS( &ulOffset ),  0  ) )                 /* 149007 */
   {   /* VDHRaedUBuf error */                                    /* 149007 */
      TRAPProcessFatalFault( 0xd, SS(pcrf ) );                    /* 149007 */
      return;                                                     /* 149007 */
   }                                                              /* 149007 */
                                                                  /* 149007 */
   VDHEndUseVPMStack();    /* End use VPM stack */                /* 149007 */
                                                                  /* 149007 */
   /* This is for V86 mode, it's always 16 bit */                 /* 149007 */
   *((USHORT *)&(pcrf->crf_altesp))   = (USHORT)exexcst.exexcst_esp;   /* 149007 */
   *((USHORT *)&(pcrf->crf_alteflag)) = (USHORT)exexcst.exexcst_eflags;/* 149007 */
   *((USHORT *)&(pcrf->crf_alteip))   = (USHORT)exexcst.exexcst_eip;   /* 149007 */
   pcrf->crf_altcs = exexcst.exexcst_cs;                          /* 149007 */
   pcrf->crf_altss = exexcst.exexcst_ss;                          /* 149007 */
   pcrf->crf_altes = exexcst.exexcst_es;                          /* 149007 */
   pcrf->crf_altds = exexcst.exexcst_ds;                          /* 149007 */
                                                                  /* 149007 */
   VDHPrimaryDPMITask( FALSE );     /* Switch original DPMI task   * 149007 */
   VDHSwitchToV86();                                              /* 149007 */
                                                                  /* 149007 */
   return;                                                        /* 149007 */
}                                                                 /* 149007 */


/*** EM86V86ExpExc9RetHook - The Exceptional handler Return process
 *                           Return from 0.9 return address    149007
 *      ENTRY:  pData     - pointer to Hook data                149007
 *              pcrf      - pointer of client register frame    149007
 *                                                              149007
 *      EXIT:   None                                            149007
 *                                                              149007
 *      Metho:                                                  149007
 *       Read in the Expanded Stack Frame                       149007
 *       set them to the corresponding CRF registers            149007
 *                                                              149007
 */
void HOOKENTRY EM86V86ExpExc9RetHook( PVOID pData, PCRF pcrf )     /* 149007 */
{                                                                  /* 149007 */
   EXEXCST exexcst;                                                /* 149007 */
   EXCST   *pexcst;                                                /* 149007 */
   ULONG   ulOffset;                                               /* 149007 */
                                                                   /* 149007 */
   pData; /* Avoid warning */                                      /* 149007 */
   ulOffset = (flVdmStatus & VDM_STATUS_VPM_32)? pcrf->crf_esp :   /* 149007 */
                     (ULONG)(SP( pcrf ));                          /* 149007 */
                                                                   /* 149007 */
   if( !VDHReadUBuf( SSToDS( &exexcst),                            /* 149007 */
                     sizeof(EXEXCST), SS( pcrf ),                  /* 149007 */
                     SSToDS( &ulOffset),  0  ) )                   /* 149007 */
   {   /* VDHRaedUBuf error */                                     /* 149007 */
      TRAPProcessFatalFault( 0xd, SS(pcrf ) );                     /* 149007 */
      return;                                                      /* 149007 */
   }                                                               /* 149007 */
                                                                   /* 149007 */
   VDHEndUseVPMStack();    /* End use VPM stack */                 /* 149007 */
                                                                   /* 149007 */
   if( flVdmStatus & VDM_STATUS_VPM_32 )                           /* 149007 */
   {                                                               /* 149007 */
      *((USHORT *)&(pcrf->crf_altesp)) =                           /* 149007 */
                               (USHORT)exexcst.oldexc32.exc32_esp; /* 149007 */
      *((USHORT *)&(pcrf->crf_alteflag)) =                         /* 149007 */
                               (USHORT)exexcst.oldexc32.exc32_eflags;/* 149007 */
      *((USHORT *)&(pcrf->crf_alteip)) =                           /* 149007 */
                               (USHORT)exexcst.oldexc32.exc32_eip; /* 149007 */
      pcrf->crf_altcs = exexcst.oldexc32.exc32_cs;                 /* 149007 */
      pcrf->crf_altss = exexcst.oldexc32.exc32_ss;                 /* 149007 */
   }                                                               /* 149007 */
   else                                                            /* 149007 */
   {                                                               /* 149007 */
      pexcst = SSToDS( &exexcst );                                 /* 149007 */
      *((USHORT *)&(pcrf->crf_altesp)) =                           /* 149007 */
                               (USHORT)pexcst->excst_sp;           /* 149007 */
      *((USHORT *)&(pcrf->crf_alteflag)) =                         /* 149007 */
                               (USHORT)pexcst->excst_flags;        /* 149007 */
      *((USHORT *)&(pcrf->crf_alteip)) =                           /* 149007 */
                               (USHORT)pexcst->excst_ip;           /* 149007 */
      pcrf->crf_altcs = pexcst->excst_cs;                          /* 149007 */
      pcrf->crf_altss = pexcst->excst_ss;                          /* 149007 */
   }                                                               /* 149007 */
                                                                   /* 149007 */
   VDHPrimaryDPMITask( FALSE );     /* Switch original DPMI task *//* 149007 */
   VDHSwitchToV86();                                               /* 149007 */
                                                                   /* 149007 */
   return;                                                         /* 149007 */
}                                                                  /* 149007 */


/*** EM86ReflectV86ExpException - The Exceptional handler for V86
 *               Reflect the Exception back to its handler    149007
 *               while Client is in V86 mode                  149007
 *                                                            149007
 *      ENTRY:  iExcept   - Exception Number                    149007
 *              pcrf      - pointer of client register frame    149007
 *              iErrcode  - Error code                          149007
 *      EXIT:   None                                            149007
 *                                                              149007
 *      Metho:                                                  149007
 *       Read in the Expanded Stack Frame                       149007
 *       set them to the corresponding CRF registers            149007
 *                                                              149007
 *   return                                                     149007
 *     TRUE  -- The Exception is handled                        149007
 *     FALSE -- The Exception is not handled                    149007
 *                                                              149007
 *  Method:                                                     149007
 *     Switch to Client Protected Mode                          149007
 *     Switch to Primary Client                                 149007
 *     Set up the Expanded Stack Frame and 0.9 Stack Frame      149007
 *     Arm two return hook for Expanded Stack and 0.9 Stack     149007
 *     Adjust the stack frame if it's 16Bit                     149007
 *     reflect back to client handler                           149007
 *                                                              149007
 */
BOOL EM86ReflectV86ExpException( int iExcept, PCRF pcrf, int iErrcode )
{                                                               /* 149007 */
   EXEXCST exexcst;                                             /* 149007 */
   EXCST   *pexcst;                                             /* 149007 */
   EXC32   *pexc32;                                             /* 149007 */
   ULONG   ulTmp;                                               /* 149007 */
   ULONG   ulOffset;                                            /* 149007 */
   SEL     selTmpCS;                                            /* 149007 */
   ULONG   ulTmpEIP;                                            /* 149007 */
   /* FPFN    fpfn; */                                          /* 149007 */
   struct f32_s                                                 /* 149007 */
   {                                                            /* 149007 */
      OFFSET f32offset;                                         /* 149007 */
      SEL    f32sel;                                            /* 149007 */
   } fpfn;                                                      /* 149007 */
                                                                /* 149007 */
   if(!( flVdmStatus & VDM_STATUS_VPM_APP) )                    /* 149007 */
   {                                                            /* 149007 */
      return( FALSE );                                          /* 149007 */
   }                                                            /* 149007 */

   /* If VW32S pFaultHandler jump in, it should be here. But be careful about
      the mode switching */                                     /* 149007 */

   VDHSwitchToVPM();           /* Switch to Protected Mode       */ /* 149007 */
   VDHPrimaryDPMITask( TRUE ); /* Switch to primary task(client) */ /* 149007 */
   if( (*pvpmData->vpmd_pav86exc)[ iExcept].vpmexc_sel == selVPMBP &&/* 149007 */
       (*pvpmData->vpmd_pav86exc)[ iExcept].vpmexc_off ==            /* 149007 */
                            (ULONG)( VPM_V86EXC_BP_START + iExcept) )/* 149007 */
   {  /* Sorry No V86 extended Exception handler registered */       /* 149007 */
      VDHPrimaryDPMITask( FALSE ); /* Switch to primary task(client) *//* 149007 */
      VDHSwitchToV86();           /* Switch to Protected Mode       */ /* 149007 */
      return( FALSE );                                             /* 149007 */
   }                                                               /* 149007 */
                                                                   /* 149007 */
   /* Process the Expanded Stack */                                /* 149007 */
   memset( SSToDS(&exexcst), 0, sizeof( EXEXCST ) );               /* 149007 */
   /* get the regs from V86*/                                      /* 149007 */
   /* exexcst.exexcst_cs  = pcrf->crf_altcs ; */                   /* 149007 */
   /* exexcst.exexcst_eip = pcrf->crf_alteip; */                   /* 149007 */
   exexcst.exexcst_es     = pcrf->crf_altes;                       /* 149007 */
   exexcst.exexcst_ds     = pcrf->crf_altds;                       /* 149007 */
                                                                   /* 149007 */
   if( iExcept == EXCPG )                                          /* 149007 */
   {                                                               /* 149007 */
      exexcst.exexcst_cr2    = cr2_buf;                            /* 149007 */
      exexcst.exexcst_pte    = 0;   /* The only chance user get page fault */
                                    /* is because the memory is uncommitted*/
   }                                                               /* 149007 */

   VDHBeginUseVPMStack();                                          /* 149007 */

   if( pcrf->crf_esp > sizeof( EXEXCST ))                          /* 149007 */
   {  /* Make room for the expanded stack */                       /* 149007 */
      pcrf->crf_esp -= sizeof( EXEXCST );                          /* 149007 */
   }                                                               /* 149007 */
   else                                                            /* 149007 */
   {                                                               /* 149007 */
      VDHEndUseVPMStack();                                         /* 149007 */
      VDHPrimaryDPMITask( FALSE ); /* Switch to primary task(client)*//* 149007 */
      VDHSwitchToV86();            /* Switch to Protected Mode      *//* 149007 */
      return( FALSE );                                             /* 149007 */
   }                                                               /* 149007 */
   if( flVdmStatus & VDM_STATUS_VPM_32 )                           /* 149007 */
   {  /* 32 bit Client */                                          /* 149007 */
      pexc32 = SSToDS( &exexcst );                                 /* 149007 */
                                                                   /* 149007 */
      pexc32->exc32_errcode = exexcst.exexcst_errcode = iErrcode;  /* 149007 */
      if( iExcept == 0x01 )  /* break point exception? */          /* 149007 */
      {                      /* Yes!                   */          /* 149007 */
         ulTmp = em86GetDr6() ;                                    /* 149007 */
         if( pcrf->crf_eflag & F_TRACE )                           /* 149007 */
            ulTmp |= 0x8000;                                       /* 149007 */
         pexc32->exc32_errcode = exexcst.exexcst_errcode = (ULONG)ulTmp;/* 149007 */
      }                                                            /* 149007 */
      if( flrestart )                                              /* 149007 */
      {                                                            /* 149007 */
         pexc32->exc32_eip = exexcst.exexcst_eip =                 /* 149007 */
                            pcrf->crf_alteip - usEIPincr;          /* 149007 */
         // usEIPincr = 0;                                         /* 149007 */
      }                                                            /* 149007 */
      else                                                         /* 149007 */
      {                                                            /* 149007 */
         pexc32->exc32_eip = exexcst.exexcst_eip = pcrf->crf_alteip;/* 149007 */
      }                                                             /* 149007 */
      pexc32->exc32_cs = exexcst.exexcst_cs = pcrf->crf_altcs;  /* Set CS */
      ulTmp = pcrf->crf_alteflag;                                  /* 149007 */
      if( ulTmp & VDM_STATUS_VME )                                 /* 149007 */
      {                                                            /* 149007 */
         if( ulTmp & F_VIF )                                       /* 149007 */
         {                                                         /* 149007 */
            ulTmp |= F_INTERRUPT;                                  /* 149007 */
         }                                                         /* 149007 */
         else                                                      /* 149007 */
         {                                                         /* 149007 */
            ulTmp &= ~F_INTERRUPT;                                 /* 149007 */
         }                                                         /* 149007 */
      }                                                            /* 149007 */
      else                                                         /* 149007 */
      {                                                            /* 149007 */
        if( !(flVdmStatus & VDM_STATUS_VPM_IF_FLAG ))              /* 149007 */
        {                                                          /* 149007 */
           ulTmp &= ~F_INTERRUPT;                                  /* 149007 */
        }                                                          /* 149007 */
      }                                                            /* 149007 */
      pexc32->exc32_eflags = exexcst.exexcst_eflags = ulTmp;       /* 149007 */
      exexcst.exexcst_ss  = pexc32->exc32_ss  = pcrf->crf_altss;   /* 149007 */
      exexcst.exexcst_esp = pexc32->exc32_esp = pcrf->crf_altesp;  /* 149007 */
                                                                   /* 149007 */
      /* Save CS:EIP for later use */                              /* 149007 */
      selTmpCS = pcrf->crf_cs;                                     /* 149007 */
      ulTmpEIP = pcrf->crf_eip;                                    /* 149007 */
      /* Set return hooker          */                             /* 149007 */
      VDHArmReturnHook( hhookV86ExpExcRetHook,                     /* 149007 */
                        VDHARH_CSEIP_HOOK | VDHARH_ALWAYS_ARM_HOOK );  /* 149007 */
      exexcst.exexcst_ret_cs  = pcrf->crf_cs;                      /* 149007 */
      exexcst.exexcst_ret_eip = pcrf->crf_eip;                     /* 149007 */

      /* Restore CS:EIP for later use */                           /* 149007 */
      pcrf->crf_cs = selTmpCS;                                     /* 149007 */
      pcrf->crf_eip = ulTmpEIP;                                    /* 149007 */
   }                                                               /* 149007 */
   else                                                            /* 149007 */
   {  /* 16 bit client */                                          /* 149007 */
      pexcst = SSToDS( &exexcst );                                 /* 149007 */

      pexcst->excst_errcode =                                      /* 149007 */
          (USHORT)(exexcst.exexcst_errcode = iErrcode);            /* 149007 */
      if( iExcept == 0x01 )     /* break point exception? */       /* 149007 */
      {                         /* Yes!                   */       /* 149007 */
         ulTmp = em86GetDr6() ;                                    /* 149007 */
         if( pcrf->crf_eflag & F_TRACE )                           /* 149007 */
            ulTmp |= 0x8000;                                       /* 149007 */
         pexcst->excst_errcode =                                   /* 149007 */
               (USHORT)(exexcst.exexcst_errcode = ulTmp);          /* 149007 */
      }                                                            /* 149007 */
      if( flrestart )                                              /* 149007 */
      {                                                            /* 149007 */
         pexcst->excst_ip =                                        /* 149007 */
             (USHORT)(exexcst.exexcst_eip = pcrf->crf_alteip - usEIPincr);
         // usEIPincr = 0;                                         /* 149007 */
      }                                                            /* 149007 */
      else                                                         /* 149007 */
      {                                                            /* 149007 */
         pexcst->excst_ip =                                        /* 149007 */
                 (USHORT)( exexcst.exexcst_eip =  pcrf->crf_alteip ); /* 149007 */
      }                                                            /* 149007 */
      pexcst->excst_cs = exexcst.exexcst_cs =  pcrf->crf_altcs;  /* Set CS */
      ulTmp = pcrf->crf_alteflag;                                 /* 149007 */
      if( ulTmp & VDM_STATUS_VME )                                /* 149007 */
      {                                                           /* 149007 */
         if( ulTmp & F_VIF )                                      /* 149007 */
         {                                                        /* 149007 */
            ulTmp |= F_INTERRUPT;                                 /* 149007 */
         }                                                        /* 149007 */
         else                                                     /* 149007 */
         {                                                        /* 149007 */
            ulTmp &= ~F_INTERRUPT;                                /* 149007 */
         }                                                        /* 149007 */
      }                                                           /* 149007 */
      else                                                        /* 149007 */
      {                                                           /* 149007 */
        if( !(flVdmStatus & VDM_STATUS_VPM_IF_FLAG ))             /* 149007 */
        {                                                         /* 149007 */
           ulTmp &= ~F_INTERRUPT;                                 /* 149007 */
        }                                                         /* 149007 */
      }                                                           /* 149007 */
      pexcst->excst_flags =(USHORT)( exexcst.exexcst_eflags = ulTmp);/* 149007 */
      pexcst->excst_ss = exexcst.exexcst_ss  = pcrf->crf_altss;      /* 149007 */
      pexcst->excst_sp = (USHORT)(exexcst.exexcst_esp = pcrf->crf_altesp); /* 149007 */
      /* Save CS:EIP for later use */                                /* 149007 */
      selTmpCS = pcrf->crf_cs;                                       /* 149007 */
      ulTmpEIP = pcrf->crf_eip;                                   /* 149007 */
      /* Set return hooker          */                            /* 149007 */
      VDHArmReturnHook( hhookV86ExpExcRetHook,                    /* 149007 */
                        VDHARH_CSEIP_HOOK | VDHARH_ALWAYS_ARM_HOOK );/* 149007 */
                                                                 /* 149007 */
      /* set up return point as 16:16 */                         /* 149007 */
      ulTmp = pcrf->crf_cs;                                      /* 149007 */
      ulTmp <<= 16;                                              /* 149007 */
      ulTmp += (pcrf->crf_eip & 0xffff);                         /* 149007 */
      exexcst.exexcst_ret_cs = pcrf->crf_cs;  /* dummy */        /* 149007 */
      exexcst.exexcst_ret_eip = ulTmp;                           /* 149007 */
      /* Restore CS:EIP for later use */                         /* 149007 */
      pcrf->crf_cs = selTmpCS;                                   /* 149007 */
      pcrf->crf_eip = ulTmpEIP;                                  /* 149007 */
   }                                                             /* 149007 */
                                                                 /* 149007 */
   ulOffset = pcrf->crf_esp;                                     /* 149007 */
   if( !VDHWriteUBuf( SSToDS( &exexcst),                         /* 149007 */
                      sizeof(EXEXCST), pcrf->crf_ss,             /* 149007 */
                      SSToDS(&ulOffset),                         /* 149007 */
                      VPM_SEL_IS_SS | VPM_SEL_PRESENT |          /* 149007 */
                      VPM_NO_SIM_EXCPT | VPM_FAULT_IF_SU_SET ) ) /* 149007 */
   {                                                             /* 149007 */
      TRAPProcessFatalFault( 0x0c, 0 );
                               /* cause hard error (trap 0xC) */ /* 149007 */
      return( TRUE );
       /* If it's error, don't let REFLECTION go any further *//* 149007 */
   }                                                              /* 149007 */
                                                                  /* 149007 */
   if( !(flVdmStatus & VDM_STATUS_VPM_32 ))                       /* 149007 */
   {                                                              /* 149007 */
      /* The 16 bit frame is 4 byte less then the 32 bit frame after
         VDHPushFarCall. We need to compensate the shortage
         store the excst 4 byte lower in the stack         */     /* 149007 */
      ulOffset = (pcrf->crf_esp -= 4);                            /* 149007 */
      if( !VDHWriteUBuf( SSToDS( &exexcst),                       /* 149007 */
                         sizeof(EXCST), pcrf->crf_ss,             /* 149007 */
                         SSToDS(&ulOffset),                       /* 149007 */
                         VPM_SEL_IS_SS | VPM_SEL_PRESENT |        /* 149007 */
                         VPM_NO_SIM_EXCPT | VPM_FAULT_IF_SU_SET ) )/* 149007 */
      {                                                            /* 149007 */
         TRAPProcessFatalFault( 0x0c, 0 );                         /* 149007 */
            /* cause hard error (trap 0xC) */                      /* 149007 */
         return( TRUE );                                           /* 149007 */
          /* If it's error, don't let REFLECTION go any further */ /* 149007 */
      }                                                            /* 149007 */
   }                                                               /* 149007 */
                                                                   /* 149007 */
   /* Set return hooker          */                                /* 149007 */
   VDHArmReturnHook( hhookV86ExpExc9RetHook,                       /* 149007 */
                     VDHARH_CSEIP_HOOK | VDHARH_ALWAYS_ARM_HOOK ); /* 149007 */

   fpfn.f32sel    = (*pvpmData->vpmd_pav86exc)[ iExcept].vpmexc_sel;/* 149007 */
   fpfn.f32offset = (*pvpmData->vpmd_pav86exc)[ iExcept].vpmexc_off;/* 149007 */
                                                                    /* 149007 */
   VDHPushFarCall( *((FPFN *)(PVOID)&fpfn) );                      /* 149007 */
   pcrf->crf_eflag &= ~F_TRACE;      /* clear trace flag   */      /* 149007 */
   VDHChangeVPMIF( FALSE );            /* disable interrupts */    /* 149007 */
                                                                   /* 149007 */
   return( TRUE );                                                 /* 149007 */
}                                                                  /* 149007 */


/*** EM86 V86 interrupt to be processed by VPM INT handler      153566
 *   The VPM Interrupt handler was registered in VPM IDT.       153566
 *   (For V86 INT 1Ch, 23h and 24h only )                       153566
 *   (All the interrupt should IRET. Otherwise the memory will not be 153566
 *    be released)                                              153566
 *                                                              153566
 *      ENTRY:  iInt      - Int number  (1Ch, 23h, 24h)         153566
 *              pcrf      - pointer of client register frame    153566
 *              iErrcode  - Error code                          153566
 *      EXIT:   None                                            153566
 *                                                              153566
 *                                                              153566
 *   return                                                     153566
 *     TRUE  -- The Exception is handled                        153566
 *     FALSE -- The Exception is not handled                    153566
 *                                                              153566
 *  Method:                                                     153566
 *     Switch to VPM mode
 *     Use VDPMI stack                                          153566
 *     Make a Interrupt Stack Frame                             153566
 *     Get the Interrupt Handler                                153566
 *     Arm a return Hook                                        153566
 *     Pass Control to it                                       153566
 *                                                              153566
 *
 *   return
 */
void EM86V86INTtoVPM( int iInt, PCRF pcrf )                    /* 153566 */
{                                                              /* 153566 */
   /* FPFN    fpfn; */                                         /* 153566 */
   IRET16 iRet16;
   IRET32 iRet32;
   ULONG  ulFlag;
                                                               /* 153566 */
   VDHSwitchToVPM();   /* Switch to Protected Mode       */    /* 153566 */

   VDHBeginUseVPMStack(); /* Give them a stack from VDPMI P25 *//* 153566 */
                                                               /* 153566 */
   VDHArmReturnHook(hhookBacktoV86RetHook, VDHARH_RECURSIVE_CSEIP_HOOK);
   ulFlag = pcrf->crf_eflag;                              /* Get Flags */
   if( !(flVdmStatus & VDM_STATUS_VME )) /* if P5 ? */    /* 153566 */
   {                                     /* no.     */    /* 153566 */
      if( !flVdmStatus & VDM_STATUS_VPM_IF_FLAG )         /* 153566 */
      {                                  /* If not F_INT*//* 153566 */
         ulFlag &= ~( F_INTERRUPT );     /* clear F_INT*/ /* 153566 */
      }                                                   /* 153566 */
   }                                                      /* 153566 */
   else                                                   /* 153566 */
   {                                                      /* 153566 */
      if( ulFlag &  F_VIF )      /* if F_INT(virt)*/      /* 153566 */
      {                          /* Yes, set F_INTERRUPT*//* 153566 */
         ulFlag |= F_INTERRUPT;                           /* 153566 */
      }                                                   /* 153566 */
      else                                                /* 153566 */
      {                          /* No, clear F_INT */    /* 153566 */
         ulFlag &= ~( F_INTERRUPT );                      /* 153566 */
      }                                                   /* 153566 */
   }                                                      /* 153566 */
   ulFlag &= (0xffff0000L |
           (*pvpmData->vpmd_pavpmint)[ iInt].vpmint_usFlagMask);/* 153566 */
   if( flVdmStatus & VDM_STATUS_VPM_32 )                       /* 153566 */
   {                                                           /* 153566 */
      iRet32.iret32_eflag = ulFlag;                            /* 153566 */
      iRet32.iret32_cs    = CS(pcrf);                          /* 153566 */
      iRet32.iret32_eip   = pcrf->crf_eip;                     /* 153566 */
      VDHPushStack(sizeof(IRET32), SSToDS(&iRet32));      /* 153566 */
      pcrf->crf_cs  = (*pvpmData->vpmd_pavpmint)[ iInt].vpmint_sel;/* 153566 */
      pcrf->crf_eip = (*pvpmData->vpmd_pavpmint)[ iInt].vpmint_off;/* 153566 */
   }                                                           /* 153566 */
   else                                                        /* 153566 */
   {                                                           /* 153566 */

      iRet16.iret16_flag = (USHORT)(ulFlag & 0xffffL);         /* 153566 */
      iRet16.iret16_cs   = CS(pcrf);                           /* 153566 */
      iRet16.iret16_ip   = IP(pcrf);                           /* 153566 */
      VDHPushStack(sizeof(IRET16), SSToDS(&iRet16));           /* 153566 */
      pcrf->crf_cs  = (*pvpmData->vpmd_pavpmint)[ iInt].vpmint_sel;/* 153566 */
      *((USHORT *)&pcrf->crf_eip) =
            (USHORT)((*pvpmData->vpmd_pavpmint)[ iInt].vpmint_off);
                                                               /* 153566 */
   }                                                           /* 153566 */
   VDHChangeVPMIF( ulFlag & F_INTERRUPT ); /* Change flags */  /* 153566 */
                                                               /* 153566 */
   return;                                                     /* 153566 */
}

/*** EM86BacktoV86RetHook - The return hook          153566
 *                          to switch the client back to V86
 *                                                              153566
 *      ENTRY:  pData     - pointer to Hook data                153566
 *              pcrf      - pointer of client register frame    153566
 *                                                              153566
 *      EXIT:   None                                            153566
 *                                                              153566
 *      Metho:                                                  153566
 *             Pop back Original CS:EIP in VPM mode             153566
 *             Pop the original DS and ES                       153566
 *             Stop useing VDPMI Stack                          153566
 *             Switch Back to v86                               153566
 *                                                              153566
 */
void HOOKENTRY EM86BacktoV86RetHook( PVOID pData, PCRF pcrf )   /* 153566 */
{                                                               /* 153566 */
                                                                /* 153566 */
   pData; /* Avoid warning */                                   /* 153566 */

   /* Get the original VPM CS:EIP. 153566 */
   VDHPopStack(sizeof(ULONG) * 2, &(pcrf->crf_eip));            /* 153566 */


   VDHEndUseVPMStack();      /* get back the stack of VDPMI */  /* 153566 */
                                                                /* 153566 */
   VDHSwitchToV86();                                            /* 153566 */

   /* ?? Do we need to add 2 to the instruction IP? GK*/        /* 153566 */
   (*(USHORT *)(&pcrf->crf_eip)) += 2;  /* usEIPincr */         /* 153566 */
   /* ?? Do we have to change the flag by VDHChangeVPMIF? GK*/  /* 153566 */

   return;                                                      /* 153566 */
}                                                               /* 153566 */



/*** EM86GetDr6           - Get DR6 value            149007
 *                          through DBGWP.C
 *                                                              149007
 *      ENTRY:                                                  149007
 *                                                              149007
 *      EXIT:   DR6 status or                                   149007
 *              NULL                                            149007
 *      Method:                                                 149007
 *        Query the DR6 from DSBGWP.c to get the logical DR6    149007
 *        Query VDPMI to get the DR6 of Client                  149007
 *        return DR6                                            149007
 *
 */
ULONG em86GetDr6()                                 /*149007 */
{
   ULONG ulLogicalDR6;                             /* 149007 */
   ULONG ulLogicalWP;                              /* 149007 */

   if( DBGDR6QueryVDM( 0x0000000f,   /* Query all 4 bit and current setting */
                       0x00000000,   /* Reset nothing */  /* 149007 */
                       SSToDS( &ulLogicalDR6 ) ) != ERROR_INVALID_PARAMETER )
   {                                                      /* 149007 */
      if( (*pfndpmQuery)( DPM_QUERY_WP_SET, SSToDS(&ulLogicalWP ) ) )/* 149007 */
      {                                                    /* 149007 */
         return( ulLogicalDR6 & ulLogicalWP );             /* 149007 */
      }                                                    /* 149007 */
      else                                                 /* 149007 */
      {                                                    /* 149007 */
         return( 0L );                                     /* 149007 */
      }                                                    /* 149007 */
                                                           /* 149007 */
      /*return( ((dbgvdm_t *)ulOffset)->dbgv_dr6 & 0x0000ff ); *//* 149007 */
   }                                                       /* 149007 */
   else    /* No, return 0 */                              /* 149007 */
      return ( 0L );                                       /* 149007 */
}                                                          /* 149007 */
                                                           /* 149007 */

#pragma END_MVDM_SWAP_CODE
