/*static char *SCCSID = "@(#)tkumem.c	6.2 91/06/09";*/
#define SCCSID  "@(#)tkumem.c	6.2 91/06/09"

/*
 *      Tasking - User Memory Access Routines
 *      This is an OS/2 2.x specific file
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      Created Jan 1989 - Jameel Hyder.
 *      157624 RJM Make calls to TRAPProcessFatalFault pass the 
  *            h/w error code for EXCPG (0xe) faults.
 *
 */

#define INCL_TYPES                      // for basedef.h typedefs
#define INCL_ERROR_H                    // for error.h defines
#define INCL_ERROR2_H                   // for error2.h defines

#include <basemac.h>
#include <basedef.h>
#define FNO_NUM FNO_TKUMEM_C
#include <fnotask.h>
#include <osmac.h>
#include <ostypes.h>
#include <infoseg.h>
#include <osconst.h>
#include <bseerr.h>
#include <dossymc.h>
#include <seldesc.h>
#include <sigdef.h>
#include <except.h>
#include <mi.h>
#include <pgexport.h>
#include <vmexport.h>
#include <tkexport.h>
#include <proc.h>
#include <sem.h>
#include <screen.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <tkptda.h>
#include <ldrxport.h>
#include <selxport.h>
#include <kmode.h>
#include <bsetib.h>
#include <tklocal.h>
#include <string.h>


/*
 *      Inside the kernel it is often necessary to get data from user space,
 *      copy data to user space or copy user data from one task's user space
 *      to another task's user space.  Examples are as follows:
 *
 *      (1)  Many of the file system calls have the application pass
 *           in a pointer to a string with a path and file name.
 *           Inside the kernel it is necessary to follow this pointer
 *           and read this string.
 *
 *      (2)  DosQCurDir has the application pass in a pointer to a
 *           buffer.  The api call fills the buffer with the current
 *           directory.
 *
 *      (3)  A debugger may wish to copy user data between itself and a
 *           debuggee.
 *
 *      Transfers of this nature must be handled carefully.  Several
 *      problems present themselves. First, the copy may result in a protection
 *      violation detected by hardware.  Violations occurring as a result
 *      of trying to access user memory must be distinguished from those
 *      that occur as a result of accessing system memory.  The former type
 *      should cause the task to fail and the latter should cause an internal
 *      error in the system.  Second, on implementations that use the Intel
 *      80386 CPU specifically, an attempt to write to pages of memory via
 *      virtual addresses via which read-only access is specified (via
 *      the read-only bit of page table entries corresponding to linear
 *      addresses) must be detected.  The 80386 CPU will allow such access
 *      from rings 2, 1 or 0.  Since this code executes at ring 0, explicit
 *      checks on the access must be made, and if the checks fail, a
 *      protection violation should be indicated.
 *
 *      To distinguish between the two cases all transfers from and to
 *      user space from the kernel MUST be done with one of the procedures in
 *      this file.  Transfers between user space (for example between a
 *      debugger and debuggee) must also use the routines in this file.
 *
 *      The following procedures have been defined:
 *
 *      TKSuByte[NF]  - set user byte
 *      TKSuWord[NF]  - set user word
 *      TKSuDWord[NF] - set user dword
 *      TKSuBuff      - set user buffer
 *      TKSuBuffz     - set user buffer until NULL or count expires
 *      TKFuByte[NF]  - fetch user byte
 *      TKFuWord[NF]  - fetch user word
 *      TKFuDWord[NF] - fetch user dword
 *      TKFuBuff      - fetch user buffer
 *      TKFuBuffz     - fetch user buffer until NULL or count expires
 *      TKFuBuffLenz  - fetch length of null-terminated user buffer
 *      TKFuBuffLenzz - fetch length of double-null-terminated user buffer
 *      TKProbeBuff   - Test address range access for I/O.  ProbeBuff does not
 *                      actually perform any I/O, but rather is used for address
 *                      checking by I/O workers.
 */


