#define SCCSID  "@(#)vmalias.c  6.7 92/01/16"

/*       IBM/Microsoft Confidential
 *
 *       Copyright (c) IBM Corporation 1987, 1989
 *       Copyright (c) Microsoft Corporation 1987, 1989
 *
 *       All Rights Reserved
 *       Change History
 *Defect 113450 04/10/95 ChangeTeam - An IPE was occurring in _pgMoveFrame
 *       because VMScanMaps did not find all of the PTEs for a page when
 *       VMMapAlias had created a PTE via PGAttach, but had not updated
 *       the object and arena records.  In VMMapAlias, moved the code which
 *       updates the object, arena, and alias records prior to the PGAttach
 *       call to prevent the IPE.
 *Defect 144206 12/11/95 ChangeTeam - Reinstated fix
 *       147968 5/11/96  RJM Change FSD and DD system owners to use HMTEs
 */

/*      This file contains VMM support for local (ptrace and VDM) aliasing
 *      functionality.
 *      Alias records are kept in a resident BMP object. These are connected
 *      doubly to their corresponding arena records via handles. Arena
 *      record contains the handle to alias records, and alias record contains
 *      a handle to arena record. Only way to walk through all aliases of an
 *      object is to walk its arena records.
 *      WARNING: Access to alias Bmp records is not serialized. Multiple
 *      contexts can be working on alias records belonging to different
 *      memory objects at the same time. In order to avoid conflicts:
 *      ** Always obtain the corresponding memory object handle semaphore
 *      when reading or modifying a given alias record.
 *
 *      Alias records are managed by BMP32. The lowest bit in the fifth
 *      byte indicates the busy bit. It is set if the record is inuse,
 *      cleared if not.
 */


#define INCL_DOSERRORS
#define INCL_OS2STD
#include <os2.h>

#define INCL_DOSP
#include <os2p.h>

#define   FNO_NUM FNO_VMALIAS_C
#include                <fnomem.h>
#include                <osmac.h>

#include <mi.h>
#include <seldesc.h>
#include <pgexport.h>
#include <vmexport.h>
#include <vmowner.h>
#include <vmlocal.h>
#include <selxport.h>
#include <tkexport.h>
#include <dossymc.h>        /* tkptda.h needs it */
#include <sigdef.h>         /* tkptda.h needs it */
#include <except.h>         /* tkptda.h needs it */
#include <infoseg.h>        /* tkptda.h needs it */
#include <curdir.h>         /* tkptda.h needs it */
#include <dirent.h>         /* tkptda.h needs it */
#include <find.h>           /* tkptda.h needs it */
#include <screen.h>         /* tkptda.h needs it */
#include <sem.h>                    /* tkptda.h needs it */
#include <tkptda.h>
#include <ldrxport.h>
#include <dynxport.h>
#include <stdlib.h>
#define FOR_EXEHDR      1 /* 147968 */
#include <exe386.h>       /* 147968 */
#include <ldrvars.h>      /* 147968 */

#define  PARMCHECK  1

int     _stdcall        vmIsBusyAliasRec(VMAL*pal);

extern  void *pBlackHole;


/***LP  vmFreeAlias - Free alias record belonging to given arena record.
 *
 *      vmFreeAlias will free the alias record and turn off OB_LALIAS bit
 *      in object record flags if needed.
 *      WARNING: This procedure assumes that the handle semaphore is
 *      obtained.
 *      WARNING: This procedure must be in resident code, because walking
 *      the arena records and turning off the OB_LALIAS flag should be done
 *      without being preempted.
 *
 *      vmFreeAlias(har, hob)
 *
 *      ENTRY   har     - handle to alias arena record
 *              hob     - handle to object record
 *      RETURN  NONE
 *
 *      PseudoCode:
 *
 *      Call BMPFree
 *      Walk arena records linked list to see if any aliases left
 *      Turn off OB_LALIAS flag if not any
 */

void
vmFreeAlias(har, hob)
register VMHAR har;
VMHOB hob;
{
    register VMOB *pob;
    register VMAR *par;
    VMAL *pal;

    pob = vmHandleMap(hob);
    par = vmArMap(har);
    pal = vmHalToPal(par->ar_hal);

    vmSemAssertOb(pob);
    vmAssert(vmAliasAr(par));           /* Make sure it's an alias AR */
    pal->al_f = 0;                      /* clear busy bit */
    BMPFree(palVMAliases, pal);         /* and free the alias record */

    har = pob->ob_har;
    while (har) {
        if (vmAliasAr((par = vmArMap(har)))) {
            return;
        }
        har = par->ar_harlink;
    }

    /* We come here only if there are no more aliases left */

    pob->ob_fs &= ~OB_LALIAS;
}



/***LP  vmCheckAlias - Check the alias record to make sure it is of desired
 *          type.
 *
 *      vmCheckAlias returns true if the passed alias type matches that in the
 *      alias records. (CS, MEMMAP, DEBUG or DEVHLP)
 *      WARNING: This function is called without obtaining the handle
 *      semaphore, therefore it must remain in resident code.
 *
 *      ENTRY   fl  - alias type flag (more than one can be specified)
 *                  VMMA_CSALIAS, VMMA_MEMMAP, VMMA_DBGALIAS, VMMA_DEVHLP
 *              hob - handle of aliased object.
 *              har - handle to arena record.
 *      RETURN  int - error code (NO_ERROR if no error)
 *
 *      int vmCheckAlias (ulong fl, VMHOB hob, VMHAR har)
 *
 *      PseudoCode:
 *
 *      Call vmSearchAlias(hob, pvaddr) ; Find the base handle record
 *      Call vmFindPal
 *      return (pal->al_f & fl)
 */
int     vmCheckAlias(fl, hob, har)
ulong_t fl;                     /* alias type(s) to search for */
VMHOB   hob;                    /* Handle to object record */
VMHAR   har;                    /* Handle to arena record */
{
    register VMAR *par = vmArMap(har);

#ifdef INCDEBUG
    vmAssert((fl & ~(VMMA_CSALIAS | VMMA_MEMMAP | VMMA_DBGALIAS | VMMA_DEVHLP))
        == NULL);
#else
    vmAssert((fl & ~(VMMA_CSALIAS | VMMA_MEMMAP | VMMA_DEVHLP))
        == NULL);
#endif
    vmAssert(VMMA_CSALIAS == AL_CSALIAS);
    vmAssert(VMMA_MEMMAP == AL_MEMMAP);

#ifdef INCDEBUG
    vmAssert(VMMA_DBGALIAS == AL_DBGALIAS);
#endif

    vmAssert(VMMA_DEVHLP == AL_DEVHLP);
    vmAssert(vmAliasAr(par));
    return((vmHalToPal(par->ar_hal))->al_f & fl);
}


/***LP  vmIsPrivLoadObj - A loader object being privatized for a debug alias
 *
 *      vmIsPrivLoadObj is called by VMMapDebugAlias when a privatized
 *      object is a loader object. If the object is a loader resource
 *      object, or no other contexts exists, loader must be called to make
 *      sure that it won't attach new contexts to privatized memory. This
 *      cal is only necessary if it is not done earlier due to previous
 *      privatization.
 *      WARNING: This procedure must remain in resident code, since marking
 *      the context as privatized should be done upon return from LDRFreeObject
 *      without being preempted.
 *
 *      void vmIsPrivLoadOb(flmap, poi)
 *
 *      ENTRY   flmap - Current flmap flags in VMMapDebugAlias
 *              poi   - pointer to object info buffer.
 *      RETURN  NONE
 *
 *      PseudoCode:
 *
 *          Call loader to decrement ref. count from its data if necessary
 */
// void        vmIsPrivLoadOb(flmap, poi)
// ulong_t     flmap;                  /* flags */
// register    VMOI *poi;              /* pointer to object information */

void        vmIsPrivLoadOb(flmap, pod)
ulong_t     flmap;                  /* flags */
register    VMOD *pod;              /* pointer to object information */
{

    int     rc;                     /* return code */

//  if (vmIsLoadOb(vmHandleMap(poi->oi_hob))) {

    /* We have to mark the context or arena record privatized now.
     * This marking must be done AFTER the check for loader call,
     * otherwise the check doesn't work properly
     */

//  if (poi->oi_fsar & AR_HCO) {
//      (vmCoMap(poi->oi_hco))->co_fb |= CO_PRIV;

    if ((pod->od_par)->ar_f & AR_HCO)
    {
        (pod->od_pco)->co_fb |= CO_PRIV;
    }
    else
    {
//      vmAssert(!VMShrArena(poi->oi_va) &&
//          !vmAliasAr(vmArMap(poi->oi_har)));
//      (vmArMap(poi->oi_har))->ar_hal = VMHAL_PRIV;

        vmAssert(!VMShrArena(pod->od_laddr) &&
                     !vmAliasAr(pod->od_par));
        (pod->od_par)->ar_hal = VMHAL_PRIV;
    };
}


#define vmVDM_VMAC (VMAC_ARENAPRV | VMAC_LOCSPECIFIC | VMAC_ALIGNPAGE | \
                     VMAC_VDM)

#define vmVDM_PG    (PG_U | PG_W | PG_R | PG_X)

#define vmVDM_PGAL  (PG_UVIRT)


