#define SCCSID  "@(#)vmdevhlp.c 6.6 92/03/18"

/*
 *       IBM/Microsoft Confidential
 *
 *       Copyright (c) IBM Corporation 1987, 1989
 *       Copyright (c) Microsoft Corporation 1987, 1989
 *
 *       All Rights Reserved
 */

/*      This file contains the Devhlp procedures supported by Virtual
 *      Memory Manager
 *
 *      All the procedures below assume that FLAT selector is loaded
 *      in DS & ES. FLAT selector maps the whole linear
 *      address space. The value of FLAT will be provided to device
 *      drivers during initialization time.
 *
 *      In addition to these, the old DevHlp interface will be
 *      supported by the Selector Manager. Selector Manager will also provide
 *      the new interfaces dh_VirtToLin, and dh_LintoVirt.
 */

#define FNO_NUM         FNO_VMDEVHLP_C
#include <fnomem.h>
#include <osmac.h>
#define INCL_DOSERRORS
#include <ostypes.h>
#include <bseerr.h>
#include <osconst.h>
#include <mi.h>
#include <vmowner.h>
#include <pgexport.h>
#include <vmexport.h>
#include <vmlocal.h>
#include <selxport.h>
#include <tkexport.h>
#include <stdlib.h>
#include <dossymc.h>                    /* for tkptda.h */
#include <infoseg.h>                    /* for tkptda.h */
#include <sigdef.h>                     /* for tkptda.h */
#include <except.h>                     /* for tkptda.h */
#include <curdir.h>                     /* for tkptda.h */
#include <dirent.h>                     /* for tkptda.h */
#include <find.h>                       /* for tkptda.h */
#include <screen.h>                     /* for tkptda.h */
#include <sem.h>                        /* for tkptda.h */
#include <tkptda.h>

/* VMLock flags table */

ulong_t  vmdhL_Flags[] = {
        VML_DEVHLP,                             /* 0 No special flag */
        VML_DEVHLP| VML_NOBLOCK,                /* 1 no block */
        VML_DEVHLP| VML_CONTIG,                 /* 2 Contiguous  lock */
        VML_DEVHLP| VML_CONTIG | VML_NOBLOCK,   /* 3 = 1 + 2 */
        VML_DEVHLP| VML_16M,                    /* 4 Below 16 Meg */
        VML_DEVHLP| VML_16M | VML_NOBLOCK,      /* 5 = 4 + 1 */
        VML_DEVHLP| VML_16M | VML_CONTIG,       /* 6 = 4 + 2 */
        VML_DEVHLP| VML_16M | VML_CONTIG | VML_NOBLOCK, /* 7 */
        VML_DEVHLP| VML_DIRTY,                  /* 8 write request */
        VML_DEVHLP| VML_DIRTY | VML_NOBLOCK,    /* 9 = 8 + 1 */
        VML_DEVHLP| VML_DIRTY | VML_CONTIG,     /* 10 = 8 + 2 */
        VML_DEVHLP| VML_DIRTY | VML_CONTIG | VML_NOBLOCK, /* 11 */
        VML_DEVHLP| VML_DIRTY | VML_16M,        /* 12 = 8 + 4 */
        VML_DEVHLP| VML_DIRTY | VML_16M | VML_NOBLOCK, /* 13 */
        VML_DEVHLP| VML_DIRTY | VML_16M | VML_CONTIG, /* 14 = 8 + 4 + 2 */
        VML_DEVHLP| VML_DIRTY | VML_16M | VML_CONTIG | VML_NOBLOCK, /* 15 */
        VML_DEVHLP| VML_LONG,                   /* 16 is long term lock */
        VML_DEVHLP| VML_LONG| VML_NOBLOCK,      /* 17 = 16 + 1 */
        VML_DEVHLP| VML_LONG| VML_CONTIG,       /* 16 + 2 */
        VML_DEVHLP| VML_LONG| VML_CONTIG | VML_NOBLOCK, /* 16 + 1 + 2 */
        VML_DEVHLP| VML_LONG| VML_16M,          /* 16 + 4 */
        VML_DEVHLP| VML_LONG| VML_16M | VML_NOBLOCK, /* 16 + 4 + 1 */
        VML_DEVHLP| VML_LONG| VML_16M | VML_CONTIG, /* 16 + 4 + 2 */
        VML_DEVHLP| VML_LONG| VML_16M | VML_CONTIG | VML_NOBLOCK,
                                                /* 16 + 4 + 2 + 1 */
        VML_DEVHLP| VML_LONG| VML_DIRTY,        /* 16 + 8 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_NOBLOCK, /* 16 + 8 + 1 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_CONTIG, /* 16 + 8 + 2 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_CONTIG | VML_NOBLOCK,
                                                /* 16 + 8 + 2 + 1 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_16M, /* 16 + 8 + 4 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_16M | VML_NOBLOCK,
                                                /* 16 + 8 + 4 + 1 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_16M | VML_CONTIG,
                                                /* 16 + 8 + 4 + 2 */
        VML_DEVHLP| VML_LONG| VML_DIRTY | VML_16M | VML_CONTIG | VML_NOBLOCK,
        VML_DEVHLP|                             /* 16 + 8 + 4 + 2 + 1 */
        VML_DEVHLP| VML_VERIFY,                 /* 32 = verify only lock */
        VML_DEVHLP| VML_VERIFY| VML_NOBLOCK,    /* 32 + 1 */
        -1,                                     /* verify+contig */
        -1,                                     /* verify+contig */
        -1,                                     /* verify+below16M */
        -1,                                     /* verfiy+below16M */
        -1,                                     /* verify+contig+below16M */
        -1,                                     /* verify+contig+below16M */
        VML_DEVHLP| VML_VERIFY| VML_DIRTY,      /* 32 + 8 (verify write) */
        VML_DEVHLP| VML_VERIFY| VML_DIRTY | VML_NOBLOCK, /* 32 + 8 + 1 */
        -1,                                     /* verify+contig */
        -1,                                     /* verify+contig */
        -1,                                     /* verify+below16M */
        -1,                                     /* verify+below16M */
        -1,                                     /* verify+contig+below16M */
        -1,                                     /* verify+contig+below16M */
        VML_DEVHLP| VML_VERIFY| VML_LONG,       /* 32 + 16 */
        VML_DEVHLP| VML_VERIFY| VML_LONG| VML_NOBLOCK, /* 32 + 16 + 1 */
        -1,                                     /* verify+contig */
        -1,                                     /* verify+contig */
        -1,                                     /* verify+below16M */
        -1,                                     /* verify+below16M */
        -1,                                     /* verify+contig+below16M */
        -1,                                     /* verify+contig+below16M */
        VML_DEVHLP| VML_VERIFY| VML_LONG| VML_DIRTY, /* 32 + 16 + 8 */
        VML_DEVHLP| VML_VERIFY| VML_LONG| VML_DIRTY | VML_NOBLOCK,
                                                /* 32 + 16 + 8 + 1 */
        /* Rest of the values are invalid */
 };