/***LP  tkSuBuff386 - Copy from Resident System Memory to User Memory
 *
 *      TkSuBuff386 performs a buffer transfer from resident system memory
 *      to user memory watching for protection faults.  The buffer
 *      transfer is subdivided into smaller transfers interspersed with
 *      yields to time critical threads.  A protection violation may
 *      optionally be fatal to the calling task.
 *
 *      Protection violations on the source data access are treated as
 *      an internal error, since the source data is resident and should be
 *      readable.  Protection violations on the destination data access
 *      are treated as user errors.  An error code is returned to the caller
 *      and, if specified, all threads of the current task are marked to
 *      terminate, and a hard error popup is generated.
 *
 *      ENTRY   pMemDst         - destination buffer in user space
 *              pMemSrc         - source buffer in resident memory
 *              cb              - byte count
 *              fl              - flags
 *                                TK_UM_FATAL - Error is fatal to task.  A
 *                                GP fault is simulated and an error is
 *                                returned to the caller.
 *
 *      EXIT    NO_ERROR, If successful
 *                  Buffer will have been written to user space
 *              ERROR_PROTECTION_VIOLATION
 *                  The specified user memory could not be written to or
 *                  is not writable from user (ring 3) code via the
 *                  specified virtual addresses.
 */

int                     tkSuBuff386(pMemDst, pMemSrc, cb, fl)
PCHAR                   pMemDst;
PCHAR                   pMemSrc;
int                     cb;
int                     fl;
{
        int             cbpage;         /* Bytes on current page */
        int             rc;             /* Return code */
        char            faultbuf[CBOBJNAMEBUF+CBERRCODEBUF];
                                        /* Fault Buffer */

        tkAssert(!(fl & (TK_UM_DEST | TK_UM_SRCE)));
                                        /* Source, target flags clear */

        if ((fl & TK_UM_USER) &&                                       //b723248
           (tkBufferWithinUserDSLimit(pMemDst, cb) != NO_ERROR)) {     //b723248
            if (fl & TK_UM_FATAL_DST)
//                TKUsrMemPageFault((ULONG) pMemDst);                  //157624
                TKUsrMemPageFault((ULONG) TK_UM_FATAL_DST);            //157624
                                        /* Kill process if fatal */
            return(ERROR_PROTECTION_VIOLATION);
        }

        rc = NO_ERROR;                  /* Assume success */
        while (cb > 0) {                /* Loop to make transfer */
            cbpage = PAGESIZE - ((int) pMemDst & PAGEMASK);
                                        /* # of bytes left on page */
            if (cbpage > cb)
                cbpage = cb;            /* Copy no more than cb bytes */
            pTCBCur->TCB_FaultBuf  = SSToDS(&faultbuf);
            pTCBCur->TCB_FaultBufL = CBOBJNAMEBUF;
            rc = PGVerifyPermission((ULONG) pMemDst >> PAGESHIFT,
              pPTDACur,1,PG_R | PG_W | PG_FORCEPRESENT);
                                        /* Verify access */
            pTCBCur->TCB_FaultBufL = 0; /* Clear error context */
            if (rc != NO_ERROR) {       /* If access violation or interrupt */
                if (rc != ERROR_INTERRUPT) {
                                        /* If true violation */
                    pTSDCur->TSDPFErr = rc;
                                        /* Save for TrapProcessFatalFault */
                    rc = ERROR_PROTECTION_VIOLATION;
                                        /* Set error code */
                    if (fl & TK_UM_FATAL_DST)
//                        TKUsrMemPageFault((ULONG) pMemDst);              //157624
                        TKUsrMemPageFault((ULONG) TK_UM_FATAL_DST);        //157624
                                        /* Kill process if fatal */
                }
                break;                  /* Exit loop */
            }
            memcpy(pMemDst,pMemSrc,cbpage);
                                        /* Copy the bytes */
            cb -= cbpage;               /* Update the count */
            pMemDst += cbpage;          /* Update the destination */
            pMemSrc += cbpage;          /* Update the source */
            TKResched();                /* Yield if necessary */
        }
        return(rc);                     /* Return error code */
}