/***EP  VMMapVDM - create/destroy mapping in VDM address space
 *
 *      VMMapVDM creates/destroys aliases or uvirt mappings in the VDM
 *      address space < (1Meg+64Kb). These mappings are always created
 *      in the current VDM context.
 *      If an alias is requested, source address can not be in the
 *      shared arena.
 *      When more than one handle semaphore needs to be taken, VMMapVDM
 *      will take the semaphore of the hihger hob value first.
 *      For best performance, this procedure makes in line updates of arena
 *      and alias records. Therefore these sections must remain in
 *      resident code.
 *
 *      ENTRY       fl      -   Flags
 *                  pMap    -   Pointer to vmMapVDM_s structure
 *                  pSrc    -   Pointer to vmSrcVDM_s structure
 *      RETURN      int     - error code (NO_ERROR if no error)
 *                          Some fields in he structures above updated
 *
 *      struct vmMapVDM_s {
 *          ulong_t   map_laddr;    // linear address of mapping
 *          ulong_t   map_cpg;      // size of mapping in pages
 *          VMHAR     map_har;      // VMHAR used by VM
 *          ushort_t  map_x;        // as yet unused
 *      }
 *
 *      vmMapVDM_s structure contains information about the mapping, whether
 *      it is an alias or uvirt or black hole map. Caller must supply
 *      the map_laddr, and map_cpg fields. The sum of map_laddr and
 *      map_cpg << PAGESHIFT can not exceed (1Meg+64Kb). Both values must
 *      be page aligned. The low 12 bits of map_laddr will be ignored
 *      and treated as if set to 0. map_har and map_x fields must be
 *      zero initialized upon first call to VMMapVDM, and should
 *      never be modified later. These fields are used by VM.
 *      Flags parameter
 *      defines the type of mapping. Following values are valid:
 *
 *      VMVDM_FREE: Free mapping
 *      VMVDM_ALIAS: Create an alias
 *      VMVDM_UVIRT: Create uvirt mapping
 *      VMVDM_BHOLE: Create black hole mapping
 *
 *      struct  vmSrcVDM_s  {
 *          union {
 *              ulong_t src_laddr;      // linear address to be aliased
 *              ulong_t src_paddr;      // physical address for uvirt maps
 *          }
 *          VMHAR       src_har;        // VMHAR used by VM
 *          ushort_t    src_x;          // Unused yet
 *      }
 *
 *      vmSrcVDM_s structure is used only when ALIAS or UVIRT flags are set.
 *      In an alias request, it contains the linear page number. In a uvirt
 *      request, it contains physical page number the pages should be mapped to.
 *      src_har, src_x fields should be cleared upon first call to VMMapVDM,
 *      and every time the address is overwritten or changed.
 *      src_laddr, and src_paddr fields will be rounded DOWN to nearest
 *      page boundary if they are not page aligned.
 *
 *      If VMMapVDM finds an error and cannot undo what it has done so far,
 *      it will free the mapping, clear map_har field, and return error code.
 *
 *      int VMMapVDM(fl, pMap, pSrc)
 *
 *      * If a free request
 *          - Call VMFreeMem
 *      * If first time uvirt/bhole map creation
 *          - Allocate arena record and reserve address space (vmReserveSub)
 *          - Allocate alias record (AL_NOALIAS)
 *          - Call PGAlloc(uvirt/bhole)
 *          - Set up arena and alias records
 *          - return map_har
 *      * If first time alias creation
 *          - Call VMMapAlias
 *          - return map_har
 *      * If remap from bhole/uvirt to a bhole/uvirt
 *          - Call PGRemapUvirt(free and remap)
 *      * If remap from a bhole/uvirt to an alias
 *          - If src_har is given check parameters, else find src_har
 *          - Obtain destination object semaphore
 *          - Set up alias and arena record fields (al_pgoff, al_f, al_hobptda,
 *               ar_hob)
 *          - Link arena record to object link list
 *          - Call PGAttach(free and reattach)
 *          - Release object semaphore
 *      * If remap from an alias to a uvirt/bhole
 *          - Obtain alias object's semaphore
 *          - Make sure long locks do not exist
 *          - Set alias record flags field to AL_NOALIAS
 *          - Set arena record ar_hob field to NULL
 *          - Remove arena record from object's linked list
 *          - Call PGRemapUvirt(free and remap)
 *          - Clear object semaphore
 *      * If remap from an alias to another alias
 *          - If src_har is given check parameters, else find src_har
 *          - Obtain both source and destination object semaphores
 *          - Make sure long locks do not exist
 *          - Reset alias record al_pgoff and al_hobptda fields
 *          - If source and destination objects are different
 *              Reset arena record ar_hob field
 *              Unlink arena record from old object's link list
 *              Relink the arena record to the new object's link list
 *          - Call PGAttach (free and reattach)
 *          - Clear both object semaphores
 *
 *
 *      PseudoCode
 *
 *      if (map_ipg+map_cpg >= (1Meg+64Kb) >> PAGESHIFT;
 *          if ALIAS and src_ipg in shared arena;
 *          if FREE and map_har is NULL;
 *          more than one of FREE, ALIAS, UVIRT, BHOLE flags set)
 *          return error
 *      endif
 *      if (map_har field is NULL)      // first time creation
 *          if (an alias request)
 *              Call VMMapAlias
 *              Obtain arena record handle of new alias
 *          else (if bhole/uvirt request)
 *              Call BMPGet to allocate an alias record
 *              Call vmReserveSub to allocate an arena record and address range
 *              Set up arena and alias record fields
 *              Call PGAlloc(uvirt) to create mapping
 *              If failed call VMFreeMem
 *          endif
 *          If success, fill in map_har field
 *      else
 *          if (ar_ipg or ar_cpg different from map ipg or cpg,
 *              neither ar is an alias nor an objectless ar)
 *              return error
 *          endif
 *          if (a free request)
 *              Call VMFreeMem
 *              clear map_har field
 *          else                            // It is a remap request
 *              if (an alias request)
 *                  Set up src_har field if zero
 *                  if nonzero, check addresses against ar_ipg and ar_cpg
 *                  Set hob1 = max(source and destination object handles)
 *                  Set hob2 = min(source and dest. object handles)
 *                      // hob2 = NULL if destination is a bhole/uvirt map
 *              else                    // a uvirt/bhole map request
 *                  Set hob2 = NULL
 *                  Set hob1 = ar_hob
 *                      // hob1 = NULL if bhole/uvirt to bhole/uvirt map
 *              endif
 *              if (hob1 is not NULL)
 *                  Call VMGetSem(hob1)
 *                  if (hob2 is not NULL)
 *                      Call VMGetSem(hob2)
 *                  endif
 *                  if (was an alias before)
 *                      Check for long term locks, fail request if any
 *                      if (hob1 != hob2)
 *                          Unlink arena record from object's list
 *                          Clear ar_hob field
 *                      endif
 *                  endif
 *                  if (bhole/uvirt request)
 *                      Clear al_pgoff, set al_f = AL_NOALIAS
 *                  else                    // an alias request
 *                      Set up al_pgoff, al_hobptda, al_f fields
 *                      Set ar_hob field
 *                      if (hob1 != hob2)
 *                          Link arena record to object's link list
 *                      endif
 *                  endif
 *              endif
 *              if (an alias requested)
 *                  Call PGAttach
 *              else
 *                  Call PGRemapUvirt
 *              endif
 *              if (hob1 != NULL)
 *                  Call VMClearSem(hob!)
 *                  if (hob2 != NULL)
 *                      Call VMClearSem(hob2)
 *                  endif
 *              endif
 *          endif
 *      endif
 *      return
 */
