#define SCCSID "@(#)int2f.c     6.4 91/07/19"

/***    INT2F.C
 *
 *      Version 1.7, for src/dos/mvdm/int2f.c, mvdm, mer.krnl, 960610.1
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      Title:
 *
 *      INT 2F dispatcher and services
 *
 *      Description:
 *
 *      This module contains the INT 2F dispatcher, regular and DPMI
 *      specific services.
 *
 *      Public routines:
 *
 *      INT2FV86Dispatcher
 *
 *      Modification History:
 *
 *    - Bx001  Bill Madden    01/18/93       DEF 60491
 *       Added support for GetVDDAPI and GETOS2Version
 *
 *    -        bjn            09/19/94
 *       Changed segment names for page tuning
 *    03-12-96 Gil Pratte - Implementing feature 149002     * 149002 *
 *       Added support for Virtual Support DPMI 1.0         * 149002 *
 *       Extension Query                                    * 149002 *
 *       Added DPMI 1.0 Service                             * 149002 *
 *         Release Current Virtual Machine's Time Slice     * 149002 *
 *    03-14-96 Gordon Kuo - Implementing feature 149007     * 149007 *
 *       Added support for Virtual Support DPMI 1.0         * 149007 *
 *
 */
#define FNO_NUM  FNO_INT2F_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

#include <vdmvdh.h>
#include <seldesc.h>
#include <sft.h>
#include <kmode.h>
#include <em86.h>
#include <int2f.h>

/* External and misc definitions */
extern PVDDAPI pVAPIList;
extern BOOL PRIVENTRY  vdmmStrcmpi(PSZ, PSZ);
extern VOID EXPENTRY   VDMMstrncpyz(ULONG, PSZ, PSZ);

/* Internal routine prototypes */

BOOL PASCAL INT2FV86Dispatcher(PVSF);
BOOL int2fGetMode(PVSF);
BOOL int2fGetVDDAPI(PVSF);                                              //BN001
BOOL int2fChain(PVSF);
BOOL int2fDPMIVirtSupport(PVSF);                           /* 149002 */
BOOL int2fReleaseTimeSlice(PVSF);                          /* 149002 */

#pragma BEGIN_MVDM_SWAP_DATA

BOOL (*apfnHighDispatchTable[])(PVSF) = {
        int2fReleaseTimeSlice,          // 80h             /* 149002 */
        int2fChain,                     // 81h
        int2fChain,                     // 82h
        int2fChain,                     // 83h
        int2fChain,                     // 84h
        int2fChain,                     // 85h
        int2fGetMode,                   // 86h
        int2fGetVPMSwitchAddr,          // 87h
        int2fChain,                     // 88h
        int2fChain,                     // 89h
        int2fDPMIVirtSupport            // 8Ah             /* 149002 */
};

#define MAX_HIGH_INT2F_FUNCTION         0x8A               /* 149002 */

/***   Virtual Support Extension String (DPMI 1.0)          * 149002 *
 *                                                          * 149002 *
 *     This string is used to detect if Virtual Support     * 149002 *
 *     is issuing the int 2f.                               * 149002 *
 */                                                        /* 149002 */
CHAR   szVirtSupportExtension[] = "VIRTUAL SUPPORT";       /* 149002 */

#define VIRTSUPPORT_EXTENSION_STRING_LEN  16               /* 149002 */

#pragma END_MVDM_SWAP_DATA

#pragma BEGIN_MVDM_SWAP_INSTANCE

#pragma END_MVDM_SWAP_INSTANCE

#pragma code_seg("SWAP32_20","CODE")

/***EP  INT2FV86Dispatcher - V86 mode INT 2F dispatcher
 *
 *      This is the INT 2F service dispatcher for V86 mode.
 *
 *      ENTRY   (pvsf) = pointer to client stack frame
 *
 *      EXIT    returns TRUE, return to V86 code
 *              returns FALSE, chain to next VDD
 *
 *      CONTEXT VDM Task
 *
 *      PSEUDO-CODE
 *
 *      if windows multiplex function
 *          if within dispatch table
 *              dispatch to int 2f service routine
 *              eat interrupt
 *      else if os2 detect call (client's AX=4010)
 *          client's AX = 0
 *          client's BX = version number
 *      else if get vdd api call (client's AX=4011)
 *          call int2fGetVDDAPI
 */