/***LP  tkSuBuff486 - Copy from Resident System Memory to User Memory
 *
 *      TkSuBuff486 performs a buffer transfer from resident system memory
 *      to user memory watching for protection faults.  The buffer
 *      transfer is subdivided into smaller transfers interspersed with
 *      yields to time critical threads.  A protection violation may
 *      optionally be fatal to the calling task.
 *
 *      Protection violations on the source data access are treated as
 *      an internal error, since the source data is resident and should be
 *      readable.  Protection violations on the destination data access
 *      are treated as user errors.  An error code is returned to the caller
 *      and, if specified, all threads of the current task are marked to
 *      terminate, and a hard error popup is generated.
 *
 *      ENTRY   pdstUsr         - destination buffer in user space
 *              psrcRes         - source buffer in resident memory
 *              cb              - byte count
 *              fl              - flags
 *                                TK_UM_FATAL - Error is fatal to task.  A
 *                                GP fault is simulated and an error is
 *                                returned to the caller.
 *
 *      EXIT    NO_ERROR, If successful
 *                  Buffer will have been written to user space
 *              ERROR_PROTECTION_VIOLATION
 *                  The specified user memory could not be written to or
 *                  is not writable from user (ring 3) code via the
 *                  specified virtual addresses.
 */

int                     tkSuBuff486(pdstUsr, psrcRes, cb, fl)
register char           *pdstUsr;       // Destination buffer in user space
register char           *psrcRes;       // Source buffer in resident memory
int                     cb;             // Count of bytes to copy
int                     fl;             // Flags
{
        ljmp_t          lj;             /* TKlongjmp buffer */
        char            faultbuf[CBOBJNAMEBUF+CBERRCODEBUF];

        tkAssert(!(fl & (TK_UM_DEST | TK_UM_SRCE)));
        pTSDCur->TSDTrapNum = EXCPG;    /* Assume page fault */
        pTCBCur->TCB_FaultBuf  = SSToDS(&faultbuf);
        pTCBCur->TCB_FaultBufL = CBOBJNAMEBUF;

        if ((fl & TK_UM_USER) &&                                       //b723248
           (tkBufferWithinUserDSLimit(pdstUsr, cb) != NO_ERROR) ||     //b723248
           (TKCatchFault(SSToDS(&lj)) != NO_ERROR)) {
            if (fl & TK_UM_FATAL_DST)
//                tkUsrMemError((ULONG) pdstUsr);                        //157624
                tkUsrMemError((ULONG) pdstUsr, (ULONG) TK_UM_FATAL_DST); //157624
                                        /* Kill process if fatal */
            pTCBCur->TCB_FaultBufL = 0;
            return(ERROR_PROTECTION_VIOLATION);
        }

        switch (cb) {                   // Optimize byte, word, dword
          case sizeof(UCHAR):           // SuByte
            *pdstUsr = *psrcRes;
            break;

          case sizeof(USHORT):          // SuWord
            *((PUSHORT) pdstUsr) = *((PUSHORT) psrcRes);
            break;

          case sizeof(ULONG):           // SuDword
            *((PULONG) pdstUsr) = *((PULONG) psrcRes);
            break;

          default:                      // SuBuff
            TKCopyBuff((ulong_t) pdstUsr, (ulong_t) psrcRes, cb);
            break;
        }
        TKClrFault();                   // Clear fault handler
        pTCBCur->TCB_FaultBufL = 0;     // Clear fault buffer
        return(NO_ERROR);               // Success if we get here
}