ulong_t         VMMapVDM(fl, pMap, pSrc)
ulong_t         fl;                     /* VMVDM_* flags */
register        VMMAP *pMap;            /* Pointer to map info structure */
register        VMSRC *pSrc;            /* Pointer to source info structure */
{
    int         rc, rc2;                /* return code */
    VMAC        ac;                     /* VMMapAlias return info buffer */
    VMHAR       har;
    register    VMAR *par;
    VMAR        *par2;                  /* pointer to arena record */
    VMHOB       hob1, hob2;
    VMOB        *pob;
    VMOD        od;                     /* object data */
    VMAL        *pal;
    ulong_t     ipg = pMap->map_laddr >> PAGESHIFT;

    vmAssert(vmVDMTask(pPTDACur));

#ifdef PARMCHECK
    /* Check sanity of input parms */

    if ((ipg + pMap->map_cpg) > ((_1MEG + _64K) >> PAGESHIFT)
                        /* address+size must be below 1Meg+64K */
        || ((fl == VMVDM_ALIAS) && VMShrArena(pSrc->src_laddr))
                        /* source of alias can't be in shared region */
        || (fl > max(VMVDM_FREE, max(VMVDM_ALIAS,
            max(VMVDM_UVIRT, max(VMVDM_MAPBACK,VMVDM_BHOLE)))))
        || (pMap->map_x != 0)
      )
        return(ERROR_INVALID_PARAMETER);

#endif

    /* special case, map back target to source */
    if(fl==VMVDM_MAPBACK) {

      /* attach to target page(s) to the source area */
      rc = PGAttach(pSrc->src_laddr >> PAGESHIFT, pPTDACur, ipg,
                    pPTDACur, pMap->map_cpg, (PG_REMAP | PG_SWITCHMAP));

      return(rc);

      }

    /* if free request and the handle is null, then free it */
    if((fl == VMVDM_FREE) && (pMap->map_har == HARNULL)) {

      rc = VMFreeMem(ipg << PAGESHIFT, HOBNULL, NA);

      return(rc);

    }

    if(pMap->map_har == HARNULL) {      /* First time creation */

        if (fl == VMVDM_ALIAS) {
            pSrc->src_laddr &= ~PAGEMASK;
            rc = VMMapAlias(vmVDM_VMAC | vmVDM_PG, NULL, VMMA_VDM,
                ipg << PAGESHIFT, HOBNULL, pSrc->src_laddr, HOBNULL,
                pMap->map_cpg << PAGESHIFT, SSToDS(&ac));
            if (rc == NO_ERROR) {
                vmAssert(ac.ac_va == (ipg << PAGESHIFT));
                od.od_laddr = ipg << PAGESHIFT;
                od.od_pPTDA = pPTDACur;
                rc = VMGetOd(NA, SSToDS(&od));
                par2 = od.od_par;
                vmAssert((rc == NO_ERROR) && (par2->ar_cpg == pMap->map_cpg));
            };
        } else if (fl > VMVDM_ALIAS) {
            /*
             *  A blackhole or uvirt map request
             */
            if ((rc = BMPGet(palVMAliases, SSToDS(&pal)))
                == NO_ERROR) {  /* Allocate alias record */
                pal->al_pgoff = NULL;
                pal->al_f = AL_ISBUSY | AL_NOALIAS;
                pal->al_hobptda = pPTDACur->ptda_handle;

                /*
                 *  Allocate arena record
                 */
                if ((rc = vmReserveSub(pMap->map_cpg, vmVDM_VMAC, ipg,
                    &(pPTDACur->ptda_ah),
                    pPTDACur->ptda_handle, SSToDS(&par2))) == NO_ERROR) {
                    pal->al_har = vmParToHar(par2);
                    par2->ar_hal = vmPalToHal(pal);
                    par2->ar_hobptda = pPTDACur->ptda_handle;

                    // Other fields of arena record is cleared by vmReserveSub

                    /*
                     *  Alias and arena records updated, now allocate pages
                     */
                    if ((rc = PGAlloc(ipg, pPTDACur, pMap->map_cpg,
                        (fl == VMVDM_UVIRT) ? pSrc->src_paddr :
                        (ulong_t) pBlackHole, 0,0,(fl == VMVDM_UVIRT) ?
                        vmVDM_PGAL | vmVDM_PG | PG_RESIDENT : vmVDM_PGAL |
                        PG_NOINCR | vmVDM_PG)) != NO_ERROR) {

                        rc2 = VMFreeMem(ipg << PAGESHIFT, HOBNULL, NA);
                        vmAssert(rc2 == NO_ERROR);

                    };
                } else {        /* vmReserveSub failed */

                    pal->al_f = 0;      /* Turn off busy flag */
                    BMPFree(palVMAliases, pal);
                };
            };                          /* End BMPGet block */

        };                              /* End if VMALIAS block */

        if (rc == NO_ERROR) {
            pMap->map_har = vmParToHar(par2);
        }
    } else    {
        /*
         *  This is not a first time creation.
         *  map_har is given, its ipg must match that of ipg, and
         *  it must be either an alias or an objectless uvirt ar.
         */
        par = vmArMap(pMap->map_har);

#ifdef PARMCHECK
        if (!(par->ar_f & AR_INUSE) ||
            (par->ar_ipg != ipg) || (par->ar_cpg != pMap->map_cpg)  ||
            (!vmAliasAr(par) && (par->ar_hob != HOBNULL)))
            return(ERROR_INVALID_PARAMETER);
#endif

        if (fl == VMVDM_FREE) {         /* It is a free request */

            rc = VMFreeMem(ipg << PAGESHIFT, HOBNULL, NA);
            if (rc == NO_ERROR) {
                pMap->map_har = HARNULL;
            }
        } else {                        /* It is a remap request */

            if (fl == VMVDM_ALIAS) {    /* Remap to an alias is requested */

                if (pSrc->src_har == HARNULL) { /* src_har not given */
                    od.od_laddr = pSrc->src_laddr;
                    od.od_pPTDA = pPTDACur;
                    rc = VMGetOd(NA, SSToDS(&od));
                    if (rc != NO_ERROR)
                        return(ERROR_INVALID_PARAMETER);
                    par2 = od.od_par;
                    pSrc->src_har = vmParToHar(par2);
                } else {
                    par2 = vmArMap(pSrc->src_har);

                    /*
                     * error if given range and size reaches beyond AR, or
                     * if Ar is an alias or objectless ar
                     */
                    if (!(par2->ar_f & AR_INUSE) ||
                        !(((par2->ar_ipg << PAGESHIFT) <= pSrc->src_laddr) &&
                        ((par2->ar_ipg + par2->ar_cpg) >=
                        ((pSrc->src_laddr >> PAGESHIFT) + pMap->map_cpg))) ||
                        vmAliasAr(par2) || (par2->ar_hob == HOBNULL))  {
                        return(ERROR_INVALID_PARAMETER);
                    };
                };                      /* End if (src_har == NULL) block */


                hob1 = max(par2->ar_hob, par->ar_hob);
                hob2 = min(par2->ar_hob, par->ar_hob);
                /*
                 * NOTE: hob2 = NULL if destination is initially a bhole/uvirt
                 * mapping
                 */
            } else {                /* Remap to a uvirt/bhole requested */
                hob2 = HOBNULL;
                hob1 = par->ar_hob;

                /* NOTE: Both hob1 = hob2 = NULL if destination is initially
                 * bhole/uvirt map
                 */
            };                      /* End if (fl==VMVDM_ALIAS) block */

            if ((hob1 == HOBNULL) ||
                ((rc = VMGetSem(hob1, (hob1 == par->ar_hob) ?
                VMGS_TAKESEM | VMGS_SLOCKWAIT : VMGS_TAKESEM,
                SSToDS(&pob))) == NO_ERROR)) {

                /* If we got the first semaphore or didn't needed it*/
                if ((hob2 == HOBNULL) ||
                    ((rc = VMGetSem(hob2, (hob2 == par->ar_hob) ?
                    VMGS_TAKESEM | VMGS_SLOCKWAIT : VMGS_TAKESEM,
                    SSToDS(&pob))) == NO_ERROR)) {
                    /* If we didn't need or got the second semaphore */

                    pal = vmHalToPal(par->ar_hal);

                    if (vmAliasAr(par)) {
                        /* If it was an alias before */

                        /*
                         * We can't unmap the alias if there are existing
                         * locks on it. We already waited for short term
                         * locks. Now make sure long term locks don't exist
                         * either.
                         */
                        pob = vmHandleMap(par->ar_hob);
                        if (pob->ob_cllock > 0) {
                            rc = vmAccessLongLockInfo(pMap->map_har,
                                pPTDACur->ptda_handle, vmlt_CHECK);
                            /*
                             * Returns ERROR_LONGLOCK if long term locks
                             * exist on the alias
                             */

                            if (rc != NO_ERROR) {

                                VMClearSem(hob1);
                                if (hob2 != HOBNULL)
                                    VMClearSem(hob2);
                                return(rc);
                            };
                        };

                        if (hob1 != hob2) {
                            /*
                             *  Old alias being aliased to a different
                             *  object or being mapped to a uvirt/bhole.
                             *  Unlink the arena record from object's
                             *  linked list.
                             */

                            par2 = NULL;
                            har = pob->ob_har;
                            while (har != pMap->map_har) {
                                har = (par2 = vmArMap(har))->ar_harlink;
                                vmAssert(har);
                            }
                            /* par2 points to previous  record */
                            if (par2 == NULL)
                                pob->ob_har = par->ar_harlink;
                            else
                                par2->ar_harlink = par->ar_harlink;

                            par->ar_hob = HOBNULL;
                            par->ar_harlink = HARNULL;

                        };          /* End unlink from a different object */

                    }               /* End 'if it was an alias' block */

                    if (fl > VMVDM_ALIAS) {

                        /* It is a bhole/uvirt map request */
                        pal->al_pgoff = NULL;
                        pal->al_f = AL_NOALIAS | AL_ISBUSY;

                    } else {
                        /* It is an alias request */
                        par2 = vmArMap(pSrc->src_har);
                        pal->al_f = AL_ISBUSY | AL_VDM;
                        pal->al_pgoff = (pSrc->src_laddr >> PAGESHIFT)
                            - par2->ar_ipg;
                        par->ar_hob = par2->ar_hob;
                        vmAssert(par2->ar_hob);
                        if (hob1 != hob2) {

                            /* Link arena record to new object */
                            pob = vmHandleMap(par->ar_hob);
                            par->ar_harlink = pob->ob_har;
                            pob->ob_har = pMap->map_har;
                        }
                    }           /* End if (fl > VMVDM_ALIAS) block */

                    /*  All VM data structures updated. Now call PGAttach
                     *  or PGRemapUvirt which first free the preexisting
                     *  mapping and then create new mapping.
                     */
                    if (fl == VMVDM_ALIAS) {
                        rc = PGAttach(ipg, pPTDACur,
                          pSrc->src_laddr >> PAGESHIFT, pPTDACur, pMap->map_cpg,
                          PG_REMAP | vmVDM_PG);
                    } else {
                        vmAssert ((fl == VMVDM_UVIRT) || (fl == VMVDM_BHOLE));
                        rc = PGRemapUvirt(ipg, pPTDACur, pMap->map_cpg,
                          ((fl == VMVDM_UVIRT) ? pSrc->src_paddr :
                          (ulong_t) pBlackHole), ((fl == VMVDM_UVIRT) ?
                          0 : PG_NOINCR));
                    }

                    /*
                     *  If the PGAttach fails we can leave the alias record
                     *  linked up since the vdm is going to try to mad the
                     *  thing again.
                     */

                    if (hob2 != HOBNULL)
                        VMClearSem(hob2);

                };      /* End VMGetSem(hob2) block */
                if (hob1 != HOBNULL)
                    VMClearSem(hob1);

            };          /* End VMGetSem(hob1) block */
        };              /* End if (fl == VMVDM_FREE) block */
    };                  /* End 'if first time creation' block */

    return(rc);
}