#define vmdhL_MaxFlags    57            /* Max value of dhw_VMLock flags */
#define vmdhL_FlagsMask   0x3f          /* dhw_VMLock Flags Mask */

ulong_t  vmdhA_Flags[] = { PG_RESIDENT,/* 0 means resident */
        -1,                             /* 1 is invalid combination */
        PG_RESIDENT,                    /* VMDHA_FIXED */
        PG_RESIDENT | PG_16M,           /* VMDHA_FIXED | VMDHA_16M */
        PG_SWAPPABLE,                   /* VMDHA_SWAP */
        -1,                             /* 5 is invalid combination */
        -1,                             /* 6 is invalid combination */
        -1,                             /* 7 is invalid combination */
        -1,                             /* 8 is invalid combination */
        -1,                             /* 9 is invalid combination */
        PG_RESIDENT | PG_CONTIG,        /* VMDHA_FIXED | VMDHA_CONTIG */
        PG_RESIDENT | PG_CONTIG | PG_16M,
        -1,                             /* 12 is invalid combination */
        -1,                             /* 13 is invalid combination */
        -1,                             /* 14 is invalid combination */
        -1,                             /* 15 is invalid combination */
        PG_UVIRT                        /* VMDHA_PHYS */
};

// MIKEK changed from 3ff to support new shared flag
// dcr 32500 changed from 7ff to support new alloc flag
// #define vmdhA_FlagsMask   0x7ff     /* Flags mask for dhw_VMAlloc */
#define vmdhA_FlagsMask   0xfff     /* Flags mask for dhw_VMAlloc */
// end
#define vmdhA_Flvm  (PG_R | PG_W | VMAC_LOCANY)
                                    /* default dwh_VMAlloc flags */
#define vmdhA_FlvmSys (VMAC_ARENASYS | VMAC_ALIGNPAGE)
                                    /* Global space dwh_VMAlloc flags */
#define vmdhA_FlvmProcess (VMAC_ALIGNSEL | VMAC_ARENAPRV | PG_U)
                                    /* Task space dwh_VMAlloc flags */

// MIKEK - Shared allocation flags
#define vmdhA_FlvmShared (VMAC_ARENASHR | VMAC_SHARED | VMAC_ALIGNSEL | \
                          PG_UVIRT | PG_RESIDENT )

#define vmdhA_MaxHeapSize   _1MEG
#define vmdhA_MaxWaist      0x100   /* Max. waisted space */

#define VMDHGP_FLVM  (VMAC_ARENAPRV | VMAC_SELALLOC | VMAC_LOCANY \
                     | PG_R | PG_U)
                     /* GlobalToProcess flags, BUGBUG: Force tiling */
#define VMDHGP_FLSEL  (SELAL_SELMAP | (SEL_RPL3 << SELAL_PRIVSHIFT))
#define VMDHPG_FLVM  (VMAC_ARENASYS | VMAC_LOCANY | VMAC_ALIGNPAGE | PG_R)
                                /* ProcessToGlobal flags */

#define vmDHS_Flvm  (VMS_COMMIT | PG_R | PG_W)

#pragma data_seg("CINIT_DATA", "CINITDATA")

struct  vmdhAllocAccess_s {
        ulong_t     vmdha_laddr;
        ulong_t     vmdha_vaddr;
        struct vmdhAllocAccess_s *vmdha_pnext;
} vmdhAllocAccess;

struct  vmdhAllocAccess_s *pAccessList;        /* Head of linked list */

#pragma data_seg()


#pragma code_seg()


/***EP  dhw_VMLock - Worker function for DevHlp interface dh_VMLock.
 *
 *      dhw_VMLock locks a memory range in physical memory.
 *      Contiguous locks will not be allowed to exceed 64K in size. Contiguous
 *      locks may require byte by byte copy of the pages in physical memory,
 *      and are considerably slower than locks that do not require contiguity.
 *      The memory will not be locked if verify flag is set, however all
 *      requests for reallocating, freeing, or decommitting memory will fail
 *      as long as there are outstanding verify requests on it. Contiguouity,
 *      below 16 Meg or Write flags are invalid with a verify request.
 *      WARNING: This function can be called with NOBLOCK option. Therefore
 *      it must remain in resident code.
 *
 *      ENTRY   flags - Action to be taken      (unsigned long)
 *                  1: VMDHL_NOBLOCK
 *                      Do not block,return immediately if pages not available.
 *                  2: VMDHL_CONTIGUOUS
 *                      Make memory range physically contiguous.
 *                  4: VMDHL_16M
 *                      Lock memory below 16Meg physical address.
 *                  8: VMDHL_WRITE
 *                      Lock is for a write request.
 *                 16: VMDHL_LONG
 *                      Lock is for long term (short term if not set)
 *                 32: VMDHL_VERIFY
 *                      Verify accessibility (The object is not locked if
 *                      this flag is set, but all requests for reallocation
 *                      freeing or decommitting memory will fail)
 *             0x8000: VMDHL_TRY_CONTIG
 *                      WARNING: this is a special interface set up for
 *                      the file system.  See PGLock.c for details.
 *
 *              laddr - linear address of the region to be locked
 *              size  - size of lock
 *              phlock - pointer to location to write 96 bit lockhandle.
 *              ppl - pointer to location to write an array of pagelist_s
 *                      strucutres that describe the physical pages underlying
 *                      the linear address range.
 *                      If this value is set to -1 no array is returned.
 *                      For Verify locks, this parameter is ignored.
 *              pel - pointer to location to write number of elements in
 *                    pagelist array.
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMLock(ulong flags,ulong laddr,ulong size,
 *              struct vmlh_s *phlock, ulong *pphysaddr[])
 *
 *      PseudoCode:
 *
 *      If (flags & not flagsmask)
 *          return ERROR_INVALID_PARAMETER
 *      Endif
 *      If (fl & VMDHL_VERIFY)
 *          if (fl & (VMDHL_CONTIGUOUS | VMDHL_16M))
 *              return(ERROR_INVALID_PARAMETER)
 *          endif
 *      Endif
 *      Verify validity of phlock address
 *      Convert VMDHL_ flags to VML_ flags
 *      Call VMLockMem (flags & lockmask, laddr, size, cur. context,
 *                      ppagelist array, ppagelist count)
 *      return (NO_ERROR)
 */