/***EP  TKSuFuBuff - copy from user memory to user memory
 *
 *      This function copies from a buffer that may be in user
 *      memory to a buffer that may also be in user memory in the
 *      same context.
 *
 *      TKSuFuBuff (pbdst, pbsrc, cb, fl)
 *
 *      ENTRY   pbdst           - pointer to destination buffer
 *              pbsrc           - pointer to source buffer
 *              cb              - number of bytes to copy
 *              fl              - flags
 *      RETURN  int             - return code (NO_ERROR if successful)
 *
 *      CALLS   TKFuBuff, tkSuBuff386, tkSuBuff486
 *
 *      WARNING NONE
 *
 *      EFFECTS Data is copied from the source to the destination.
 */

int                     TKSuFuBuff(pbdst,pbsrc,cb,fl)
char                    *pbdst;         /* Destination buffer pointer */
char                    *pbsrc;         /* Source buffer pointer */
int                     cb;             /* Count of bytes to copy */
int                     fl;             /* Flags */
{
        int             cbpart;         /* Partial byte count */
        int             rc;             /* Return code */
        char            abtemp[1024];   /* Temporary buffer */

        cbpart = fl & (TK_UM_DEST | TK_UM_SRCE);
                                        /* Get source, destination bits */
        fl &= ~(TK_UM_DEST | TK_UM_SRCE);
                                        /* Clear the bits */
        switch (cbpart) {               /* Switch on source, target combo */
            case 0:                     /* Both buffers in system space */
                TKCopyBuff((ulong_t) pbdst,(ulong_t) pbsrc,cb);
                return(NO_ERROR);

            case TK_UM_DEST:            /* Destination in user space */
                return((*pfntkSuBuff)(pbdst,pbsrc,cb,fl));

            case TK_UM_SRCE:            /* Source in user space */
                return(TKFuBuff(pbdst,pbsrc,cb,fl));

            default:                    /* Both in user space */
                rc = NO_ERROR;          /* Assume success */
                while (cb > 0) {        /* Loop to copy in chunks */
                    cbpart = sizeof(abtemp);
                    if (cbpart > cb)
                        cbpart = cb;
                    if ((rc = TKFuBuff(SSToDS(abtemp),pbsrc,
                      cbpart,fl)) != NO_ERROR ||
                      (rc = (*pfntkSuBuff)(pbdst,SSToDS(abtemp),
                      cbpart,fl)) != NO_ERROR)
                        break;          /* Break if transfer fails */
                    cb -= cbpart;       /* Adjust count */
                    pbdst += cbpart;    /* Adjust pointers */
                    pbsrc += cbpart;
                    TKResched();        /* Yield if necessary */
                }
                return(rc);             /* Return error code */
        }
}


/***EP  TKSuBuffz - Copy null-terminated string to user space
 *
 *      TKSuBuffz copies a NULL terminated string from system space to
 *      user space.  The copy will stop when a NULL byte is hit or MaxLength
 *      bytes have been copied.  Protection faults will be caught and dealt
 *      with.
 *
 *      ENTRY   pLen            pointer to where actual transfer length is
 *                              returned.  Could be NULL
 *              pMemRes         pointer to resident system buffer
 *              pMemUsr         pointer to user buffer
 *              MaxLength       Maximum length to copy
 *              Flags
 *                TK_UM_FATAL - Error is fatal to task.  A GP fault is simulated
 *                              and an error is returned to the caller.
 *
 *      EXIT    NO_ERROR, If successful
 *              ERROR_PROTECTION_VIOLATION
 *                  The specified user memory could not be written to or
 *                  is not writable from user (ring 3) code via the
 *                  specified virtual addresses.
 *
 */

int     TKSuBuffz(pLen, pdstUsr, psrcRes, MaxLength, Flags)
PINT    pLen;
PCHAR   psrcRes, pdstUsr;
int     MaxLength, Flags;
{
        int             len;

        tkAssert(!(Flags & (TK_UM_DEST | TK_UM_SRCE)));
        if (tkScanBuffz(SSToDS(&len), psrcRes, MaxLength, FALSE) ==
          ERROR_TERMINATOR_NOT_FOUND)
            len = MaxLength;
        if (pLen != NULL)
            *pLen = len;
        return ((*pfntkSuBuff)(pdstUsr, psrcRes, len, Flags));
}