/***LP  vmIsBusyAliasRec - Check if the given local alias record is busy
 *
 *      vmIsBusyAliasRec returns TRUE if the given local alias record
 *      is busy, FALSE if free.
 *
 *      ENTRY   pal - pointer to the location of local alias record.
 *      RETURN  int - TRUE if alias record is free, FALSE if not
 *
 *      int vmIsBusyAliasRec(VMAL *pal)
 *
 *      PseudoCode:
 *
 *      Check busy flag in local alias record.
 *      If (busy), return (TRUE)
 *      Else    return (FALSE)
 *      Endif
 */
int     _stdcall        vmIsBusyAliasRec(VMAL   *pal)
{
    return(pal->al_f & AL_ISBUSY);
}


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

/***LP  vmInitAliasRec - Initialize alias bmp records object.
 *
 *      vmInitAliasRec initializes alias bmp records memory object.
 *
 *      ENTRY   None
 *      RETURN  none
 *
 *      vmInitAliasRec()
 *
 *      PseudoCode:
 *
 *      Call BMPInit(VMAL_MAXRECS, sizeof (VMAL), noswap,
 *              isbusy = &vmIsBusyAliasRec, palVMAliases)
 *      If (error), InternalError
 *      return
 */
void    vmInitAliasRec()
{
    if ((BMPInit(
        (PGGlobalFlags & PG_SYS_CONSTRAINED) ? VMAL_MAXRECS/2 : VMAL_MAXRECS,
        sizeof(VMAL),
        (PGGlobalFlags & PG_SYS_CONSTRAINED) ?
                     VMBMP_DONATEMEM | PG_RESIDENT : PG_RESIDENT,
        VMALOWNER,
        vmIsBusyAliasRec, &palVMAliases)) != NO_ERROR)
        panic("VMAlias:Could not create alias records memory");

    /* Initialize palvmIal to palVMAliases- sizeof(VMAL) */
    palvmIal = palVMAliases - 1;

    return;
}


/**************************************************************************
 *                                                                        *
 *  WARNING: Everything below this line will be in swappable code!!!!     *
 *                                                                        *
 **************************************************************************/

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


/***EP  VMSelAlias - Export address of Selector Manager local alias record.
 *
 *      VMSelAlias returns the address of first alias record of the given
 *      type to Selector Manager, returning error if alias record of the
 *      given type is not found. More than one type of alias can be
 *      specified.
 *      WARNING: Object semaphore must be obtained when calling this function.
 *      We are walking the arena and alias records link lists in swappable
 *      code. Only way to ensure that these won't change while we block is
 *      to get the object semaphore.
 *
 *      ENTRY   flags   -  type of alias to search for
 *                          VMMA_CSALIAS or VMMA_MEMMAP
 *              hob     - handle to memory object
 *              ppal    - Pointer to location to write address of alias record
 *      RETURN  int     - error code (NO_ERROR if no error)
 *
 *      VMSelAlias (ulong_t flags, VMHOB hob, void **ppal)
 *
 *      PseudoCode:
 *
 *ifdef VMSTRICT
 *      vmAssert(vmHandleMap(hob)->ob_fs & OB_LALIAS)
 *endif
 *      For every arena record in the object's  linked list
 *          If (alias)
 *              Check the alias record's flags
 *              If  desired type, return
 *          Endif
 *      return (ERROR_NOT_FOUND)
 */
int         VMSelAlias(fl, hob, ppal)
ulong_t     fl;                 /* Alias type flags */
VMHOB       hob;                /* object handle */
VMAL        **ppal;             /* pointer to write address of alias record */
{
    VMOB    *pob = vmHandleMap(hob);
    register VMHAR   har;
    register VMAR    *par;

    vmSemAssertOb(pob);
    vmAssert(pob->ob_fs & OB_LALIAS);
    har = pob->ob_har;

#ifdef INCDEBUG
    vmAssert ((SAL_CSDSVALID & (AL_CSALIAS | AL_MEMMAP | AL_DBGALIAS
        | AL_DEVHLP)) == 0);
#else
    vmAssert ((SAL_CSDSVALID & (AL_CSALIAS | AL_MEMMAP
        | AL_DEVHLP)) == 0);
#endif
    while (har != HARNULL) {
        par = vmArMap(har);
        if (vmAliasAr(par)) {               /* If an alias AR */
            if ((*ppal=vmHalToPal(par->ar_hal))->al_f & fl)
                return(NO_ERROR);
        };
        har = par->ar_harlink;
    };
    *ppal = (VMAL *) VM_NO_ADDR;            /* NO address returned */
    return(ERROR_INVALID_PARAMETER);
}

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

/***LP  vmAliasToAlias - Called by VMMapAlias and VMMapDebugAlias when
 *          an alias is being aliased.
 *
 *      Given object information of the alias being aliased, vmAliasToAlias
 *      converts the object information and the address to be aliased to
 *      the corresponding main object and address. Object semaphore must
 *      be obtained prior to calling this function.
 *
 *      ENTRY   poi     - Pointer to object information (Initially contains
 *                          information of the alias that is being aliased,
 *                          converted to nonalias information later.)
 *              pdisp   - Pointer to disp. from the beginning of the object
 *                          (initially displacement with respect to alias
 *                          being aliased, converted to displacement from
 *                          beginning of the object later)
 *              pladdr  - Address being aliased(initially the address of the
 *                          alias being aliased, converted to main object's
 *                          address to be aliased)
 *      EXIT    NONE
 *
 *      void  vmAliasToAlias(poi, pdisp, pladdr)
 *
 *      PseudoCode
 *
 *      Find alias record
 *      Find nonalias AR that the alias is created to
 *      if (not selmgr alias)
 *          add alias offset to disp
 *      endif
 *      Set laddr = (address of nonalias AR) + disp
 *      Call VMObjectInfo(laddr, nonalias context, poi)
 *      if (error), InternalError
 *      return
 */
// void vmAliasToAlias(poi, pdisp, pladdr)
// VMOI        *poi;       /* Pointer to object information */

void vmAliasToAlias(pod, pdisp, pladdr)
VMOD        *pod;       /* Pointer to object descrptor */
ulong_t     *pdisp;     /* Displacement of the alias */
ulong_t     *pladdr;    /* Address of the region to be aliased */
{
    int     rc;
    register VMAL *pal;
    VMHOB   hobptda;
    VMAR    *par, *par2;
    VMCO    *pco;

    /* Make sure we own the semaphore */
//  vmSemAssertOb(vmHandleMap(poi->oi_hob));
    vmSemAssertOb(pod->od_pob);

    /* Make sure AR is an alias */
//  vmAssert(vmAliasAr(vmArMap(poi->oi_har)));
    vmAssert(vmAliasAr(pod->od_par));

//  pal = vmHalToPal((vmArMap(poi->oi_har))->ar_hal);

    pal = vmHalToPal((pod->od_par)->ar_hal);
    if (!vmIsSELAlias(pal))
    {
        /* Correct displacement */
        *pdisp += pal->al_pgoff << PAGESHIFT;
    };
//  rc = vmFindArCo(vmFAC_NOALIAS | vmFAC_NOIPG,
//                  hobptda = ((pal->al_f & AL_CSALIAS) ? poi->oi_hobptda : pal->al_hobptda),
//                  NULL, vmHandleMap(poi->oi_hob), SSToDS(&par), SSToDS(&par2),
//                  SSToDS(&pco));

    rc = vmFindArCo(vmFAC_NOALIAS | vmFAC_NOIPG,
                    hobptda = ((pal->al_f & AL_CSALIAS) ? VMHobPTDAOd(*pod) :
                                                          pal->al_hobptda),
                    NULL, pod->od_pob, SSToDS(&par), SSToDS(&par2),
                    SSToDS(&pco));
    vmAssert(rc == NO_ERROR);
    *pladdr = (par->ar_ipg << PAGESHIFT) + *pdisp;
//  rc = VMObjectInfo(*pladdr, hobptda, poi);
    pod->od_laddr = *pladdr;
    pod->od_pPTDA = VMGetPTDAAddr(hobptda);
    rc = VMGetOd(NA, pod);
    vmAssert(rc == NO_ERROR);
}

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