BOOL PASCAL
INT2FV86Dispatcher(pvsf)
register PVSF pvsf;
{
    register ULONG ul;

    // if AH is the windows multiplex function
    if(VSF_AH(pvsf) == INT2F_WINDOWS_MULTIPLEX) {
        ul = VSF_AL(pvsf);
        if(ul & INT2F_HIGH_FUNCTION) {
            if(ul <= MAX_HIGH_INT2F_FUNCTION) {
                ul &= ~INT2F_HIGH_FUNCTION;
                return((*apfnHighDispatchTable[ul])(pvsf));
            }
        }
    } else if (VSF_AX(pvsf) == INT2F_GETOS2VER) {                       //BN001 begin
       VSF_AX(pvsf) = 0;
       VSF_BX(pvsf) = (MAJOR_VERSION << 8) | MINOR_VERSION;
       return(TRUE);
    } else if (VSF_AX(pvsf) == INT2F_GETVDDAPI) {
       return(int2fGetVDDAPI(pvsf));                                    //BN001 end
    }

    return(FALSE);
}

#pragma code_seg("SWAP32_26","CODE")
/***LP  int2fChain - chain on to the next int2f hook
 *
 *      This is a dummy entry in the int 2f dispatch table for
 *      functions not handled by the kernel.
 *
 *      ENTRY   (pvsf) = pointer to client register stack frame
 *
 *      EXIT    NONE
 *
 *      USES    EAX, ECX, EDX, FS, GS, Flags
 *
 *      CONTEXT VDM Task
 *
 *      PSEUDO-CODE
 */

BOOL
int2fChain(pvsf)
PVSF pvsf;
{
    pvsf;                     // eliminate compiler warning
    return(FALSE);
}

#pragma code_seg()
#pragma BEGIN_MVDM_SWAP_CODE
/***LP  int2fGetMode - return current mode
 *
 *      This routine returns 0 if we are executing in protect mode,
 *      and a non-zero value otherwise.
 *
 *      ENTRY   (pvsf) = pointer to client register stack frame
 *
 *      EXIT    NONE
 *
 *      USES    EAX, ECX, EDX, FS, GS, Flags
 *
 *      CONTEXT VDM Task
 *
 *      PSEUDO-CODE
 */

BOOL int2fGetMode(pvsf)
PVSF pvsf;
{
    /* This will only get called from real mode, so return 1 */
    VSF_AX(pvsf) = 1;

    return(FALSE);
}
#pragma END_MVDM_SWAP_CODE

#pragma code_seg()                                                   /* 149002 */
#pragma BEGIN_MVDM_SWAP_CODE                                         /* 149002 */

/***LP  int2fDPMIVirtSupport - Int 2fH DPMI 1.0 Extension Query       * 149002 *
 *                                                                    * 149002 *
 *      This routine only handles the Int 2fh Extension Request       * 149002 *
 *      Query for Virtual Memory Support for DPMI 1.0 in Real Mode.   * 149002 *
 *      All other requests are ignored and chained to the next        * 149002 *
 *      interrupt handler.                                            * 149002 *
 *                                                                    * 149002 *
 *      ENTRY   (pvsf) = pointer to client register stack frame       * 149002 *
 *                                                                    * 149002 *
 *      EXIT    NONE                                                  * 149002 *
 *                                                                    * 149002 *
 *      USES    EAX, ECX, EDX, FS, GS, Flags                          * 149002 *
 *                                                                    * 149002 *
 *      CONTEXT VDM Task                                              * 149002 *
 *                                                                    * 149002 *
 *      PSEUDO-CODE                                                   * 149002 *
 *        If Real Mode                                                * 149002 *
 *           if "VIRTUAL SUPPORT" string                              * 149002 *
 *              Set AX(pvsf)=0                                        * 149002 *
 *              Return (do not chain to next interrupt handler)       * 149002 *
 */                                                                  /* 149002 */