/***EP  TKFuBuff - Copy from User Memory to Resident System Memory
 *
 *      TKFuBuff performs a buffer transfer from user data to resident
 *      system data watching for protection faults.  The buffer transfer is
 *      subdivided into small transfers interspersed with yields to time
 *      critical threads.
 *
 *      Protection violations on the destination data access are treated as
 *      an internal error, since the destination data is resident system data
 *      and should be writeable.  Protection violations on the source data
 *      access are treated as user errors.  An error code is returned to the
 *      caller and optionally all threads of the current task are marked to
 *      terminate and a hard error popup is generated.
 *
 *      ENTRY   pdstRes         - pointer to resident system buffer
 *              psrcUsr         - pointer to user buffer
 *              cb              - byte count
 *              fl              - flags
 *                                  TK_UM_FATAL - Error is fatal to task.
 *                                  A GP fault is simulated and an error
 *                                  is returned to the caller.
 *
 *      EXIT    NO_ERROR, If successful
 *                  Buffer will have been written to user space
 *              ERROR_PROTECTION_VIOLATION
 *                  The specified user memory could not be written to.  A
 *                  flag will have been set to kill the entire task.
 */

int                     TKFuBuff(pdstRes, psrcUsr, cb, fl)
register PCHAR          pdstRes;        // Destination
register PCHAR          psrcUsr;        // Source
int                     cb;             // Count of bytes to transfer
int                     fl;             // Flags
{
        ljmp_t          lj;             // TKlongjmp buffer
        char            faultbuf[CBOBJNAMEBUF+CBERRCODEBUF];

        tkAssert(!(fl & (TK_UM_DEST | TK_UM_SRCE)));
        pTSDCur->TSDTrapNum = EXCPG;    /* Assume page fault */
        pTCBCur->TCB_FaultBuf  = SSToDS(&faultbuf);
        pTCBCur->TCB_FaultBufL = CBOBJNAMEBUF;

        if ((fl & TK_UM_USER) &&                                       //b723248
           (tkBufferWithinUserDSLimit(psrcUsr, cb) != NO_ERROR) ||     //b723248
           (TKCatchFault(SSToDS(&lj)) != NO_ERROR)) {
            if (fl & TK_UM_FATAL_SRC)
//                tkUsrMemError((ULONG) psrcUsr);                        //157624
                tkUsrMemError((ULONG) psrcUsr, (ULONG) TK_UM_FATAL_SRC); //157624  
                                        /* Kill process if fatal */
            pTCBCur->TCB_FaultBufL = 0;
            return(ERROR_PROTECTION_VIOLATION);
        }
        switch (cb) {                   // Optimize byte, word, dword
          case sizeof(UCHAR):           // SuByte
            *pdstRes = *psrcUsr;
            break;

          case sizeof(USHORT):          // SuWord
            *((PUSHORT) pdstRes) = *((PUSHORT) psrcUsr);
            break;

          case sizeof(ULONG):           // SuDword
            *((PULONG) pdstRes) = *((PULONG) psrcUsr);
            break;

          default:                      // SuBuff
            TKCopyBuff((ulong_t) pdstRes, (ulong_t) psrcUsr, cb);
            break;
        }
        TKClrFault();                   // Clear fault handler
        pTCBCur->TCB_FaultBufL = 0;
        return(NO_ERROR);               // Success if we get here
}