int                 dhw_VMLock(fl, laddr, cb, phlock, ppl, pel)
ulong_t             fl;     /* action flags (converted to VML_ flags later) */
ulong_t             laddr;  /* address of lock */
ulong_t             cb;     /* size in bytes of region to be locked */
struct vmlh_s *phlock;      /* Location to return lockhandle */
struct pagelist_s   *ppl;   /* Location to return PageList array */
ulong_t             *pel;   /* Location to return number of elements in array*/
{
    ulong_t fTryContig;


#define FIX_VMLOCK_BUGBUG
#ifdef  FIX_VMLOCK_BUGBUG
    ljmp_t lj;             /* TKlongjmp buffer */                      //b720627
    char    c;                                                         //b720627

    if (fl &  VMDHL_TRY_CONTIG) {
        fl &= ~VMDHL_TRY_CONTIG;
        fTryContig=VML_TRY_CONTIG;
    } else {
        fTryContig=0;
    }

    if ( (!(fl & ~vmdhL_FlagsMask)) &&
         (fl <= vmdhL_MaxFlags) &&
         (cb <= VMMAXSIZE) &&
         (cb != 0) &&
         /* Convert to VML_ flags, error if invalid */
         ((fl = vmdhL_Flags[fl]) != -1)) {

        /* Verify the validity of phlock address, and the page list. */
        if (TKCatchFault(SSToDS(&lj)) == NO_ERROR) {                  // b720627
            // Try viewing both ends of the lock handle buffer.
            c = *((char *)phlock + sizeof(VMLH) - 1) |
                *(char *)phlock;
            // If the caller asks for a page list, then
            // try viewing both ends of the 'page list array' buffer,
            // and both ends of the 'number of elements' buffer.
            if ((ulong_t)ppl != -1)
                c = *((char *)ppl + sizeof(struct pagelist_s) *
                      (((ulong_t)ppl + cb)
                      - ((ulong_t)ppl & (~((ulong_t)PAGESIZE-1)))
                      + ((ulong_t)PAGESIZE - 1) >> PAGESHIFT) - 1)
                  | *(char *)ppl
                  | *(char *)pel
                  | *((char *)pel + sizeof(ulong_t) - 1);

            // Clear the fault handler.
            TKClrFault();

            /* Lock the region and fill in pagelist array if requested */
            return(VMLockMem(laddr, cb, fl | fTryContig, phlock, ppl, pel));
        }
    }
    return(ERROR_INVALID_PARAMETER);

#else
    if ((fl & ~vmdhL_FlagsMask) || (fl > vmdhL_MaxFlags) || cb > VMMAXSIZE ||
        cb == 0)
        return(ERROR_INVALID_PARAMETER);

    /* Convert to VML_ flags, error if invalid */
    if ((fl = vmdhL_Flags[fl]) == -1)
        return(ERROR_INVALID_PARAMETER);


    /* Lock the region and fill in pagelist array if requested */
    /*
     *  BUGBUG - a local fault handler should be used to verify the
     *           caller's lock handle pointer and the page list.
     */
     return(VMLockMem(laddr, cb, fl, phlock, ppl, pel));
#endif

}



/***EP  dhw_VMUnlock - Worker function for DevHlp interface dh_VMUnlock.
 *
 *      dhw_VMUnlock unlock previously locked memory range.
 *      WARNING: This function is in swappable code.
 *
 *      ENTRY   phlock - Pointer to lock handle returned by VMLock
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMUnlock (struct vmlh_s *phlock)
 *
 *      PseudoCode:
 *
 *      Verify it is a Devhlp lock
 *      Call VMUnlock
 *      return
 */
int                    dhw_VMUnlock(phlock)
register struct vmlh_s    *phlock;      /* Lock handle */
{

#define FIX_VMUNLOCK_BUGBUG
#ifdef  FIX_VMUNLOCK_BUGBUG
ljmp_t lj;             /* TKlongjmp buffer */                          //b720627
char    c;                                                             //b720627

    /* Verify the validity of phlock address, and verify that */
    /* the Devhlp lock flag is set.                           */
    if (TKCatchFault(SSToDS(&lj)) == NO_ERROR) {     // b720217
        c = *((char *)phlock + sizeof(VMLH) - 1) |   // Try viewing both ends
            *(char *)phlock;                         // of the lock handle.
        TKClrFault();                                // Clear the fault handler.
        if (phlock->lh_flags & VMLH_DEVHLP) {
            return (VMUnlock(phlock));
        }
    }
    return(ERROR_INVALID_PARAMETER);
#else
    /* Verify validity of phlock address. */
    /*
     *  BUGBUG - a local fault handler should be used to verify the
     *           caller's lock handle pointer.
     */

    /* Verify that it is a Devhlp lock */
    if ((phlock->lh_flags & VMLH_DEVHLP) == 0)
        return(ERROR_INVALID_PARAMETER);
    return (VMUnlock(phlock));
#endif
}


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

/***EP  dhw_VMGlobalToProcess - Worker function for DevHlp interface
 *          dh_VMGlobalToProcess.
 *
 *      dhw_VMGlobalToProcess creates a mapping to global address range in
 *      the user address range. The address range can not cross memory
 *      objects. Address must be on a page boundary.
 *      If selector map is requested, selectors will be allocated as
 *      ring 3 data.
 *      WARNING: Existing hardware may not support read only mapping.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY   flags - Action flags
 *                    1:VMDHGP_WRITE Read only map requested (r/w otherwise)
 *                    2:VMDHGP_SELMAP Selector map requested
 *                    4:VMDHGP_SGSCONTROL Register under SGS control
 *                    8:VMDHGP_4MEG Allocate on a 4Meg boudary
 *                   16:VMDHGP_ATTACH Attach shared memory
 *              laddr - Linear address of region to be aliased
 *                      (Must be on a page boundary)
 *              size  - Size of region to be aliased
 *              pladdr - pointer to location to write alias linear address to.
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMGlobalToProcess(ulong flags, ulong laddr, ulong size,
 *          ulong_t *pladdr, SEL *psel)
 *
 *      PseudoCode:
 *
 *      If (flags & not flagsmask, or laddr not in sys arena)
 *          return (ERROR_INVALID_PARAMETER)
 *      Endif
 *      If (laddr not on a page boundary)
 *          return (ERROR_INVALID_PARAMETER)
 *      Endif
 *      Call VMMapAlias(cur. context, [selmap], [readonly])
 *      return
 */