/***EP  VMMapAlias - Map an alias to memory region
 *
 *      VMMapAlias maps an alias to memory region.
 *      It is caller's responsibility to ensure that aliases marked
 *      as read only are never passed to user code that can write
 *      through it in ring 2.
 *      WARNING: This procedure is in swappable code.
 *
 *      ENTRY   flalloc -  Allocation flags
 *                  Acceptable flags are: VMAC_ARENASYS|VMAC_ARENAPRV
 *                  PG_W, PG_R, PG_X, PG_U, VMAC_SELALLOC
 *                  VMAC_LOCANY|VMAC_LOCSPECIFIC|VMAC_LOCABOVE, VMAC_VDM
 *                  Also:
 *              flselmgr- SELAlloc flags (needed only if VMAC_SELALLOC)
 *              fl      - Alias flags type (cs, MemMap, debug or 0)
 *                          VMMA_MEMMAP is old 16 bit MemMapAlias alias
 *                          VMMA_CSALIAS is a cs alias
 *                          VMMA_DBGALIAS is a debug alias
 *                          VMMA_DEVHLP is a DevHlp alias
 *                          vmMA_PRIV used by VMMapDebugAlias only
 *                          PG_PRIV used by VMMapDebugAlias only
 *              laddral - Linear address of the alias. (page boundary)
 *              hptdaal - Context of the alias (0 for current context)
 *              laddr   - linear address of region to be aliased (page boundary)
 *              hptda   - Context of the source region (0 for current context,
 *                              not needed if laddr is global address)
 *              cb      - size of alias map
 *              pac     - pointer to location of VMMapAlias return buffer.
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      VMMapAlias (ulong_t flal, ulong_t flsel, ulong_t fl, ulong_t laddral,
 *          VMHOB hptdaal, ulong_t laddr, VMHOB hptda, ulong_t cb, VMAC *pac)
 *
 *      PseudoCode:
 *
 *ifdef VMSTRICT
 *      If (laddr & PAGEMASK), InternalError
 *      If (not(SELMAP) && (size & PAGEMASK)), InternalError
 *endif
 *      if (not VDM or not VMAC_ARENASYS)
 *         Turn on SELMAP flag  ; BUGBUG: For v2.0 we always tile selectors
 *      Call VMGetOd(laddr, hptda) ; get object information
 *      If (laddr + cb > object laddr+object size)
 *          Call VMCLearSem
 *          return (ERROR_CROSSES_OBJECT_BOUNDARY);
 *      Endif
 *#ifdef VMSTRICT  ;  verify integrity of flags
 *      if ((VMAC_ARENASHR & VMAC_ARENASYS) || (VMAC_ARENAPRV & VMAC_ARENASHR))
 *          InternalError
 *      endif
 *#endif
 *      Call BMPGet         ; get alias record
 *      If (error), goto Exit
 *      Call VMReserve
 *      if (error), goto Err2Exit
 *      Call    PGAttach
 *      If (error), goto Err3Exit
 *      If (selector map requested)
 *          Call SELAlloc
 *          if (error) goto Err4Exit
 *      Endif
 *      Turn on OB_LALIAS flag in object record flags
 *      Set ar_hob, ar_f, ar_hal, and ar_harlink fields in Arena Record
 *      Set up alias record
 *      Goto Exit with NO_ERROR
 *Err4Exit:
 *      Call PGFree         ; free attached pages
 *Err3Exit:
 *      Call VMVirtFree     ; free reserved linear address range
 *Err2Exit:
 *      Call BMPFree        ; free alias record
 *Exit:
 *      Call VMClearSem
 *      return (return code)
 */

int     VMMapAlias(flalloc, flsel, flmap, laddral, hptdaal, laddr,
            hptda, cb, pac)