/***EP  TKFuBuffz - Copy null-terminated string from user space
 *
 *      TKFuBuffz copies a null-terminated string from user space to
 *      resident system space.  The copy will stop when a NULL byte is hit
 *      or MaxLength bytes have been copied.  Protection faults will be caught
 *      and dealt with.
 *
 *      ENTRY   pLen    pointer to where actual transfer length is
 *                              returned.  Could be NULL
 *              pMemRes         pointer to resident system buffer
 *              pMemUsr         pointer to user buffer
 *              MaxLength       Maximum length to copy
 *              Flags
 *                TK_UM_FATAL - Error is fatal to task.  A GP fault is simulated
 *                              and an error is returned to the caller.
 *
 *      EXIT    NO_ERROR, If successful
 *              ERROR_PROTECTION_VIOLATION
 *                  The specified user memory could not be read.
 *
 */

int     TKFuBuffz(pLen, pMemRes, pMemUsr, MaxLength, Flags)
PINT                    pLen;           // Place to return length copied
register PCHAR          pMemRes;        // System buffer pointer
register PCHAR          pMemUsr;        // User buffer pointer
int                     MaxLength;      // Size of system buffer
int                     Flags;          // Fatal if error flag
{
        register int    len;            // Count of bytes copied
        ljmp_t          lj;             // TKlongjmp buffer
        char            faultbuf[CBOBJNAMEBUF+CBERRCODEBUF];

        tkAssert(!(Flags & (TK_UM_DEST | TK_UM_SRCE)));
        pTSDCur->TSDTrapNum = EXCPG;    /* Assume page fault */
        pTCBCur->TCB_FaultBuf  = SSToDS(&faultbuf);
        pTCBCur->TCB_FaultBufL = CBOBJNAMEBUF;

        if (TKCatchFault(SSToDS(&lj)) == NO_ERROR) {
            tkAssert(MaxLength <= PAGESIZE);// Assert no need to yield
            for (len = 0; len < MaxLength; ) {
                                            // Loop to copy string
                len++;
                if ((*pMemRes++ = *pMemUsr++) == '\0')
                    break;                  // Break if end of string found
            }
            if (pLen != NULL)
                *pLen = len;                // Return length copied


            TKClrFault();                   // Clear local fault handler
            pTCBCur->TCB_FaultBufL = 0;

            if (!(Flags & TK_UM_USER) ||                               //b723248
               (tkBufferWithinUserDSLimit(pMemUsr,len) == NO_ERROR))   //b723248
                return(NO_ERROR);
        }

        if (Flags & TK_UM_FATAL)
//            tkUsrMemError((ULONG) pMemUsr);                         //157624
            tkUsrMemError((ULONG) pMemUsr, (ULONG) TK_UM_FATAL_SRC);  //157624
                                    /* Kill process if fatal */
        pTCBCur->TCB_FaultBufL = 0;
        return(ERROR_PROTECTION_VIOLATION);

}


/***EP  TKFuBufLen  - Common code for TKFuBufLenz and TKFuBuffLenzz
 *
 *      Determine length of null (or double null) terminated user strings
 *
 *      ENTRY:  pLen    pointer to where length is returned
 *              pMemUsr         pointer to user buffer
 *              MaxLength       Max. length to scan
 *              Flags
 *                TK_UM_FATAL - A protection violation causes the task
 *                              to terminate.
 *              fDNULL          TRUE if double null terminated string
 *
 *      EXIT:   NO_ERROR
 *                  Length is copied to pLen
 *              ERROR_TERMINATOR_NOT_FOUND
 *              ERROR_PROTECTION_VIOLATION
 *
 */