int     dhw_VMGlobalToProcess(fl, laddr, cb, pladdr)
ulong_t fl;                             /* Map flags */
ulong_t laddr;                          /* Address to map*/
ulong_t cb;                             /* size of map */
ulong_t *pladdr;                        /* location to return alias address */
{
    int     rc;                         /* return code */
    register ulong_t flvm = VMDHGP_FLVM; /* Flags passed to VMMapAlias */
    ulong_t flsel = VMDHGP_FLSEL;       /* Flags for SELMGR */
    VMAC    ac;                         /* VMMapAlias return info buffer */
    VMOD    od;
    VMHOB   hob;

    if (fl & VMDHGP_ATTACH)
    {
        //  Must be a shared linear address we want to attach to process
        if ( !(VMShrArena(laddr)))
            return(ERROR_INVALID_PARAMETER);

        od.od_laddr = laddr;
        od.od_pPTDA = NULL;
        if((rc = VMGetOd(VMOD_ANY_CTXT| VMGS_TAKESEM, SSToDS(&od))) != NO_ERROR)
            return(ERROR_INVALID_ADDRESS);

        hob = VMHobOd(od);
        if(laddr != od.od_laddr)
        {
            rc = ERROR_INVALID_ADDRESS;
            goto retclearsem;
        }

        if ((rc = VMAttach(hob, pPTDACur->ptda_handle, PG_U | PG_R | PG_W)) == NO_ERROR)
        {
            *pladdr = (ulong_t) od.od_laddr;  // Return address - same as input
        }
retclearsem:
        VMClearSem(hob);
        return(rc);
    }

    if (fl & ~(VMDHGP_WRITE | VMDHGP_SELMAP | VMDHGP_SGSCONTROL |
        VMDHGP_4MEG))
        return(ERROR_INVALID_PARAMETER);
    if (!(VMSysArena(laddr)))
        return(ERROR_INVALID_PARAMETER);
    if (laddr & PAGEMASK || cb > VMMAXSIZE || cb == 0)
        return(ERROR_INVALID_PARAMETER);

    /* Convert input flags to VMMapAlias alloc flags */
    if (fl & VMDHGP_WRITE) {
        flvm |= PG_W;
        flsel |= SELAL_W;
    }
    if (fl & VMDHGP_4MEG)
        flvm |= VMAC_ALIGNDIR;
    else
        flvm |= VMAC_ALIGNSEL;

    if ((rc = VMMapAlias(flvm, flsel, VMMA_DEVHLP, NULL, HOBNULL, laddr,
             HOBNULL, cb, SSToDS(&ac))) != NO_ERROR)
        return(rc);
    if (fl & VMDHGP_SGSCONTROL) {
        /* If to be registered under SGS control */
        if (VMSGSControl(VMSGS_U, ac.ac_va) != NO_ERROR) {
            VMFreeMem(ac.ac_va, HOBNULL, NULL);
            return(ERROR_NOT_ENOUGH_MEMORY);
        }
    }
    /* All succeeded */
    *pladdr = (ulong_t) ac.ac_va;       /* return address */
    return(NO_ERROR);
}

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

/***EP  dhw_VMProcessToGlobal - Worker function for DevHlp function.
 *
 *      dhw_VMProcessToGlobal creates a mapping in global address range to
 *      the user address range. The address range can not cross memory
 *      objects.
 *      WARNING: Existing hardware may not support read only mapping.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY   flags - Action flags
 *                    1:VMDHGP_WRITE Read/write map requested (r only otherwise)
 *              laddr - Linear address of region to be aliased
 *              size  - Size of region to be aliased
 *              pladdr - pointer to location to write alias linear address to.
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMProcessToGlobal(ulong flags, ulong laddr, ulong size,
 *          ulong_t *pladdr)
 *
 *      PseudoCode:
 *
 *      If (flags & not VMDHGP_WRITE, or laddr in sys arena)
 *          return (ERROR_INVALID_PARAMETER)
 *      Endif
 *      Call VMMapAlias(globalmap, [readonly], cur.context)
 *      return
 */
int     dhw_VMProcessToGlobal(fl, laddr, cb, pladdr)
ulong_t fl;                         /* Readonly or not */
ulong_t laddr;                      /* Address to map */
ulong_t cb;                         /* Size of map */
ulong_t *pladdr;                    /* Location to return mapping address */
{
    int     rc;                         /* return code */
    VMAC    ac;                         /* VMMapAlias return info buffer */

    if (fl & ~VMDHGP_WRITE || cb > VMMAXSIZE || cb == 0)
        return(ERROR_INVALID_PARAMETER);
    if (VMSysArena(laddr))
        return(ERROR_INVALID_PARAMETER);
    if ((rc = VMMapAlias((fl & VMDHGP_WRITE) ?
        (VMDHPG_FLVM | PG_W) : VMDHPG_FLVM, NULL, VMMA_DEVHLP, NULL,
        HOBNULL, laddr & ~PAGEMASK, HOBNULL, (cb + (laddr & PAGEMASK)),
        SSToDS(&ac))) != NO_ERROR) return(rc);
    /* All succeeded */
    *pladdr = (ulong_t) ac.ac_va + (laddr & PAGEMASK);  /* return address */
    return(NO_ERROR);
}


#pragma code_seg()
#pragma code_seg("SWAP32_28", "CODE")
/***EP  dhw_VMAlloc - Worker function for DevHlp interface dh_VMAlloc
 *
 *      dhw_VMAlloc allocates virtual memory, and depending on flags,
 *      it either commits physical storage or maps virtual memory to
 *      given physical address.
 *      Virtual memory is allocated in global (system) address space, unless
 *      private process space is requested. Memory requested in process space
 *      can only be swappable. If VMA_PHYS flag is set the, virtual memory
 *      is mapped to given physical address. The physical memory must be
 *      fixed or locked in this case.
 *      If requested, memory allocated in process space can be registered
 *      under screen group switch control. In that case, task will be denied
 *      write access to this memory unless it is in foreground.
 *      If fixed contiguous memory is requested, physical address will be
 *      returned to *ppaddr, unless it is set to -1.
 *      WARNING: This procedure is in swappable code.
 *
 *      ENTRY   flags - Action flags
 *                1:VMDHA_16M Allocate below 16Meg physical address.
 *                          (valid only if VMDHA_FIXED)
 *                2:VMDHA_FIXED Allocate fixed memory
 *                          (not valid if VMDHA_PROCESS)
 *                4:VMDHA_SWAP Allocate swappable memory
 *                          (not valid if VMDHA_FIXED)
 *                8:VMDHA_CONTIG Allocate fixed, physically contiguous.
 *                          memory (valid only with VMDHA_FIXED)
 *               16:VMDHA_PHYS Map given physical address.
 *               32:VMDHA_PROCESS Allocate virtual memory in process space.
 *               64:VMDHA_SGSCONT Register memory under screen group switch
 *                          control. (valid only if VMDHA_PROCESS)
 *              128:VMDHA_SELMAP Map 16:16 selectors
 *              256:VMDHA_RESERVE Reserve (do not commit) memory
 *              Also:
 *                  VMDHIA_USER: If called during initialization.WARNING: This
 *                          flag is not exported through dh_VMAlloc.
 *   MIKEK          VMDHA_SHARED: Allocate shared memory object. This flag
 *                          is only supported for mapping a physical address
 *                          to non-system memory into the shared arena.
 *                          VMDHA_PHYS must be specified.
 *  dcr 32500
 *            0x800:VMDHA_USEHIGHMEM use memory above the 16 meg line if it exists
 *              (NOTE: this is only valid while the DD is doing initialization)
 *  end
 *              size - size of memory to be allocated.
 *              pladdr - pointer to location to write linear address to.
 *              ppaddr - location to read/return physaddr (not used if -1)
 *                         (if VMDHA_PHYS, physaddr is read from this location,
 *                          if fixed & contiguous, physaddr is returned to
 *                          this location)
 *              psel   - location to return the 16:16 address
 *                         (only if VMDHA_SELMAP)
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMAlloc(ulong flags, ulong size, ulong *pladdr, ulong *pphysaddr
 *                   ulong *pvaddr)
 *
 *      PseudoCode:
 *
 *      If (flags & not flagsmask)
 *          return (ERROR_INVALID_PARAMETER)
 *      Endif
 *      If ((fixed & swappable) || (swappable & (16M or contig)) || (sgscont
 *          & not Process))
 *          return(ERROR_INVALID_PARAMETER)
 *      Endif
 *      If (sgs control && not process arena)
 *          return ERROR_INVALID_PARAMETER
 *      Endif
 *      If ((16Meg or contiguous) && not fixed)
 *          return ERROR_INVALID_PARAMETER
 *      Endif
 *      Call VMAllocMem(flags, size, owner, system area)
 *      If (sgs control), add address to sgs linked list
 *      If (error), return (error code)
 *      Write linear address
 *      return (NO_ERROR)
 */