BOOL int2fDPMIVirtSupport(pvsf)                                      /* 149002 */
PVSF pvsf;                                                           /* 149002 */
{                                                                    /* 149002 */
    CHAR    achVSUserString[VIRTSUPPORT_EXTENSION_STRING_LEN];       /* 149002 */

   // This code will only get hit from Real Mode,                    /* 149002 */
   // VDPX will handle this DPMI 1.0 Extension query in Protect Mode./* 149002 */
   // V86 mode app, just convert to linear address and copy the name /* 149002 */
   if (!(flVdmStatus & VDM_STATUS_VPM_EXEC))                         /* 149002 */
   {                                                                 /* 149002 */
      VDMMstrncpyz(VIRTSUPPORT_EXTENSION_STRING_LEN,                 /* 149002 */
                   PFROMVADDR(VSF_DS(pvsf),VSF_SI(pvsf)),            /* 149002 */
                   SSToDS(&achVSUserString));                        /* 149002 */

      // Check if this is Virtual Support DPMI 1.0 issuing the Int 2f/* 149002 */
      if (!strcmp(achVSUserString, szVirtSupportExtension))          /* 149002 */
      {                                                              /* 149002 */
         VSF_AX(pvsf) = 0;       // virtual support is supported     /* 149002 */

         return(TRUE); // do not chain to next interrupt handler     /* 149002 */
      }                                                              /* 149002 */
   }                                                                 /* 149002 */
   return(FALSE); // chain to next interrupt handler                 /* 149002 */
}                                                                    /* 149002 */
#pragma END_MVDM_SWAP_CODE                                           /* 149002 */

#pragma code_seg()                                                   /* 149002 */
#pragma BEGIN_MVDM_SWAP_CODE                                         /* 149002 */

/***LP  int2fReleaseTimeSlice - Release Current Virtual Machine's     * 149002 *
 *                              Time Slice                            * 149002 *
 *                                                                    * 149002 *
 *      This routine releases the current virtual machine's time      * 149002 *
 *      slice by invoking VDHYield() which "gives up" the             * 149002 *
 *      processor to other threads.  Tasks in this machine use        * 149002 *
 *      this call to report that they are idle and to yield their     * 149002 *
 *      time slice. This routine has no effect on the current         * 149002 *
 *      Idle and Busy statuses for this machine.                      * 149002 *
 *                                                                    * 149002 *
 *      ENTRY   (pvsf) = pointer to client register stack frame       * 149002 *
 *                                                                    * 149002 *
 *      EXIT    NONE                                                  * 149002 *
 *                                                                    * 149002 *
 *      USES    EAX, ECX, EDX, FS, GS, Flags                          * 149002 *
 *                                                                    * 149002 *
 *      CONTEXT VDM Task                                              * 149002 *
 *                                                                    * 149002 *
 *      PSEUDO-CODE                                                   * 149002 *
 *        Invoke VDHYield to "give up" processor to other threads     * 149002 *
 *        Set AX(pvsf)=0                                              * 149002 *
 *        Return (do not chain to next interrupt handler)             * 149002 *
 */                                                                  /* 149002 */

BOOL int2fReleaseTimeSlice(pvsf)                                     /* 149002 */
PVSF pvsf;                                                           /* 149002 */
{                                                                    /* 149002 */
   VDHYield(0);            // Yield processor to other tasks         /* 149002 */

   VSF_AX(pvsf) = 0;       // Supported                              /* 149002 */

   return(TRUE); // do not chain to next interrupt handler           /* 149002 */
}                                                                    /* 149002 */
#pragma END_MVDM_SWAP_CODE                                           /* 149002 */