ulong_t     flalloc;                /* alias allocation flags */
ulong_t     flsel;                  /* SELAlloc flags (only if VMAC_SELALLOC) */
ulong_t     flmap;                  /* alias type (cs, debug, memmap, devhlp)*/
ulong_t     laddral;                /* address of alias laddr */
VMHOB       hptdaal;                /* context to own alias */
ulong_t     laddr;                  /* address of region to be aliased */
VMHOB       hptda;                  /* context alias is being created from */
ulong_t     cb;                     /* size in bytes */
VMAC        *pac;                   /* pointer to VMMapAlias return buffer */
{
    int     rc, rc2;                /* return code */
    ulong_t cpg = (cb + PAGEMASK) >> PAGESHIFT;
//  VMOI    oi;                     /* Object information buffer */
    VMOD    od;                     /* Object descriptor */
    void    *p;
    VMAR    *par2;                  /* Pointer to arena record being aliased */
    VMAL    psal;                   /* Saved alias record              113450*/
    VMAR    psar;                   /* Saved arena record              113450*/
    VMOB    psob;                   /* Saved object record             113450*/
    register VMAL    *pal;          /* Pointer to local alias record */
    register VMAR    *par;          /* Pointer to alias arena record */
    void    *pptdaal;               /* Pointer to ptda that owns the alias */
    SEL     sel = 0;                /* Alias selector (if requested) */
    register VMOB    *pob;          /* Pointer to object record */
    ulong_t disp;                   /* displacement of alias from base of obj */
    ulong_t fl = 0;
    ulong_t cpgReserve;

#ifdef VMSTRICT
    vmAssert((laddr & PAGEMASK) == 0);

    /* DevHelps and SELMAP aliases may request byte granular size */
    if (!((flmap & VMMA_DEVHLP) || (flalloc & VMAC_SELALLOC)))
    {
        vmAssert((cb & PAGEMASK) == 0);
    }
    if (flmap & vmMA_PRIV)
    {
        vmAssert(flmap & VMMA_DBGALIAS);
    }
#endif

#ifdef INCDEBUG
    vmAssert((PG_PRIV & (VMMA_MEMMAP | VMMA_DEVHLP | VMMA_DBGALIAS |
        VMMA_CSALIAS | vmMA_PRIV)) == NULL);
#else
    vmAssert((PG_PRIV & (VMMA_MEMMAP | VMMA_DEVHLP |
        VMMA_CSALIAS | vmMA_PRIV)) == NULL);
#endif

    /* BUGBUG: For v2.0, we always tile task  area memory */
    if ((flalloc & VMAC_ARENAPRV) && !(flalloc & VMAC_VDM))
    {
        flalloc |= VMAC_SELALLOC;
    }
    vmAssert (VMAC_ARENAPRV);

//  if ((rc = VMGetMemInfo(VMGS_TAKESEM | VMGS_VERIFY, laddr, hptda,
//      SSToDS(&oi), VMMI_CHECKUVIRT)) != NO_ERROR)
    od.od_laddr = laddr;
    od.od_pPTDA = VMGetPTDAAddr(hptda);
    if((rc = VMGetOd(VMGS_TAKESEM | VMGS_VERIFY | VMOD_CHECK_UVIRT,
                     SSToDS(&od))) != NO_ERROR)
    {
        return(rc);
    }

    /* Make sure alias doesn't cross object boundary */
    rc = ERROR_CROSSES_OBJECT_BOUNDARY;
//  if (laddr + cb <= oi.oi_va + oi.oi_cb)
    if(laddr + cb <= od.od_laddr + ((od.od_par)->ar_cpg << PAGESHIFT))
    {
        vmAssert (((VMAC_ARENASHR & VMAC_ARENASYS) ||
            (VMAC_ARENASHR & VMAC_ARENAPRV)) == 0);

//      disp = laddr - oi.oi_va;        /* Displacement of the alias */
//      par2 = vmArMap(oi.oi_har);
        disp = laddr - od.od_laddr;     /* Displacement of the alias */
        par2 = od.od_par;
        if (vmAliasAr(par2))
        {
            fl = par2->ar_f;             /* Save permission flags for later */

            /* An alias is being aliased, convert oi parms to nonalias parms */
//          vmAliasToAlias(SSToDS(&oi), SSToDS(&disp), SSToDS(&laddr));
            vmAliasToAlias(SSToDS(&od), SSToDS(&disp), SSToDS(&laddr));
        };

        if ((rc = BMPGet(palVMAliases, SSToDS(&p))) == NO_ERROR)
        {
            pal = (VMAL *) p;           /* Pass to register variable */

            /* All SEL aliases and nonVDM PRVARENA aliases must be
             * rounded up to nearest 64Kb in reserve size. If it is a
             * base selector map all type of alias, the reserved size
             * must map to the end of object's total reserved size.
             */
            if (flsel & SELAL_BASEALL)
            {
//              cpgReserve = (vmSelCeil(oi.oi_va - laddr + oi.oi_cb)) >>
//                  PAGESHIFT;
                cpgReserve = (vmSelCeil(od.od_laddr - laddr +
                             ((od.od_par)->ar_cpg << PAGESHIFT))) >> PAGESHIFT;
            }
            else
            {
                cpgReserve = ((vmPrvArenaReq(flalloc) && !vmVDMReq(flalloc)) ||
                  (flmap & VMMA_MEMMAP)) ? vmSelCeil(cb) >> PAGESHIFT : cpg;
            }

            if ((rc = VMReserve(cpgReserve, flalloc,
                                    (pptdaal = VMGetPTDAAddr(hptdaal)),
                                    laddral >> PAGESHIFT, 0,
                                    SSToDS(&p))) == NO_ERROR)
            {
                par = (VMAR *) p;           /* Pass to register variable */
                pob = od.od_pob;                                                      /*113450*/
                /* Save arena, object, and alias in case PGAttach fails */            /*113450*/
                memcpy(SSToDS(&psal), pal, sizeof(struct vmal_s));                    /*113450*/
                memcpy(SSToDS(&psar), par, sizeof(struct vmar_s));                    /*113450*/
                memcpy(SSToDS(&psob), pob, sizeof(struct vmob_s));                    /*113450*/
                par->ar_hob = vmPobToHob(od.od_pob);                                  /*113450*/
                par->ar_hal = vmPalToHal(pal);                                        /*113450*/
                pal->al_har = vmParToHar(par);                                        /*113450*/
                pal->al_hobptda = VMHobPTDAOd(od);                                    /*113450*/
                pal->al_pgoff = disp >> PAGESHIFT;                                    /*113450*/
                vmLinkAr(par, pob);                                                   /*113450*/
                if ((cb == 0) ||
//                  (rc = PGAttach(par->ar_ipg, pptdaal, laddr >> PAGESHIFT,
//                                 oi.oi_pPTDA, cpg, (flalloc & PG_PERM) |
//                                 (flmap & PG_PRIV))) == NO_ERROR)
                    (rc = PGAttach(par->ar_ipg, pptdaal, laddr >> PAGESHIFT,
                                   od.od_pPTDA, cpg, (flalloc & PG_PERM) |
                                   (flmap & PG_PRIV))) == NO_ERROR)
                {
//                  pob = vmHandleMap(oi.oi_hob);
//113450            pob = od.od_pob;
                    if (!(flalloc & VMAC_SELALLOC) ||
                        ((rc = SELAlloc(pob, par, cb,
                                        (flalloc & PG_PERM) ? flalloc :
                                        flalloc | PG_R | PG_W,
                                        flsel, pptdaal,
                                        SSToDS(&sel))) == NO_ERROR))
                    {
                        /* Nothing could fail from here on */
                        vmAssert(VMMA_CSALIAS & AL_CSALIAS);
                        vmAssert(VMMA_MEMMAP & AL_MEMMAP);

#ifdef INCDEBUG
                        vmAssert(VMMA_DBGALIAS & AL_DBGALIAS);
#endif
                        vmAssert(VMMA_DEVHLP & AL_DEVHLP);
                        vmAssert (vmMA_PRIV == AL_PRIV);

                        /* Set up and link the arena and alias records */
                        if ((flalloc & PG_PERM) == 0 && fl == 0)
                        {
                            /*
                             * Use existing permission flags.  Get the current
                             * flags from the object record for shared arena
                             * private content, the context record for shared
                             * arena shared content, or the arena record for
                             * all others.
                             */
//                          if (VMShrArena(oi.oi_va))
                            if (VMShrArena(od.od_laddr))
                            {
//                              if (VMPrvOi(oi))
                                if (VMPrvOd(od))
                                {
//                                  fl = (oi.oi_fsob & OB_PERMMASK) >>
//                                       OB_PERMSHFT;
                                    fl = ((od.od_pob)->ob_fs & OB_PERMMASK) >>
                                         OB_PERMSHFT;
                                }
                                else
                                {
//                                  fl = (vmCoMap(oi.oi_hco)->co_fb &
//                                       CO_PERMMASK) << CO_PERMSHFT;
                                    fl = ((od.od_pco)->co_fb & CO_PERMMASK) <<
                                         CO_PERMSHFT;
                                }
                            }
                            else
                            {
//                              fl = (oi.oi_fsar & AR_PERMISSION) >>
//                                   AR_PERMSHFT;
                                fl = ((od.od_par)->ar_f & AR_PERMISSION) >>
                                     AR_PERMSHFT;
                            }
                            par->ar_f = (par->ar_f & ~AR_PERMISSION) |
                                        (fl << AR_PERMSHFT);
                        }
//                      par->ar_hob = oi.oi_hob;
//113450                par->ar_hob = vmPobToHob(od.od_pob);
//113450                par->ar_hal = vmPalToHal(pal);
//113450                pal->al_har = vmParToHar(par);
//                      pal->al_hobptda = oi.oi_hobptda;
//113450                pal->al_hobptda = VMHobPTDAOd(od);
//113450                pal->al_pgoff = disp >> PAGESHIFT;
                        pal->al_f = AL_ISBUSY | (ushort_t) flmap;

                        /* If context is already privatized previously, we have to set
                         * privatized flag in the alias.
                         */
//                      if ((oi.oi_fsob & OB_SHARED) && !(flmap & vmMA_PRIV) &&
//                        (flmap & VMMA_DBGALIAS))

#ifdef INCDEBUG
                        if(((od.od_pob)->ob_fs & OB_SHARED) &&
                           !(flmap & vmMA_PRIV) && (flmap & VMMA_DBGALIAS))
#else
                        if(((od.od_pob)->ob_fs & OB_SHARED) &&
                           !(flmap & vmMA_PRIV) )
#endif
                        {
//                          if (((oi.oi_fsar & AR_HCO) && vmPrivCo(vmCoMap(oi.oi_hco)))
//                            || vmPrivAr(par2))
                            if((((od.od_par)->ar_f & AR_HCO) &&
                                vmPrivCo(od.od_pco)) ||
                                vmPrivAr(par2))
                            {
                                pal->al_f |= AL_PRIV;
                            }
                        };

                        /* Do arena record linking in resident code */

//113450                vmLinkAr(par, pob);

                        pac->ac_sel = sel;
                        pac->ac_va = par->ar_ipg << PAGESHIFT;
//                      pac->ac_hob = oi.oi_hob;
//                      VMClearSem(oi.oi_hob);
                        pac->ac_hob = vmPobToHob(od.od_pob);
                        VMClearSem(vmPobToHob(od.od_pob));
                        return(NO_ERROR);

                    }; /* end SELAlloc block */

    /* The rest of this code is executed only if something fails */

                    /* We have to undo PGAttach here */
                    rc2 = PGFree(par->ar_ipg, pptdaal, cpg, PG_SKIPFREE);
                    vmAssert(rc2 == NO_ERROR);

                };  /* end PGAttach block */

                /* Undo arena, object, and alias updates */                           /*113450*/
                memcpy(pal, SSToDS(&psal), sizeof(struct vmal_s));                    /*113450*/
                memcpy(par, SSToDS(&psar), sizeof(struct vmar_s));                    /*113450*/
                memcpy(pob, SSToDS(&psob), sizeof(struct vmob_s));                    /*113450*/
                /* We have to undo VMReserve here */
                VMVirtFree(par, vmGetArenaHeader(par->ar_ipg,
                                             (struct ptda_s *)pptdaal));
            };  /* end VMReserve block */

            /* We have to undo BMPGet here */
            BMPFree(palVMAliases, pal);

        };   /* end BMPGet block */

    };  /* end alias crossing object boundary */

//  VMClearSem(oi.oi_hob);
    VMClearSem(vmPobToHob(od.od_pob));
    return(rc);
}

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

/***LP  vmFreeObjectAliases - Free all aliases to a given object created
 *          from a certain context.
 *
 *      vmFreeObjectAliases frees all aliases to a given object created
 *      from the given context.
 *
 *      Does not free cs aliases. Object sempahore must be taken when calling
 *      this procedure.
 *      It is an Internal Error to find debug or MEMMAP aliases.
 *
 *      ENTRY   hob     - Handle to object record
 *              hobptda - Context the aliases to be freed should map to.
 *      RETURN  NONE
 *
 *      vmFreeObjectAliases(VMHOB hob, VMHOB hobptda)
 *
 *      PseudoCode:
 *
 *      For every Arena Record in link list
 *          If AR is an alias AR
 *              Find alias record
 *              if (not cs alias && al_hobptda == hobptda)
 *                  if (debug or MEMMAP alias) InternalError
 *                  Call VMFreeMem(ipg << PAGESHIFT, hobptda)
 *                  If (error), InternalError
 *              Endif
 *          Endif
 *      return
 */
void    vmFreeObjectAliases(hob, hobptda)
VMHOB   hob;                /* handle to object record */
VMHOB   hobptda;            /* Handle to context */
{
    VMOB    *pob = VMHandleMap(hob);    /* Pointer to object record */
    register VMAL *pal;     /* Pointer to alias alias record */
    register VMHAR har;     /* Handle of arena record */
    register VMAR  *par;    /* Pointer to arena record */
    int     rc;             /* Return code */

    vmSemAssertOb(pob);
    vmAssert(vmHasAliasOb(pob));
    har = pob->ob_har;
    while (har != HARNULL) {       /* While we still have arena records */
        par = vmArMap(har);
        har = par->ar_harlink;      /* Get next arena record */

        if (vmAliasAr(par)) { /* If it is an alias */
            pal = vmHalToPal(par->ar_hal);
            if (pal->al_hobptda == hobptda && !(pal->al_f & AL_CSALIAS)) {

#ifdef INCDEBUG
                if (pal->al_f & (AL_MEMMAP | AL_DBGALIAS))
#else
                if (pal->al_f & (AL_MEMMAP))
#endif
                    panic("vmFreeObjectAliases:Bad alias type");
                rc = VMFreeMem(par->ar_ipg << PAGESHIFT,
                    par->ar_hobptda, NULL);
                vmAssert(rc == NO_ERROR);
            };
        };
    }
    return;
}

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

/***LP  vmChangeAlias - Change mapping of local alias to the privatized
 *                          one if contexts match.
 *      vmChangeAlias walks the arena records linked to the object
 *      record. Every alias found belonging to the privatized context
 *      is marked privatized and remapped to new pages.
 *      WARNING: Object sempahore must be obtained when calling this function
 *
 *      ENTRY   flmap  - Alias mapping flags(vmMA_PRIV must be set, PG_PRIV)
 *              poi    - Object information
 *      RETURN  NONE   - MUST NOT FAIL
 *
 *      vmChangeAlias(flmap, poi)
 *
 *      PseudoCode:
 *
 *      For every alias arena record belonging to the old object
 *          Find corresponding alias record
 *          If (context == privatized one)
 *              Set AL_PRIV flag in the alias record
 *              If (PG_PRIV)
 *                  Call PGAttach(attach to new memory, make swappable)
 *              Endif
 *          Endif
 */