int     dhw_VMAlloc(fl, cb, pladdr, pphysaddr, pvaddr, owner)
ulong_t fl;                     /* allocation flags */
ulong_t cb;                     /* allocation size */
ulong_t *pladdr;                /* Location to return linear address */
ulong_t *pphysaddr;             /* Location to read/return Physaddr */
ulong_t *pvaddr;                /* Location to return 16:16 address */
VMHOB   owner;                  /* owner for memory */
{
    register int     rc;                        /* return code */
    ulong_t flvm;                               /* VMAllocMem flags */
    VMAC    ac;                                 /* VMAllocMem return buffer */
    ulong_t flsel = NULL;                       /* VMAllocMem selmgr flags */
    ulong_t  ipg;
    ulong_t  cpg;
    register struct ptda_s *pptda;         /* PTDA pointer */

    if ((fl & ~vmdhA_FlagsMask) || cb > VMMAXSIZE || cb == 0)
        return(ERROR_INVALID_PARAMETER);
// dcr 32500
    /*  if they're setting the USEHIGHMEM bit then they must also set the
     *  FIXED (resident) bit and must not set the below 16 meg bit (16M)
     */
    if ( (fl & VMDHA_USEHIGHMEM) && (((fl & VMDHA_FIXED) == 0) ||
         (fl & VMDHA_16M)  || (PGGlobalFlags & PG_HIGH_MEM_INITED)) )
        return(ERROR_INVALID_PARAMETER);
// end

    if (fl & VMDHA_PROCESS) {
        /* Check for invalid flags */
        if (fl & (VMDHA_16M | VMDHA_FIXED | VMDHA_CONTIG | VMDHA_SHARED)) {
            return(ERROR_INVALID_PARAMETER);
        }
        if (fl & VMDHA_PHYS) {
            if (fl & VMDHA_SWAP)  {
                return(ERROR_INVALID_PARAMETER);
            }
            flvm = PG_UVIRT | vmdhA_Flvm | vmdhA_FlvmProcess;
        }
        else {
            flvm = PG_SWAPPABLE | vmdhA_Flvm | vmdhA_FlvmProcess;
        }
    }
    else if (fl & VMDHA_SHARED) {
            if (fl & (VMDHA_SWAP | VMDHA_PROCESS | VMDHA_16M | VMDHA_FIXED |
                      VMDHA_CONTIG | VMDHA_SGSCONT | VMDHA_SELMAP)) {
                return(ERROR_INVALID_PARAMETER);
            }
            if (fl & VMDHA_PHYS) //Only valid when input paddr is specified
            {
                flvm = vmdhA_Flvm | vmdhA_FlvmShared;
                flsel = SELAL_SELMAP | (3 << SELAL_PRIVSHIFT) | SELAL_W;
            }
            else
            {
                return(ERROR_INVALID_PARAMETER);
            }
    }
    else {
// dcr 32500
        flvm = fl & ~(VMDHA_USEHIGHMEM | VMDHIA_USER |
                             VMDHA_SELMAP | VMDHA_RESERVE);
// end
        /* Global space, filter out some invalid flags */
        if (flvm > VMDHA_PHYS) {
            return(ERROR_INVALID_PARAMETER);
        }
        vmAssert(max(VMDHA_16M, max(VMDHA_FIXED, max(VMDHA_CONTIG,
            max(VMDHA_SWAP, max(VMDHA_SWAP, VMDHA_PHYS))))) == VMDHA_PHYS);

        flvm = vmdhA_Flags[flvm];
        if (flvm == -1) {
            /* Invalid flags combination */
            return(ERROR_INVALID_PARAMETER);
        }

        flvm |= vmdhA_FlvmSys | vmdhA_Flvm | ((fl & VMDHIA_USER) ? PG_U : 0);
        if (fl & VMDHA_SELMAP) {
            /* selector map is requested */
            flvm |= VMAC_SELALLOC;
            flsel = SELAL_SELMAP | SELAL_GDTRPL0 | SELAL_W |
                (flvm & PG_U) ? SEL_RPL3 << SELAL_PRIVSHIFT : 0;
        }
    }

    if (fl & VMDHA_RESERVE)
      {
        /* Eliminate invalid flags */
        if (fl & (VMDHA_16M | VMDHA_FIXED | VMDHA_SWAP | VMDHA_CONTIG | VMDHA_PHYS))
          {
            return(ERROR_INVALID_PARAMETER);
          }
        flvm |= VMAC_DHSETMEM;
        cb = vmPageCeil(cb);
      }

    /* Some global arena allocations may go to heap */
    if (!(fl & (VMDHA_RESERVE | VMDHA_PHYS | VMDHA_PROCESS)) &&
                                        /* not a uvirt or reserve only map */
        (cb <= vmdhA_MaxHeapSize) &&    /* Below given size */
        (((PAGESIZE - cb) & PAGEMASK) > vmdhA_MaxWaist))
            /* Waists too much memory on the last page */  {

        flvm &= ~(VMAC_ARENAMASK | PG_ZEROFILL | VMAC_ALIGNPAGE);
        flvm |= VMAC_ARENAHEAP;
    }

    rc = VMAllocMem(cb,
                    (fl & VMDHA_RESERVE)? 0 : cb,
                    flvm,
                    HOBNULL,
                    DEVHLPOWNER,
                    owner,
                    (fl & VMDHA_USEHIGHMEM)? flsel | VMACX_USEHIGHMEM : flsel,
                    (fl & VMDHA_PHYS)? *pphysaddr : 0,
                    SSToDS(&ac));

    if (rc != NO_ERROR) return(rc);

    if (fl & VMDHA_SHARED)   // Reset PTEs to have user access
    {
       cpg = VMRegionSize((ulong_t)ac.ac_va, cb) >> PAGESHIFT;
       ipg = VMRegionBase((ulong_t)ac.ac_va) >> PAGESHIFT;

       pptda = VMGetPTDAAddr(HOBNULL);
       if ((rc = PGSetAccess(ipg, pptda, cpg, PG_UVIRT|PG_RESIDENT|PG_U|PG_W))
            != NO_ERROR)
       {
            return(rc);
       }
    }

    if (fl & VMDHA_SGSCONT) {
        /* If to be registered under SGS control */
        if ((rc = VMSGSControl(VMSGS_U, ac.ac_va)) != NO_ERROR) {
            VMFreeMem(ac.ac_va, HOBNULL, NULL);
            return(rc);
        }
    }
    *pladdr = (ulong_t) ac.ac_va;
    if ((flvm & PG_CONTIG) && (pphysaddr != (ulong_t *) (-1))) {
        /* Return physical address of contiguous memory */
        rc = VMLinToPhys(ac.ac_va, pphysaddr);
        vmAssert(rc == NO_ERROR);
    }
    if (fl & VMDHA_SELMAP) {

        /*
         *  For reserve only process space allocations, we don't get any
         *  selectors back. In this case find the selector via laddr.
         */
        if ((fl & VMDHA_RESERVE) && (fl & VMDHA_PROCESS))
          {
            ac.ac_sel = LaToSelTiled(ac.ac_va) | SEL_RPL3;
          }

        /* Return 16:16 address */
        *pvaddr = ac.ac_sel << WORDSHIFT;
    }
    return(NO_ERROR);
}

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