#pragma code_seg("SWAP32_26","CODE")
/***LP  int2fGetVDDAPI - return VDD API entry point                     //BN001
 *
 *      This routine returns the VDD V86 mode entry point for the VDD
 *      specified by the VDD ID in the client's BX register.
 *
 *      ENTRY   (pvsf) = pointer to client register stack frame
 *              DS:SI(vsf) = asciiz VDD name to return handler for
 *
 *      EXIT
 *        If VDD name registered
 *              ES(vsf) = segment of BP for V86 API handler
 *              DI(vsf) = offset of BP for V86 API handler
 *        Otherwise
 *              ES(vsf) = NULL
 *              DI(vsf) = NULL
 *
 *      USES    EAX, ECX, EDX, FS, GS, Flags
 *
 *      CONTEXT VDM Task
 *
 *      PSEUDO-CODE
 */

BOOL int2fGetVDDAPI(pvsf)                                               //BN001
PVSF pvsf;
{
   ULONG   ulOffset, ulcb;
   CHAR    szVDDName[MAXLENXDD+1];
   PVDDAPI pvddapi;
   FPFN    fpfnVPMBP;

   // If protected mode app, use VDHReadUBuf to read in VDD name
   if (flVdmStatus & VDM_STATUS_VPM_EXEC) {
      if (flVdmStatus & VDM_STATUS_VPM_32) {
         ulOffset = pvsf->vsf_esi;
      } else {
         ulOffset = (ULONG)VSF_SI(pvsf);
      }
      for (ulcb = 0, szVDDName[MAXLENXDD] = '\0'; ulcb < MAXLENXDD; ulcb++) {
         if (VDHReadUBuf((SSToDS(&(szVDDName[ulcb]))), 1, VSF_DS(pvsf),
                         SSToDS(&ulOffset), VPM_SEL_PRESENT)) {
            if (szVDDName[ulcb] == '\0') {
               break;
            }
         } else {
            return(FALSE);
         }
      }

   // V86 mode app, just convert to linear address and copy the name
   } else {
      VDMMstrncpyz(MAXLENXDD+1,
                   PFROMVADDR(VSF_DS(pvsf),VSF_SI(pvsf)),
                   SSToDS(&szVDDName));
   }

   // Look for VDD in VDD API list to see if it is already registered
   pvddapi = pVAPIList;
   while (pvddapi) {

      // Is this the requested VDD?
      if (vdmmStrcmpi(pvddapi->vapi_szVDD,SSToDS(szVDDName))) {

         // If in protected mode, check for protect mode hook
         if ((flVdmStatus & VDM_STATUS_VPM_EXEC) &&
             (pvddapi->vapi_hhookVPM)) {

            // If we haven't armed the BP, arm it
            if (!(pvddapi->vapi_vpVPMBP)) {
               fpfnVPMBP = VDHArmVPMBPHook(pvddapi->vapi_hhookVPM);
               SEGMENTOF16(pvddapi->vapi_vpVPMBP) = SEGMENTOF32(fpfnVPMBP);
               OFFSETOF16(pvddapi->vapi_vpVPMBP) =
                  (USHORT)(OFFSETOF32(fpfnVPMBP));
            }

            VSF_ES(pvsf) = SEGMENTOF16(pvddapi->vapi_vpVPMBP);

            if (em86Is32Sel(VSF_CS(pvsf))) {
               pvsf->vsf_edi = (ULONG)(OFFSETOF16(pvddapi->vapi_vpVPMBP));
            } else {
               VSF_DI(pvsf) = OFFSETOF16(pvddapi->vapi_vpVPMBP);
            }

         // If in V86 mode, check for V86 mode hook
         } else if (!(flVdmStatus & VDM_STATUS_VPM_EXEC) &&
                    (pvddapi->vapi_vpV86BP)) {
            VSF_ES(pvsf) = SEGMENTOF16(pvddapi->vapi_vpV86BP);
            VSF_DI(pvsf) = OFFSETOF16(pvddapi->vapi_vpV86BP);

         // No V86 mode handler, return null
         } else {
            VSF_ES(pvsf) = NULL;
            VSF_DI(pvsf) = NULL;
         }

         return(TRUE);              // Don't chain to next handler

      // No, get next entry
      } else {
         pvddapi = pvddapi->vapi_next;
      }
   }
   VSF_ES(pvsf) = NULL;
   VSF_DI(pvsf) = NULL;
   return(TRUE);                    // chain to next handler
}

#pragma END_MVDM_SWAP_CODE