// void            vmChangeAlias(flmap, poi)
// ulong_t         flmap;          /* Alias mapping flags */
// register        VMOI *poi;      /* Pointer to object information */

void            vmChangeAlias(flmap, pod)
ulong_t         flmap;          /* Alias mapping flags */
register        VMOD *pod;      /* Pointer to object information */
{
    register VMAL *pal;
    register VMAR *par;
    struct  ptda_s *pptda;
    VMHAR   har;
    int     rc;

//  vmSemAssertOb(vmHandleMap(poi->oi_hob));
//  vmAssert((flmap & vmMA_PRIV) && (poi->oi_fsob & OB_SHARED));
//  har = (vmHandleMap(poi->oi_hob))->ob_har;

    vmSemAssertOb(pod->od_pob);
    vmAssert((flmap & vmMA_PRIV) && ((pod->od_pob)->ob_fs & OB_SHARED));
    har = (pod->od_pob)->ob_har;

    while (har != HARNULL)
    {
        par = vmArMap(har);
        if (vmAliasAr(par))
        {
            pal = vmHalToPal(par->ar_hal);
            vmAssert(!(pal->al_f & AL_CSALIAS)); /* Must not be cs alias */

//          if ((pal->al_hobptda == poi->oi_hobptda) &&

            if ((pal->al_hobptda == VMHobPTDAOd(*pod)) &&
                !(pal->al_f & AL_PRIV))
            {
                /* This alias needs to be privatized */

                pal->al_f |= AL_PRIV;

                if (flmap & PG_PRIV)
                {
                    /* NOTE: We don't need to call PGAttach if PG_PRIV flag is
                     * not passed to PGAttach, because PGAttach already
                     * iterates over all mappings via VMEachMap in this case.
                     */
                    pptda = VMSysArenaPg(par->ar_ipg) ? pPTDACur :
                                               VMGetPTDAAddr(par->ar_hobptda);
//                  rc = PGAttach(par->ar_ipg, pptda,
//                      (poi->oi_va >> PAGESHIFT) + pal->al_pgoff,
//                      poi->oi_pPTDA, par->ar_cpg, PG_REMAP |
//                      ((par->ar_f & AR_PERMISSION) >> VMAC_PSHIFT));

                    rc = PGAttach(par->ar_ipg, pptda,
                                  (pod->od_laddr >> PAGESHIFT) + pal->al_pgoff,
                                  pod->od_pPTDA, par->ar_cpg, PG_REMAP |
                                  ((par->ar_f & AR_PERMISSION) >> VMAC_PSHIFT));

                    vmAssert ((AR_READ >> VMAC_PSHIFT) == PG_R);
                    vmAssert ((AR_WRITE >> VMAC_PSHIFT) == PG_W);
                    vmAssert ((AR_EXEC >> VMAC_PSHIFT) == PG_X);
                    vmAssert ((AR_USER >> VMAC_PSHIFT) == PG_U);
                    vmAssert(rc == NO_ERROR);
                };  /* End if PG_PRIV flag */
            };  /* End if context matches block */
        };  /* End if alias AR block */
        har = par->ar_harlink;      /* check next AR */
    };      /* End while(har) block */
}


/***LP  vmHasDiscardablePages - return TRUE if any of the pages in the
 *                          given range is discardable
 *
 *      vmHasDiscardablePages returns TRUE if any of the pages in the
 *      given range is discardable.
 *      WARNING: This procedure is in swappable code, object semaphore must
 *      be obtained when calling this function.
 *
 *      ENTRY       ipg     - Start of the page range
 *                  pptda   - Pointer to ptda
 *                  cpg     - No. of pages
 *      RETURN      int     - TRUE or FALSE
 *
 *      PseudoCode
 *
 *      // Check the state of every page in the region, if any of them
 *      // is discardable, return TRUE, otherwise return FALSE
 *      For (; ipg < ipgmax ; ipg += returned pages)
 *          Call PGQueryState
 *          If (error from PGQueryState)
 *              break
 *          If (state == dicardable)
 *              return (TRUE)
 *          Set cpg -= returned pages
 *      return(FALSE)
 */

int     vmHasDiscardablePages(ipg, pptda, cpg)
ulong_t         ipg;
struct          ptda_s *pptda;
register        ulong_t cpg;
{
    ulong_t     fl;
    ulong_t     npages = cpg;

    for (; cpg > NULL ; ipg += npages, npages = cpg) {
        if (PGQueryState(ipg, pptda, SSToDS(&npages), SSToDS(&fl))
            != NO_ERROR)
            break;
        if ((fl & PQ_TYPEMASK) == PQ_DISCARDABLE)
            return(TRUE);
        cpg -= npages;
    };
    return(FALSE);
}


/***EP  VMMapDebugAlias - Map a local alias to memory region for ptrace.
 *
 *      VMMapDebugAlias creates a local alias in the current context to
 *      the passed memory region. This alias allows fast access
 *      to another process' memory for debug component.
 *      Both the address of the memory region and the size of the
 *      alias map has to start at a page boundary.
 *      System area aliases are allowed only for internal use by the
 *      DOSDEBUG component. They shouldn't be exported to debugger.
 *      If selector map is requested, it will be mapped as ring3 data in
 *      the process space, Ring 0 data in the system area.
 *
 *      NOTE This routine assumes that the caller owns the loader
 *      semaphore.
 *
 *      VMMapDebugAlias (ulong flags, ulong laddr, ulong size,
 *                VMHOB owner, vmac *pac)
 *
 *      ENTRY   flags - VMDA_RO (read only, read/write if not set)
 *                      VMDA_SELMAP (selector map requested)
 *                      VMDA_SYSTEM (put alias in system arena)
 *              laddr - linear address of the region to be aliased
 *              size  - size of alias mapping
 *              owner - Owner of the region to be aliased (source hptda)
 *              pac     - pointer to location of VMMapAlias return buffer.
 *      RETURN  int             - error code (NO_ERROR if no error)
 *
 *      PseudoCode:
 *
 *      If (laddr && PAGEMASK), return(ERROR_INVALID_PARAMETER)
 *      If (size && PAGEMASK), return(ERROR_INVALID_PARAMETER)
 *      If (not system area)
 *          Turn on SELMAP flag     ; BUGBUG: For v2.0 we always tile addresses
 *      Endif
 *      Call VMGetOd                    ; Get handle info, semaphore
 *      If (error), return
 *      If (an alias), call vmAliasToAlias to convert to nonalias object info.
 *      If (OB_SHARED && r/w alias requested && ReadOnly memobject &&
 *          any of the pages to be aliased are discardable)
 *          ; needs to be privatized
 *          set vmMA_PRIV flag for VMMapAlias
 *          Check for long term locks made from context to be privatized
 *          If (any exist)
 *              return ERROR_LONGLOCK
 *          Endif
 *          If (other references exist)
 *              set PG_PRIV flag for PGAttach
 *          Endif
 *      Endif
 *      Call VMMapAlias(w/r, private) ; Create Arena record and map pages
 *      If (error)
 *          Call VMClearSem on object handle
 *          return(error code)
 *      Endif
 *      If (vmMA_PRIV)
 *          Call DynTrace to purge all dynamic trace points in private mem.
 *          Call loader to decrement ref. count from its data
 *          ; All r/o aliases that may have existed belonging to current context
 *          ;   must be remapped to new memory object
 *          For every alias belonging to the old object handle
 *              If (context == privatized one)
 *                  Set AL_PRIV flag in the alias record
 *                  If (PG_PRIV)
 *                      Call PGAttach(attach to new memory, don't pass PG_PRIV)
 *                  Endif
 *              Endif
 *      Endif
 *      Call VMClearSem
 *      return
 */
#define     vmDA_fl     (PG_R | VMAC_LOCANY)
#define     vmDA_flsys  (VMAC_ARENASYS | VMAC_ALIGNPAGE)
#define     vmDA_flprv  (VMAC_ARENAPRV | PG_U | VMAC_ALIGNSEL)