/***EP  dhw_VMSetMem - Worker function for DevHlp interface dh_VMSetMem
 *
 *      dh_VMSetMem commits, decommits or changes type (swappable to resident
 *      or back) of a range of memory based on input flags.
 *      The entire memory region to be acted upon must be of uniform type
 *      (all swappable, all resident, or all free)
 *      The address and size passed must be page aligned.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY   flags - Action flags
 *                1:VMDHS_DECOMMIT  Decommit memory
 *                2:VMDHS_RESIDENT  Make memory resident
 *                4:VMDHS_SWAP      Make memory swappable
 *              laddr - Starting address of the region (must be page aligned)
 *              cb    - Size of the region (must be page aligned)
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMSetMem (ulong flags, ulong laddr, ulong cb)
 *
 *      PseudoCode:
 *
 *      Validate input parameters (no invalid flags, page aligned laddr, cb)
 *      Call VMGetMemInfo, take object semaphore
 *      If (not dhSetMem object || range crosses object boundary)
 *          Call VMClearSem
 *          return(error)
 *      Endif
 *      Call VMSetMemSub
 *      If (error && not decommit request)  ; region may need a type change
 *          Call VMQueryMem
 *          If (all region homogenuous && not of desired tpye)
 *              Call PGSetType
 *          Endif
 *      Endif
 *      Call VMClearSem
 *      return
 */
int         dhw_VMSetMem(fl, laddr, cb)
ulong_t     fl;
ulong_t     laddr;
ulong_t     cb;
{
             int       rc;
             VMOD      od;
             ulong_t   flvm;
             SEL       sel;
             ulong_t   cbdesc;
             ulong_t   cbQuery;
             ulong_t   flQuery;
    register VMOD      *pod = SSToDS(&od);

    /* Validate input parameters */

    if ((fl == NULL) ||
        (fl & ~(VMDHS_DECOMMIT | VMDHS_RESIDENT | VMDHS_SWAP)) ||
        ((fl & VMDHS_RESIDENT) && (fl & (VMDHS_SWAP | VMDHS_DECOMMIT))) ||
        ((fl & VMDHS_SWAP) && (fl & (VMDHS_RESIDENT | VMDHS_DECOMMIT))) ||
        (laddr & PAGEMASK) || (cb & PAGEMASK))
    {
        return(ERROR_INVALID_PARAMETER);
    }

    pod->od_laddr = laddr;
    pod->od_pPTDA = pPTDACur;

    if((rc = VMGetOd(VMGS_VERIFY | VMGS_TAKESEM | VMGS_SLOCKWAIT, pod)) ==
                         NO_ERROR)
    {

        if (!VMDHSetMemOd(*pod) || VMIsAliasOd(*pod))
        {
            rc = ERROR_ACCESS_DENIED;       /* SetMem not allowed */
        }
        else if((pod->od_laddr + VMSizeOd(*pod)) < (laddr + cb))
        {
            rc = ERROR_CROSSES_OBJECT_BOUNDARY;
        }
        else
        {
            /*
             * All is OK.
             * Assume it is a commit/decommit request
             */

            flvm = (fl & VMDHS_DECOMMIT) ? VMS_DECOMMIT :
                                           ((fl & VMDHS_RESIDENT) ?
                                           vmDHS_Flvm | PG_RESIDENT :
                                           vmDHS_Flvm | PG_SWAPPABLE);

            sel = ((pod->od_par)->ar_f & AR_SELMAP) ? VMSelOd(*pod) : NULL;

            if(VMTiled(laddr))
            {
                flvm |= PG_U;
            }

            if (sel != NULL)
            {
                rc = SELGetSize(pod->od_laddr, sel, HOBNULL, VMSizeOd(*pod),
                                    SSToDS(&cbdesc));

                vmAssert(rc == NO_ERROR);

                if (!(fl & VMDHS_DECOMMIT) &&
                    ((pod->od_laddr + cbdesc) < (laddr + cb)))
                {
                    flvm |= VMS_SELMAP;
                }

            }
            else
            {
                cbdesc = NULL;
            }

            rc = VMSetMemSub(flvm, pod, laddr, cb, NULL, cbdesc);

            if ((rc == ERROR_ACCESS_DENIED) && !(fl & VMDHS_DECOMMIT))
            {
                /*
                 *  This may be a change type operation. Use PGSetType instead.
                 */

                flQuery = VMQ_STATE;
                cbQuery = cb;
                rc = VMQueryMem(laddr, SSToDS(&cbQuery), HOBNULL,
                                    SSToDS(&flQuery));

                vmAssert(rc == NO_ERROR);

                flQuery &= PQ_TYPEMASK;

                /* Return error if all memory of not uniform type */

                if ((cbQuery < cb) || (flQuery == PQ_INVALID))
                {
                    rc = ERROR_ACCESS_DENIED;
                }
                else if (((flQuery == PQ_RESIDENT) && (fl & VMDHS_RESIDENT)) ||
                         ((flQuery == PQ_SWAPPABLE) && (fl & VMDHS_SWAP)))
                {
                    /*
                     * The object already of desired type. Return NO_ERROR
                     */
                    rc = NO_ERROR;
                }
                else
                {
                    /* We have to change type */
                    rc = PGSetType(laddr >> PAGESHIFT, pPTDACur,
                                   cb >> PAGESHIFT,
                                   (fl & VMDHS_RESIDENT) ? PG_RESIDENT :
                                                           PG_SWAPPABLE);
                }
            }
        }
        VMClearSem(vmPobToHob(pod->od_pob));
    }
    return(rc);
}