int     TKFuBufLen(pLen, pMemUsr, MaxLength, Flags, fDNULL)
PINT    pLen;
PCHAR   pMemUsr;
int     MaxLength, Flags, fDNULL;
{
        ljmp_t  lj;                     // TKlongjmp buffer
        int     rc;
        char            faultbuf[CBOBJNAMEBUF+CBERRCODEBUF];

        pTSDCur->TSDTrapNum = EXCPG;    /* Assume page fault */
        pTCBCur->TCB_FaultBuf  = SSToDS(&faultbuf);
        pTCBCur->TCB_FaultBufL = CBOBJNAMEBUF;

        if (TKCatchFault(SSToDS(&lj)) == NO_ERROR) {
            rc = tkScanBuffz(pLen, pMemUsr, MaxLength, fDNULL);
            TKClrFault();                   // Clear fault handler
            pTCBCur->TCB_FaultBufL = 0;
            if (!(Flags & TK_UM_USER) ||                               //b723248
               (tkBufferWithinUserDSLimit(pMemUsr,                     //b723248
                                         (rc == NO_ERROR) ?            //b723248
                                         *pLen : 1L)  == NO_ERROR))    //b723248
                return (rc);
        }
                                        // If fault during copy
        if (Flags & TK_UM_FATAL)
//            tkUsrMemError((ULONG) pMemUsr);                          //157624
            tkUsrMemError((ULONG) pMemUsr, (ULONG) TK_UM_FATAL_SRC);   //157624
                                    // Kill process if fatal
        pTCBCur->TCB_FaultBufL = 0;
        return (ERROR_PROTECTION_VIOLATION);
                                        // Return error code
}


/***EP  TKUsrMemPageFault - Handle Erroneous Page Fault in User Memory
 *
 *      TKUsrMemPageFault is called when an error is detected by
 *      one of the user memory accessing routines in this module.
 *
 *      It produces a delayed hard error popup that specifies a linear
 *      address for the user.   Use TKUsrMemGPFault for 16:16 addresses.
 *
 *      ENTRY   p               - Address of fault
 *                                157624 changed to simulated error code
 *
 *      EXIT    Always returns ERROR_PROTECTION_VIOLATION, to be propogated
 *              out of the system call.
 */

int     TKUsrMemPageFault(p)
ULONG   p;
{
        TRAPProcessFatalFault(EXCPG, p);
        return (ERROR_PROTECTION_VIOLATION);
}


/***EP  TKUsrMemGPFault - Handle Erroneous GP Fault in User Memory
 *
 *      TKUsrMemGPFault is called when an error is detected by
 *      one of the user memory accessing routines in this module.
 *
 *      It produces a delayed hard error popup that specifies a 16:16
 *      address for the user.  Use TKUsrMemPageFault for linear addresses.
 *
 *      ENTRY   p16             - 16:16 Address of fault (FarPtr)
 *
 *      EXIT    Always returns ERROR_PROTECTION_VIOLATION, to be
 *              propogated out of the system call.
 *
 */

int     TKUsrMemGPFault(p16)
ULONG   p16;
{
        TRAPProcessFatalFault(EXCGP, p16);
        return (ERROR_PROTECTION_VIOLATION);
}


/***LP  tkUsrMemError - Handle Fault in User Memory Routines
 *
 *      tkUsrMemError is called when an error is detected by
 *      one of the user memory accessing routines in this module.
 *
 *      tkUsrMemError is invoked when an actual fault is captured
 *      while accessing user memory.  In this case, pTSDCur->TSDTrapNum
 *      us whether it was a GP fault or a page fault.
 *
 *      BUGBUG: GP faults contain a linear address, and should be
 *              converted to 16:16, so that the user doesn't get confused.
 *
 *      ENTRY   p               - Address of fault                
 *                                157624 changed to simulated error code if
 *                                       EXCPG fault.
 *
 *      EXIT    Always returns ERROR_PROTECTION_VIOLATION, to be
 *              propogated out of the system call.
 *
 */

//int     tkUsrMemError(p) 
int     tkUsrMemError(p,f)         //157624
ULONG   p;
ULONG   f;                         //157624
{
        if (pTSDCur->TSDTrapNum==EXCPG)                    //157624
           TRAPProcessFatalFault(EXCPG,f);                 //157624
        else                                               //157624
           TRAPProcessFatalFault(pTSDCur->TSDTrapNum, p);
        return (ERROR_PROTECTION_VIOLATION);
}