int         VMMapDebugAlias(fl, laddr, cb, hptda, pac)
ulong_t     fl;                     /* flags */
ulong_t     laddr;                  /* address of source region */
ulong_t     cb;                     /* size to be aliased */
VMHOB       hptda;                  /* owner context of region to be aliased */
VMAC        *pac;                   /* pointer to VMMapAlias return buffer */
{

    int     rc;                     /* return code */
//  VMOI    oi;                     /* object information */
    VMOD    od;                     /* Object Descriptor */
    ulong_t flal;                   /* VMMapAlias flalloc flags */
    ulong_t flsel;                  /* VMMapAlias selmgr flags */
    ulong_t  flmap = VMMA_DBGALIAS; /* VMMapAlias alias flags */
    ulong_t disp;                   /* Needed by vmAliasToAlias */
    register VMOB *pob;             /* Pointer to object info */
//  register VMOI *poi = SSToDS(&oi);
    register VMOD *pod = SSToDS(&od);

    /* Make sure size and laddr are page aligned */
    if ((laddr & PAGEMASK) || (cb & PAGEMASK))
    {
        return(ERROR_INVALID_PARAMETER);
    }

    if (VMSysArena(laddr))
    {
        return(ERROR_ACCESS_DENIED);
    }

    if (!(fl & VMDA_SYSTEM))
    {
        flal = vmDA_fl | vmDA_flprv;        /* prv arena flags */
    }
    else
    {
        flal = vmDA_fl | vmDA_flsys;        /* system arena */
    }

    if (fl & VMDA_SELMAP)
    {
        flal |= VMAC_SELALLOC;
        flsel = SELAL_SELMAP | ((fl & VMDA_SYSTEM) ? NULL :
            (SEL_RPL3 << SEL_RPLDPL_SHIFT));
    }
    else
    {
        flsel = NULL;
    }

    if (!(fl & VMDA_RO))
    {
        flal |= PG_W;
        flsel   |= SELAL_W;
    };

//  if ((rc = VMGetMemInfo(VMGS_TAKESEM | VMGS_VERIFY | VMGS_SLOCKWAIT, laddr,
//      hptda, poi, VMMI_CHECKUVIRT)) != NO_ERROR)

//  od.od_laddr = laddr;                 //56848
//  if(hptda == HOBNULL)                 //56848
//     hptda = pPTDACur->ptda_handle;    //56848
//  od.od_pPTDA = VMGetPTDAAddr(hptda);  //56848

    pod->od_laddr = laddr;                // 56848
    pod->od_pPTDA = VMGetPTDAAddr(hptda); // 56848
    if((rc = VMGetOd(VMGS_TAKESEM | VMGS_VERIFY | VMGS_SLOCKWAIT |
                         VMOD_CHECK_UVIRT, pod)) != NO_ERROR)
    {
        return(rc);
    }

    /* Semaphore obtained, see if we are aliasing an alias */
//  if (vmAliasAr((vmArMap(poi->oi_har))))
    if (vmAliasAr(pod->od_par))
    {
        /* Convert object information to that of main object */
//      disp = laddr - poi->oi_va;
//      vmAliasToAlias(poi, SSToDS(&disp), SSToDS(&laddr));
        disp = laddr - pod->od_laddr;
        vmAliasToAlias(pod, SSToDS(&disp), SSToDS(&laddr));
    };
//  pob = VMHandleMap(poi->oi_hob);
    pob = pod->od_pob;
    /* Do we need privatization ?
     * We need privatization if we are creating a read/write alias to a
     * read only, shared and discardable page.
     */
//  if (!(fl & VMDA_RO) && (poi->oi_fsob & OB_SHARED) &&
//      !(poi->oi_fsar & AR_WRITE) &&
//      vmHasDiscardablePages(laddr >> PAGESHIFT, poi->oi_pPTDA,
//      cb >> PAGESHIFT))

    if(!(fl & VMDA_RO) && ((pod->od_pob)->ob_fs & OB_SHARED) &&
           !((pod->od_par)->ar_f & AR_WRITE) &&
            (vmIsLoadOb(pod->od_pob)))
    {
        /* We need privatization */
        flmap |= vmMA_PRIV;            /* set privatization flag for PGAttach */

        /* We waited for all short term locks to clear. If there are long
         * term locks placed on the object by this task, we can not
         * privatize. Return error in this case.
         */
//      if ((poi->oi_cllock >= 2) && ((rc = vmAccessLongLockInfo(poi->oi_har,
//          poi->oi_hobptda, vmlt_CHECK)) == ERROR_LONGLOCK)) {

        if(((pod->od_pob)->ob_cllock > 0) &&
           ((rc = vmAccessLongLockInfo(vmParToHar(pod->od_par),
                                           (pod->od_pPTDA)->ptda_handle,
                                           vmlt_CHECK)) == ERROR_LONGLOCK))
        {
//          VMClearSem(poi->oi_hob);
            VMClearSem(vmPobToHob(pod->od_pob));
            return(rc);
        }
//      /* Pass PG_PRIV flag only if other references exist */
//      if (VMSearchRef(VMSR_TWO, poi->oi_hob) == NO_ERROR)

        flmap |=PG_PRIV;
    };              /* end if privatization block */

    /* Create the alias */
//  rc = VMMapAlias(flal, flsel, flmap, NULL, HOBNULL, laddr, poi->oi_hobptda,
//     cb, pac);

    rc = VMMapAlias(flal, flsel, flmap, NULL, HOBNULL, laddr,
                        (pod->od_pPTDA)->ptda_handle, cb, pac);
    if (rc == NO_ERROR)
    {
        /* Alias succeeded, see if we did privatization */
        if (flmap & vmMA_PRIV)
        {
            /* If privatization occurred */

            /* Purge dynamic trace points from private memory */

#if    RAS
            if (fDYNActive && !VMApiOd(*pod))
            {
//              DYNPurgeRange(poi->oi_hobmte, laddr,
                DYNPurgeRange((pod->od_pob)->ob_hobmte, laddr,
                                  ((cb + PAGEMASK) & ~PAGEMASK),
                                  (char *) pac->ac_va);
            }
#endif

            /* If a loader resource object, or no other contexts exist,
             * we must call the loader to make sure that it won't attach
             * new contexts to privatized memory, provided we haven't
             * called it already due to previous privatization. We also
             * need to mark the context or arena record privatized.
             */

//          vmIsPrivLoadOb(flmap, poi);
            vmIsPrivLoadOb(flmap, pod);

            /* Now we have to find all aliases created to the same context
             * and remap them to the privatized object, setting AL_PRIV flag if
             * necessary */
//          if (poi->oi_fsob & OB_LALIAS) /* If it was aliased before */
            if ((pod->od_pob)->ob_fs & OB_LALIAS) /* If it was aliased before */
            {
//              vmChangeAlias(flmap, poi);
                vmChangeAlias(flmap, pod);
            }
            /* All done */
        };
    };
//  VMClearSem(poi->oi_hob);
    VMClearSem(vmPobToHob(pod->od_pob));
    return(rc);
}

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

/***LP  vmHasDebugAlias - return true if given range has debug aliases
 *
 *      vmHasDebugAlias returns true if there are any aliases mapping
 *      any part of the given range. It stops at first debug alias
 *      found. In order to find all debug aliasess it should be
 *      iteratively called until it returns false.
 *      WARNING: This procedure assumes that the handle semaphore is
 *      obtained. This procedure is in swappable code.
 *
 *      int     vmHasDebugAlias(VMOI *poi)
 *
 *      ENTRY   poi     - Object information (overwritten if a debug
 *                          alias is found)
 *      RETURN  int     - FALSE if no debug aliases exist
 *                        TRUE if debug alias exists
 *                          *poi filled with debug alias info (har, par, etc..)
 *      PseudoCode:
 *
 *      If the memory being freed has debug aliases mapped to it
 *          from the context being freed
 *          Obtain object information of the first one found
 *          return (TRUE)
 *      Endif
 *      return(FALSE)
 */
//int         vmHasDebugAlias(poi)
//register    VMOI    *poi;                   /* object information */

int         vmHasDebugAlias(pod)
register    VMOD    *pod;                   /* object information */
{
    register VMHAR har;
    register VMAR *par;
    int     rc;

//  vmSemAssertOb(vmHandleMap(poi->oi_hob));
//  vmAssert(VMHasAliasOi(*poi));
//  har = (vmHandleMap(poi->oi_hob))->ob_har;

    vmSemAssertOb(pod->od_pob);
    vmAssert(VMHasAliasOd(*pod));
    har = (pod->od_pob)->ob_har;

    while(har != HARNULL)
    {
        par = vmArMap(har);
        /* If AR is an alias && it is a debug alias && alias created from
         * the context being freed */
//      if (vmAliasAr(par) &&
//        vmCheckAlias(VMMA_DBGALIAS, poi->oi_hob, har) &&
//        (((VMAL *) (vmHalToPal(par->ar_hal)))->al_hobptda == poi->oi_hobptda))

        if (vmAliasAr(par) &&
            vmCheckAlias(VMMA_DBGALIAS, vmPobToHob(pod->od_pob), har) &&
            (((VMAL *) (vmHalToPal(par->ar_hal)))->al_hobptda ==
                 VMHobPTDAOd(*pod)))
        {
//          rc = VMObjectInfo(par->ar_ipg << PAGESHIFT, par->ar_hobptda, poi);
            pod->od_laddr = par->ar_ipg << PAGESHIFT;
            pod->od_pPTDA = VMGetPTDAAddr(par->ar_hobptda);
            rc = VMGetOd(NA, pod);
            vmAssert(rc == NO_ERROR);
            return(TRUE);
        }
        har = par->ar_harlink;
    }
    return(FALSE);
}

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

/***EP  VMGetAliasOffset - Return the offset of the given alias from the object
 *
 *      VMGetAliasOffset returns the offset of the given alias from the
 *      beginning of the object. The object semaphore must be taken
 *      during this call.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY       pod     -   Pointer to object desciptor structure
 *      RETURN      ulong_t -   Offset of the alias
 */
ulong_t  VMGetAliasOffset(pod)
register VMOD    *pod;
{

    VMAL    *pal;

    vmSemAssertOb(pod->od_pob);
    vmAssert(VMIsAliasOd(*pod));
    pal = vmHalToPal((pod->od_par)->ar_hal);

    return(vmIsSELAlias(pal) ? 0 : pal->al_pgoff << PAGESHIFT);
}