#pragma code_seg()


/***EP  dhw_VMFree - Worker function for DevHlp interface dh_VMFree
 *
 *      dhw_VMFree frees the fixed memory allocated via dhw_VMAlloc, or
 *      the mappings created via GlobalToProcess and ProcessToGlobal.
 *
 *      ENTRY   laddr - Linear address of memory object
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMFree(ulong laddr)
 *
 *      PseudoCode:
 *
 *      Call VMGetMemInfo
 *      If (error)
 *          return (ERROR_INVALID_PARAMETER)
 *      Endif
 *      If (owner != DevHlpOwner || !(ALIAS and DEVHLP alias))
 *          return ERROR_ACCESS_DENIED
 *      Endif
 *      Call VMFreeMem(laddr)
 *      If (under sgs control), remove from sgs control linked list
 *      return(NO_ERROR)
 */
int dhw_VMFree(laddr)
ulong_t laddr;                              /* address of object */
{
//  VMOI    oi;                             /* VMObjectInfo return buffer */
    VMOD    od;                             /* VMObjectInfo return buffer */
    VMHOB   hobowner;
    int     rc;

//  if (VMGetMemInfo(VMGS_SLOCKWAIT | VMGS_VERIFY,
//      laddr, 0, SSToDS(&oi), 0) != NO_ERROR)

    od.od_laddr = laddr;
    od.od_pPTDA = pPTDACur;
    if (VMGetOd(VMGS_SLOCKWAIT | VMGS_VERIFY, SSToDS(&od)) != NO_ERROR)
    {
        return(ERROR_INVALID_PARAMETER);
    }
//  if (!(VMIsAliasOi(oi))) {

    if (!(VMIsAliasOd(od)))
    {
        /* If not an alias, owner better be DevHlp or HEAP */
//      if (oi.oi_hobowner == VMKRHRWOWNER || oi.oi_hobowner == VMKRHROOWNER ||
//          oi.oi_hobowner == VMKSHRWOWNER || oi.oi_hobowner == VMKSHROOWNER)

        hobowner = (od.od_pob)->ob_hobowner;
        if (hobowner == VMKRHRWOWNER || hobowner == VMKRHROOWNER ||
            hobowner == VMKSHRWOWNER || hobowner == VMKSHROOWNER)
        {
            /*
             * Heap allocation. Get the heap block owner, and validate that
             * the address is start of a kernel heap block.
             */

//          if ((rc = SELValidateKHBAddress((char *)laddr, (SEL *) VM_NO_ADDR,
//              SSToDS(&(oi.oi_hobowner)))) != NO_ERROR)

            if ((rc = SELValidateKHBAddress((char *)laddr, (SEL *) VM_NO_ADDR,
                                            SSToDS(&hobowner))) != NO_ERROR)
            {
                return(rc);
            }
        }
        else
        {
//          if (laddr != oi.oi_va)              /* Must be base address */

            if (laddr != od.od_laddr)           /* Must be base address */
            {
                return(ERROR_INVALID_PARAMETER);
            }
        }

//      if (!IsDevHlpOwner(oi.oi_hobowner))

        if (!IsDevHlpOwner(hobowner))
        {
            return(ERROR_ACCESS_DENIED);
        }
    }
    else                /* better be DEVHLP alias */
    {
//      if (!(vmCheckAlias(VMMA_DEVHLP, oi.oi_hob, oi.oi_har)))

        if(!(vmCheckAlias(VMMA_DEVHLP, vmPobToHob(od.od_pob),
                               vmParToHar(od.od_par))))
        {
            return(ERROR_ACCESS_DENIED);
        }
        if (VMSysArena(laddr))
        {
            /* Global aliases may have unaligned addresses */
            laddr &= ~PAGEMASK;
        }
//      if (laddr != oi.oi_va)              /* Must be base address */
        if (laddr != od.od_laddr)           /* Must be base address */
        {
            return(ERROR_INVALID_PARAMETER);
        }
    }
// dcr 32500
// BUGBUG - for now don't free memory allocated with VMDHA_USEHIGHMEM
//          until after the page manager has initialized high memory
    if ((PGGlobalFlags & PG_HIGH_MEM_INITED) == 0)
    {
//      if (oi.oi_xflags & VMOB_HIGHMEM)
        if ((od.od_pob)->ob_xflags & VMOB_HIGHMEM)
        {
            return(0);
        }
    }
// end
    return(VMFreeMem(laddr, HOBNULL, VMFM_ALLOW_HEAP));
}



/***EP  VMLinToPhys - Convert linear address to physical
 *
 *      VMLinToPhys converts linear address to physical.
 *
 *      ENTRY   laddr - linear address to convert
 *              pphysaddr - pointer to location to write physical address to.
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      VMLinToPhys(ulong laddr, ulong *pphysaddr)
 *
 *      Don't use the 'far' keyword (FS and GS must be preserved)
 *
 *      PseudoCode:
 *
 *      Set offst = laddr & PAGEMASK
 *      Convert linear address to pageno
 *      Call PGPageToPhys
 *      If (no error)
 *          Add offst to returned physical address
 *      Endif
 *      return
 */
int             VMLinToPhys(laddr, pphysaddr)
ulong_t         laddr;          /* linear address */
ulong_t         *pphysaddr;     /* pointer to location to write phys addr */
{
    int     rc;                 /* return code */
    ulong_t paddr;

    if ((rc = PGPageToPhys(laddr>>PAGESHIFT,pPTDACur,
        SSToDS(&paddr))) == NO_ERROR)
        *pphysaddr = paddr + (laddr & PAGEMASK);
    return(rc);
}


#pragma code_seg("CINIT_TEXT", "CODE")      /* This section goes to INIT code */

/***EP  dhw_VMInitAlloc - Worker function for DevHlp interface dh_VMAlloc
 *          used during initialization.
 *
 *      This procedure turns on the VMDHIA_USER flag and calls dhw_VMAlloc.
 *      This enables device drivers to access their allocated memory during
 *      initialization. At the end of initialization, VMDHIA_USER flag will
 *      be turned off for every memory allocated via this function.
 *      ENTRY   flags - Action flags
 *                1:VMDHA_16M Allocate below 16Meg physical address.
 *                          (valid only if VMDHA_FIXED)
 *                2:VMDHA_FIXED Allocate fixed memory
 *                          (not valid if VMDHA_PROCESS)
 *                4:VMDHA_SWAP Allocate swappable memory
 *                          (not valid if VMDHA_FIXED)
 *                8:VMDHA_CONTIG Allocate fixed, physically contiguous.
 *                          memory (valid only with VMDHA_FIXED)
 *               16:VMDHA_PHYS Map given physical address.
 *               32:VMDHA_PROCESS Allocate virtual memory in process space.
 *               64:VMDHA_SGSCONT Register memory under screen group switch
 *                          control. (valid only if VMDHA_PROCESS)
 *              128:VMDHA_SELMAP Map 16:16 selectors
 *              Also:
 *                  VMDHIA_USER: If called during initialization.WARNING: This
 *                          flag is not exported through dh_VMAlloc.
 *              size - size of memory to be allocated.
 *              pladdr - pointer to location to write linear address to.
 *              ppaddr - location to read/return physaddr (not used if -1)
 *                         (if VMDHA_PHYS, physaddr is read from this location,
 *                          if fixed & contiguous, physaddr is returned to
 *                          this location)
 *              psel   - location to return the 16:16 address
 *                         (only if VMDHA_SELMAP)
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      dhw_VMInitAlloc(ulong flags, ulong size, ulong *pladdr,
 *                   ulong pphysaddr, ulong *pvaddr)
 */
int     dhw_VMInitAlloc(fl, cb, pladdr, pphysaddr, pvaddr, owner)
ulong_t fl;                     /* allocation flags */
ulong_t cb;                     /* allocation size */
ulong_t *pladdr;                /* Location to return linear address */
ulong_t *pphysaddr;             /* Location to read/return Physaddr */
ulong_t *pvaddr;                /* Location to return 16:16 address */
VMHOB   owner;                  /* owner for memory */
{
    int     rc, rc2;            /* return code */

    /*
     * If it is not a process space allocation or not physical mapping,
     * we need to turn on the VMDHIA_USER flag.
     */

    if (!(fl & (VMDHA_PROCESS | VMDHA_PHYS))) {
        fl |= VMDHIA_USER;
    }
    if (((rc = dhw_VMAlloc(fl, cb, pladdr, pphysaddr, pvaddr, owner)) == NO_ERROR) &&
        (fl & VMDHIA_USER)) {
        /* Register this into the temporary access list */
        if ((rc = vmdh_AllocAddList(*pladdr,
            (fl & VMDHA_SELMAP) ? *pvaddr : NULL, owner)) != NO_ERROR) {
            rc2 = dhw_VMFree(*pladdr);
            vmAssert(rc2 == NO_ERROR);
        }
    }
    return(rc);
}


/***LP  vmdh_AllocAddList - Add the given address to the temporary access
 *              list.
 *
 *      vmdh_AllocAddList adds the given address to the linked list of objects
 *      where temporary access has been added. At the end of initalization,
 *      this list will be walked and every object will have its user level
 *      access removed.
 *
 *      ENTRY       laddr   - Linear address of the object
 *                  vaddr   - 16:16 address of the object (0 if no selmap)
 *                  owner   - owner of object
 *      EXIT        rc      - error code
 *
 */
int         vmdh_AllocAddList(laddr, vaddr, owner)
ulong_t     laddr;
ulong_t     vaddr;
VMHOB       owner;
{
    int     rc;
    struct  vmdhAllocAccess_s  *pvmdha;

        // BUGBUG - remove owner parameter

    if ((rc = VMAllocKHB(VM_HKH_PUB_RESRW, sizeof(vmdhAllocAccess),
        INITOWNER, NULL, (void **)(SSToDS(&pvmdha)))) == NO_ERROR) {
        pvmdha->vmdha_laddr = laddr;
        pvmdha->vmdha_vaddr = vaddr;
        pvmdha->vmdha_pnext = pAccessList;
        pAccessList = pvmdha;
    }
    return(rc);
}


/***LP  vmdh_AllocRemoveList - Remove given entry from temporary access list
 *
 *      vmdh_AllocRemoveList walks the linked list of temporary access
 *      objects, and removes the record found with the given laddr.
 *
 *      ENTRY       laddr   - Linear address of the given object
 *      EXIT        NONE
 */
void        vmdh_AllocRemoveList(laddr)
register ulong_t     laddr;
{
    register struct  vmdhAllocAccess_s   *pvmdha, *pprev = NULL;

    if (VMSysArena(laddr)) {
        /* We don't put process arena memory here */
        pvmdha = pAccessList;       /* Get head of linked list */
        while (pvmdha) {
            if (pvmdha->vmdha_laddr == laddr)
                break;
            pprev = pvmdha;
            pvmdha = pvmdha->vmdha_pnext;
        }
/*      vmAssert(pvmdha);   @SEC - can be null..  09/15/94  */
        if(pvmdha)
        {
            if (pprev == NULL) {
                pAccessList = pvmdha->vmdha_pnext;
            } else {
                pprev->vmdha_pnext = pvmdha->vmdha_pnext;
            }
            VMFreeKHB(VM_HKH_PUB_RESRW, (char *)pvmdha);
        }
    }
    return;
}


/***EP  VMDH_AllocRemoveAccess - Remove user level access from the objects
 *
 *      VMDH_AllocRemoveAccess walks the linked list of temporary accessed
 *      objects and removes user level access from them
 *
 *      ENTRY       NONE
 *      EXIT        NONE
 */
void    VMDH_AllocRemoveAccess()
{
    register struct  vmdhAllocAccess_s   *pvmdha, *pnext = NULL;

    pvmdha = pAccessList;       /* Get head of linked list */
    while (pvmdha) {
        pnext = pvmdha->vmdha_pnext;
        SELRemoveAccess(pvmdha->vmdha_laddr,
            (SEL)(pvmdha->vmdha_vaddr >> WORDSHIFT));
        VMFreeKHB(VM_HKH_PUB_RESRW, (char *)pvmdha);
        pvmdha = pnext;
    }
    return;
}
