#define SCCSID  "@(#)vminit.c   6.12 92/02/24"

/*
 *       IBM/Microsoft Confidential
 *
 *       Copyright (c) IBM Corporation 1987, 1989
 *       Copyright (c) Microsoft Corporation 1987, 1989
 *
 *       All Rights Reserved
 *
 *  09/18/91  Khoa Dang Huynh
 *       CP20 DCR 1486  Provide selector packing capability.
 */

/*
 *  BUGBUG IDB )1/17/90 - replace filler in VMBH structure
 */

#define bh_cBusyBlocks bh_filler

/*      Virtual Memory Manager Initialization Routines */

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

#define INCL_DOSP
#include <os2p.h>

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

#include <mi.h>
#include <sysinvar.h>
#include <seldesc.h>

#define FOR_EXEHDR 1

#include <exe386.h>
#include <dossymc.h>
#include <sigdef.h>
#include <except.h>
#include <pgexport.h>
#include <vmowner.h>
#include <vmexport.h>
#include <vmlocal.h>
#include <sellocal.h>
#include <tkexport.h>
#include <vmkh.h>            // must be after tkexport.h for KSEM definition
#include <infoseg.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <screen.h>
#include <sem.h>
#include <tkptda.h>
#include <selxport.h>
#include <ldrxport.h>
#include <stdlib.h>

/* GSR start */

// Moved to sdata.asm for System Anchor Block - f122427
extern VMAR    *parGlobalShrSearchStart;
extern ulong_t  vmGlobalShrUBDRY;
extern ulong_t  vmGlobalShrLBDRY;

VMAR    *parRWBasedSearchStart;
// lotus #define VM_GLOBALSHR_SIZE          _64MEG          /* Packed region size */
#define VM_GLOBALSHR_SIZE          _16MEG          /* Packed region size */
#define VM_GLOBALSHR_START         (VM_PACKED_START - VM_GLOBALSHR_SIZE)
/* GSR end */

extern ulong_t pgPhysPages;  // for determining size of the KRH

/* BUGBUG IDB 08/18/89 - The following equate should be defined in exe386.h */

#define OBJNOFLAT OBJIOPL

/*      Global variables - */

/* NOTE:  The shared {tiled, untiled} arena lower boundary always lies between
 *        aipgMinPub[i] and aipgMaxPrv[i] where i = 0 for tiled and 1 for
 *        untiled.  In a given context, the private {tiled or untiled} arena
 *        upper boundary (contained in the ipgmax field of its sentinel record)
 *        is always equal to the base of the "no man's land" area between
 *        the private {tiled or untiled} arena and the shared {tiled, untiled}
 *        arena (as contained in the ar_ipg field of the boundary sentinel)
 */


#define VMHOBOB 1               /* object record object's HOB */

#ifdef SMP
#ifdef MMIOPH
ulong_t pPSA = 0;
#endif
#endif

/* Flags used to communicate special init time info to worker routines */
// ulong_t vmInitFlags = 0;
// Moved to sdata.asm for System Anchor Block - f122427
extern ulong_t vmInitFlags;

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


/***EP  VMInit - Initialize the Virtual Memory Manager
 *
 *      This routine initializes the data structures used by the Virtual
 *      Memory Manager and creates VM data structures for the kernel objects.
 *
 *      ENTRY           pArenaInfo      - Pointer to the Arena Information
 *                                        array.  This array contains physical
 *                                        addresses and lengths for each of
 *                                        the kernel objects.
 *
 *      RETURN          void            - Nothing is returned.  Return to
 *                                        caller means success.  Any error
 *                                        causes a panic message.
 */

void VMInit(pArenaInfo)
struct arena_s          *pArenaInfo;    /* Arena info structure pointer */

{
  ulong_t               laddrFreeMax;   /* Upper bound of free region */
  ulong_t               laddrORT;       /* Base address of Obj Rec Table */
  ulong_t               laddrART;       /* Base address of Arena Rec Table */
  ulong_t               laddrKRH;       /* Base address of RW res heap */
  ulong_t               cbORT;          /* Unrounded ORT size */
  ulong_t               cbRoundORT;     /* Rounded ORT size */
  ulong_t               cbART;          /* Unrounded ART size */
  ulong_t               cbRoundART;     /* Rounded ART size */
  ulong_t               cbKRH;          /* Unrounded KRH size */
  ulong_t               cbRoundKRH;     /* Rounded KRH size */
  ulong_t               cbfb;
  ulong_t               cb;
  ulong_t               baseoflags;
  struct arena_s        *pai;           /* Arena info array pointer */
  struct arena_s        *paibase;       /* Arena info array base pointer */
  register VMAR         *par;           /* Arena record pointer */
  register VMAR         *parSen;        /* Sentinel Arena record pointer */
  VMAR                  *parART;        /* ART arena record pointer */
  VMAR                  *parORT;        /* ORT arena record pointer */
  VMAR                  *parKRH;        /* Kernel Res RW Heap par */
  VMOB                  *pobART;        /* ART object record pointer */
  VMOB                  *pobORT;        /* ORT object record pointer */
  VMOB                  *pobKRH;        /* Kernel Res RW Heap pob */
  VMOB                  *pob;           /* General object record pointer */
  VMBH                  *pbhART;        /* ART's BMP32 header pointer */
  VMBH                  *pbhORT;        /* ORT's BMP32 header pointer */
  VMAH                  *pah;           /* Arena header pointer */
  VMAT                  *pat;           /* Per-type arena info pointer */
  char                  *pb;            /* General byte pointer */
  int                   rc;
  ushort_t              baseowner;
  VMHKH                 hkh;            /* Heap handle */
  VMAC                  ac;             /* VMAllocMem return buffer */
  VMOD                  od;             /* Object data */

  /*
   *  (1) Check compile-time mask definitions for VM are OK.
   */

  vmAssert(!(vmfm_LMASK & VMFM_GMASK));

  /*
   *  (2) Find the virtual page that follows the end of the free area.  This
   *  is done by scanning the arena info array, finding the minimum virtual
   *  page among those specified in arena info entries.  Flag AF_LADDR in an
   *  arena info entry indicates whether or not the field a_laddr contains a
   *  valid virtual address.  A special arena info entry with the AF_VEND flag
   *  set indicates that there are no more arena info entries with valid
   *  virtual addresses specified.
   */

  pai = pArenaInfo;
  laddrFreeMax = MAXSYSLADDR;                   /* Start at upper boundary */
  while(!(pai->a_aflags & AF_VEND))             /* While end not reached */
    {
      if((pai->a_aflags & AF_LADDR) && (pai->a_laddr < laddrFreeMax))
                                                /* If valid lpage and lower */
        {
          laddrFreeMax = pai->a_laddr;          /* record new minimum */
        }
      pai++;                                    /* Point to next record */
    }

  /*
   *  (3) Calculate start virtual address, page and size of object record
   *  table.  The object record table will be managed by BMP32, so this
   *  start address is also the start of its BMP header.  The table is
   *  aligned to a page boundary so that we can commit a single page and
   *  know that the BMP header is aligned to the page start.  This in
   *  turn ensures that we can create a free list of sufficient size
   *  so that BMPGet calls made to obtain object records don't need to
   *  use VMAllocMem, which isn't available yet.
   */
  /*
   * perf enh - we don't need 64k worth of handles in a constrained system
   */
  if ( PGGlobalFlags & PG_SYS_CONSTRAINED ) {
      cbORT = sizeof(VMBH) + ((VM_MAX_HANDLES/2) * sizeof(VMOB));
  } else {
      cbORT = sizeof(VMBH) + (VM_MAX_HANDLES * sizeof(VMOB));
  }

  cbRoundORT = vmPageCeil(cbORT);
  laddrORT = laddrFreeMax - cbRoundORT;
  pbhORT = (VMBH *) laddrORT;
  pobvmOne = (VMOB *)(pbhORT + 1);
  laddrFreeMax = laddrORT;

  /*
   *  (4) Initialize pobVMZero for fast hob mapping algorithm.  By setting
   *  pobvmIob to  point to one object record's distance before the
   *  start of the object record table, the need to subtract 1 from a hob
   *  when mapping it to a pob is eliminated.
   */

  pobvmZero = pobvmOne - 1;

  /*
   *  (5) Commit first page of Object Record Table.
   */

  if((rc = PGAlloc(laddrORT >> PAGESHIFT,       /* Start linear page */
                   pPTDACur,                    /* Sysinit's PTDA */
                   1,                           /* Need first page only */
                   0L,                          /* Not a loader object */
                   VMHOBOB,                     /* hob of object records */
                   0,                           /* object-relative ipg */
                   (VMAC_PAFLAGS & vm_BMP_GROW) | PG_RESIDENT))
                                                /* Zfill, res, read/write */
    != NO_ERROR)
    {
      goto pgAllocPanic;
    }

  /*
   *  (6) Write BMP32 header to start of first page of Object Record Table.
   *  Create initial free list of object records on first page of Object
   *  Record Table.  Note that space must be deducted for the BMP32 header.
   */

  vmInitBMPObject(pbhORT,
                 HOBNULL,
                 sizeof(VMOB),
                 vm_BMP_GROW | PG_RESIDENT,
                 vmIsBusyObBMP,
                 (VMOB **) &pobvmOne,
                 cbORT,
                 PAGESIZE);

  /*
   *  (7) Allocate object record for the ORT itself from free list.  Note
   *  that BMPGet cannot yet be used (because the object record for the ORT
   *  does not yet exist and BMPGet needs to access that object record in
   *  order to take the ORT's semaphore).
   */

  pobORT = pbhORT->bh_pbFreeHead;
  pbhORT->bh_pbFreeHead = *((void **) pobORT);
  pbhORT->bh_hob = vmPobToHob(pobORT);
                                                /* Set handle to true value */
  vmAssert(pbhORT->bh_hob == VMHOBOB);
  pbhORT->bh_pbLastBusy = pobORT;
  pobORT->ob_hobowner = VMOBOWNER;      /* VM Object Record Tbl owner */
  pbhORT->bh_cBusyBlocks++;

  /*
   *  (8) Calculate start virtual address, page and size of arena record
   *  table.  The arena record table will reside immediately below
   *  the object record table in virtual address space.  The start of
   *  the arena record table will contain the BMP header.  Start the table
   *  on a page boundary so that we can commit a single page aligned to the
   *  start of the BMP header.
   */

  /*
   * perf enh - we don't need 64k worth of handles in a constrained system
   */
  if ( PGGlobalFlags & PG_SYS_CONSTRAINED ) {
      cbART = sizeof(VMBH) + ((VM_MAX_ARENA_RECORDS/2) * sizeof(VMAR));
  } else {
      cbART = sizeof(VMBH) + (VM_MAX_ARENA_RECORDS * sizeof(VMAR));
  }
  cbRoundART =  vmPageCeil(cbART);
  laddrART = laddrFreeMax - cbRoundART;
  laddrFreeMax = laddrART;
  pbhART = (VMBH *) laddrART;
  parvmOne = (VMAR *) (pbhART + 1);

  /*
   *  (9) Initialize parvmZero for fast har mapping algorithm.  By setting
   *  parvmIar to  point to one arena record's distance before the
   *  start of the arena record table, the need to subtract 1 from a har
   *  when mapping it to a par is eliminated.
   */

  parvmZero = parvmOne - 1;

  /*
   *  (10) Allocate object record for arena record table from free list.  Note
   *  that BMPGet can now be used since the object record table's record
   *  now exists and since we don't need access to the arena record.
   *  (We call BMPGet via vmObAlloc).
   */

  if((rc = vmObAlloc(SSToDS(&pobART))) != NO_ERROR)
    {
      goto arobcoAllocPanic;
    }
  pobART->ob_hobowner = VMAROWNER;

  /*
   *  (11) Commit first page of arena record table.
   */

  if((rc = PGAlloc(laddrART >> PAGESHIFT,       /* Start linear page */
                   pPTDACur,                    /* Sysinit's PTDA */
                   1,                           /* Need first page only */
                   0L,                          /* Not a loader object */
                   vmPobToHob(pobART),          /* ART's hob */
                   0,                           /* ob-relative ipg */
                   (VMAC_PAFLAGS & vm_BMP_GROW) | PG_RESIDENT))
    != NO_ERROR)
    {
      goto pgAllocPanic;
    }

  /*
   *  (12) Write BMP header to start of first page of arena record table.
   *  Create initial free list of arena records on first page of arena
   *  record table.  Note that space must be deducted for the BMP header.
   */

  vmInitBMPObject(pbhART,
                 vmPobToHob(pobART),
                 sizeof(VMAR),
                 vm_BMP_GROW | PG_RESIDENT,     /* Not swappable */
                 vmIsBusyArBMP,
                 (VMAR **) &parvmOne,
                 cbART,
                 PAGESIZE);

  /*
   *  (13) Allocate and init system arena record for the object record
   *  table.  Doubly link it to the object record for the object record
   *  table using handles.
   */

  if((rc = vmArAlloc(SSToDS(&parORT))) != NO_ERROR)
    {
      goto arobcoAllocPanic;
    }
  parORT->ar_ul1 = 0;
  parORT->ar_hob = vmPobToHob(pobORT);
  pobORT->ob_har = vmParToHar(parORT);
  parORT->ar_ipg = laddrORT >> PAGESHIFT;
  parORT->ar_cpg = cbRoundORT >> PAGESHIFT;
  parORT->ar_f = AR_INUSE + AR_TAGREG;
  parORT->ar_hal = HALNULL;

  /*
   *  (14) Allocate and init system arena record for the arena record
   *  table.  Doubly link it to the object record for the arena
   *  record table using handles.
   */

  if((rc = vmArAlloc(SSToDS(&parART))) != NO_ERROR)
    {
      goto arobcoAllocPanic;
    }
  parART->ar_ul1 = 0;
  parART->ar_hob = vmPobToHob(pobART);
  pobART->ob_har = vmParToHar(parART);
  parART->ar_ipg = laddrART >> PAGESHIFT;
  parART->ar_cpg = cbRoundART >> PAGESHIFT;
  parART->ar_f = AR_INUSE + AR_TAGREG;
  parART->ar_hal = HALNULL;

  /*
   *  (15) Create the Public Read/Write Kernel Resident Heap.  We need to
   *  use the heap to allocate blocks for object data location info.
   */

// perf - mem reduction : for retail and hstrict builds combine
//                        RES1MRO and RES1MRW and RESRO with RESRW
#ifdef VMSTRICT
  cbKRH = VM_MAX_RES_RW_HEAP_SIZE;
#else
  cbKRH = VM_MAX_RES_RW_HEAP_SIZE+VM_MAX_RES_RO_HEAP_SIZE+
          VM_MAX_RES_RW_HEAP_SIZE+VM_MAX_RES_RO_HEAP_SIZE;
#endif
  /*
   * perf enh - don't make the resident heap bigger than 1/2 available memory
   *            in a constrained system
   */
  if ( PGGlobalFlags & PG_SYS_CONSTRAINED ) {
     cbRoundKRH = vmPageFloor( (pgPhysPages << PAGESHIFT)/2);
  } else {
     cbRoundKRH = vmPageCeil(cbKRH);
  }

  laddrKRH = laddrFreeMax - cbRoundKRH;
  laddrFreeMax = laddrKRH;
  apkh[VM_HKH_PUB_RESRW].kh_pkrh = (VMKRH *) laddrKRH;

  /*
   *  (16) Allocate object and arena records for the heap and link them
   *  together.
   */

  if((rc = vmObAlloc(SSToDS(&pobKRH))) != NO_ERROR)
    {
      goto arobcoAllocPanic;
    }
  pobKRH->ob_hobowner = VMKRHRWOWNER;
  if((rc = vmArAlloc(SSToDS(&parKRH))) != NO_ERROR)
    {
      goto arobcoAllocPanic;
    }
  parKRH->ar_ul1 = 0;
  pobKRH->ob_har =  vmParToHar(parKRH);
  parKRH->ar_hob = vmPobToHob(pobKRH);
  parKRH->ar_ipg = laddrKRH >> PAGESHIFT;
  parKRH->ar_cpg = cbRoundKRH >> PAGESHIFT;
  parKRH->ar_f = AR_INUSE + AR_TAGREG;
  parKRH->ar_hal = HALNULL;

  /*
   *  (17) Commit storage for first and last pages of the heap.
   */

  if((rc = PGAlloc(laddrKRH >> PAGESHIFT,       /* Start laddr for heap*/
                   pPTDACur,                    /* Sysinit's PTDA */
                   1,                           /* Need first page only */
                   0L,                          /* Not a loader object */
                   vmPobToHob(pobKRH),          /* heap's hob */
                   0,                           /* ob-relative ipg */
                   (VMAC_PAFLAGS & vm_BMP_GROW) | PG_RESIDENT))
    != NO_ERROR)
    {
      goto pgAllocPanic;
    }

  if((rc = PGAlloc((laddrKRH + cbRoundKRH - PAGESIZE) >>
                       PAGESHIFT,       /* End page for heap*/
                   pPTDACur,                    /* Sysinit's PTDA */
                   1,                           /* Need first page only */
                   0L,                          /* Not a loader object */
                   vmPobToHob(pobKRH),          /* arena table's hob */
                   0,                           /* ob-relative ipg */
                   (VMAC_PAFLAGS & vm_BMP_GROW) | PG_RESIDENT))
    != NO_ERROR)
    {
      goto pgAllocPanic;
    }

  /*
   *  (18) Initialize the heap.
   */

  ac.ac_va = laddrKRH;
  ac.ac_hob = parKRH->ar_hob;
  vmladdrMinKH = ac.ac_va;
  vmladdrMaxKH = ac.ac_va + cbRoundKRH;
  if((rc = VMCreateKH(cbRoundKRH, PG_RESIDENT | PG_R | PG_W,
                      VMKRHRWOWNER, SSToDS(&hkh), SSToDS(&ac)))
    != NO_ERROR)
    {
      panic("VMInit: Heap creation fail - stage 3");
    }

  /*
   *  (19) Create an empty system arena.
   */

  if((rc = vmCreateArena(VMAT_SYS, &ahvmSys)) != NO_ERROR)
    {
      goto arInitPanic;
    }
  parSen = ahvmSys.ah_parSen;

  /*
   *  (20) Enter the system arena records created so far into the system arena
   *  by doubly linking them to the sentinel.  The arena records are linked in
   *  ascending order of the base linear addresses that they map, beginning
   *  with the sentinel.  The order is therefore as follows:
   *
   *  System Arena Sentinel Arena Record
   *  Public Read-Write Kernel Resident Heap Arena Record
   *  Arena Record Table (BMP32 Object) Arena Record
   *  Object Record Table (BMP32 Object) Arena Record
   */

  parSen->ar_harnext = vmParToHar(parKRH);
  parKRH->ar_harnext = vmParToHar(parART);
  parART->ar_harnext = vmParToHar(parORT);
  parORT->ar_harnext = vmParToHar(parSen);
  parSen->ar_harprev = vmParToHar(parORT);
  parORT->ar_harprev = vmParToHar(parART);
  parART->ar_harprev = vmParToHar(parKRH);
  parKRH->ar_harprev = vmParToHar(parSen);

  /*
   *  (21) Enter each object's location data.
   */

  par = ahvmSys.ah_parSen;
  par = vmArMap(par->ar_harnext);
  do
    {
      /*
       *  Record object in bitmap or hash table then skip to next
       *  arena record.
       */

      if((rc = vmRecordOd(&ahvmSys, par)) != NO_ERROR)
        {
          panic("VMInit: Error recording sysarena object");
        }
      par = vmArMap(par->ar_harnext);
    }
  while(vmRegAr(par));

#ifdef VM_HGS
  /*
   *  (21a) Create an empty high global shared arena
   */

  if((rc = vmCreateArena(VMAT_HGS, &ahvmHGS)) != NO_ERROR)
    {
      goto arInitPanic;
    }
#endif

  /*
   *  (22) Create the tiled shared arena and SysInit's private tiled
   *  arena.  Note that we do this here because the arena headers
   *  must be initialized before VMGetOd and VMAllocMem can be used
   *  even for the system arena.
   */

  if((rc = vmCreateArena(VMAT_SHR_TILED, &ahvmShr)) != NO_ERROR)
    {
      goto arInitPanic;
    }
  parSen = ahvmShr.ah_parSen;
  atvm[VMAT_PRIV_TILED].at_harParent = vmParToHar(parSen);
  atvm[VMAT_PRIV_VDM].at_harParent = vmParToHar(parSen);

  /*
   *  (23) Set up the initial arena bounds for the SysInit task's
   *  private arena so that the macros VMSysArena etc can be used.
   *  The private arena will be set up properly later on after exit
   *  from VMInit by a call to VMInitTask
   */

  pah = &(pPTDACur->ptda_ah);
  pat = &(atvm[VMAT_PRIV_TILED]);
  pah->ah_laddrMin = pat->at_laddrInitMin;
  pah->ah_laddrMax = pat->at_laddrInitMax;

  /*
   *  (24) At this point, now that the ORT, ART, public read-write resident heap
   *  arena header and object data location structures are initialized,
   *  VMAllocMem, BMPInit and BMPGet are available for use within the system
   *  arena.  We must however first use VMAllocMem to create object and arena
   *  records for each of the kernel data objects.  VMAllocMem detects that
   *  we are still in the initialization state and recoginizes that the
   *  istorage for the kernel objects is already allocated.  After these
   *  special calls to VMAllocMem are complete, all VM services are available
   *  for use within the system arena.
   */

  /*
   *  (25) Allocate pseudo mte handle for kernel mte, so we can store it in
   *  object records coming from kernel mte.
   */

  if((rc = VMCreatePseudoHandle(pDosModMte, LDRMTEOWNER,
                                     &DosModHdl)) != NO_ERROR)
    {
      panic("VMInit: can not create handle for DOSCALLS");
    }

  /*
   *  (26) Walk the arenainfo array.  Identify groups of arenainfo records
   *  that map contiguous regions of committed virtual memory.  Slice these
   *  up into subregions, beginning a new subregion whenever an arenainfo
   *  record base virtual address starts on a page boundary.  This ensures
   *  that the granularity of the objects is such that individual
   *  objects are created for anything that has to be freed via VMFreeMem
   *  later.
   */

  pai = pArenaInfo;                     /* Point at start of arena info */
  while(!(pai->a_aflags & AF_VEND))     /* While not at end of */
    {                                   /* arena info array */
      if(pai->a_aflags & AF_LADDR)      /* If virtual address valid */
        {
          paibase = pai;
          baseoflags = paibase->a_oflags;
          baseowner = paibase->a_owner;

          /*
           *  (26a) Scan a group of arenainfo records that:
           *  - have virtual addresses
           *  - map adjacent page-granular virtual address ranges
           *  - only the first record in the group maps to a page boundary.
           *  We will create a single VM object for the entire group.
           */

          while((!(pai->a_aflags & AF_VEND)) &&
                (pai->a_aflags & AF_LADDR) &&
                ((pai+1)->a_aflags & AF_LADDR) &&
                (pai->a_laddr + pai->a_size <= (pai+1)->a_laddr) &&
                (((pai+1)->a_laddr & PAGEMASK) > 0) &&
                (VMRegionBase(pai->a_laddr) +
                VMRegionSize(pai->a_laddr, pai->a_size)
                >= (pai+1)->a_laddr))
            {
              pai++;
            }

          ac.ac_va = paibase->a_laddr;

#ifdef SMP

          if ((paibase->a_laddr >> PAGESHIFT) == MINPSAPAGE) {

             /*
              *  (26b) Create a memory object which spans 4 megabytes for the
              *  PSA pages. This area is reserved so no one can use any other
              *  pte's in the page table in which the PSA pages pte's reside.
              *  These pages contain data on a per processor basis.
              */

             if (pai->a_owner != OS2KRNLOWNER)
                panic("VMInit: Laddr conflict");

             if (vmPageCeil(pai->a_laddr - paibase->a_laddr + pai->a_size) !=
                 PSASIZE)
                   panic("VMInit: PSA wrong size");

             if((rc = VMAllocMem(_4MEG,              /* Reserve size */
                                 0,                  /* Commit 0 bytes */
                                 VMAC_ARENASYS       /* lives in system arena */
                                 +VMAC_LOCSPECIFIC,  /* Specific location */
                                 HOBNULL,            /* Current PTDA */
                                 OS2KRNLOWNER,       /* Owner */
                                 DosModHdl,          /* mte handle */
                                 NA,                 /* No Selector Mgr flags */
                                 NA,                 /* No loader block no */
                                 SSToDS(&ac)))       /* Return values buffer */
               != NO_ERROR)
               {
                 panic("VMInit: Failure reserving PSA");
               }
#ifdef MMIOPH
               pPSA = ac.ac_va;
#endif
          }
          else {
#endif
          /*
           *  (26b) At this point, pai points to the last arena info record
           *  in the current group.  The size of the group is the
           *  difference of the virtual addresses in the first and last
           *  arena info entries + the size of the last entry.  Create
           *  a memory object for the whole group.
           */

          if((rc = VMAllocMem(pai->a_laddr - paibase->a_laddr +
                              pai->a_size,      /* Byte size of group */
                              0,                /* Commit 0 bytes */
                              VMAC_ARENASYS     /* lives in system arena */
                              +VMAC_LOCSPECIFIC, /* Specific location */
                              HOBNULL,          /* Current PTDA */
                              pai->a_owner,     /* Owner saved in the struct */
                              (pai->a_owner == OS2KRNLOWNER) ?
                                  DosModHdl : (VMHOB) HOBNULL,  /* mte handle */
                              NA,               /* No Selector Mgr flags */
                              NA,               /* No loader block no */
                              SSToDS(&ac)))     /* Return values buffer */
            != NO_ERROR)
            {
              panic("VMInit: Failure reserving OS/2 code and data");
            }
#ifdef SMP
          }
#endif

          pob = vmHandleMap(ac.ac_hob);
          vmAssert(pob->ob_har != HARNULL);     /* Must have arena record */
          par = vmArMap(pob->ob_har);           /* Map arena record */

          if(pai->a_oflags & OBJALIAS16)
            {                                   /* If selector mapping */
              par->ar_sel = paibase->a_sel;     /* Store sel in arena record */
              VMArSetTiled(par, AR_SELMAP);     /* Set AR_SELMAP flag */
            }

          /*
           *  (26c) Store hob in page manager data structures.
           */

          PGInitHob(ac.ac_va >> PAGESHIFT, par->ar_cpg, ac.ac_hob);
        }
      pai++;                                    /* Next arena info entry */
    }
  vmInitFlags |= VMS_COMMIT;     /* Future allocations must be committed */

  /*
   *  (27) Allocate the Context Record Table.  Initialize pcovmZero for fast
   *  hco mapping algorithm.  By setting pcovmZero to  point to one context
   *  record's distance before the start of the context record table (i.e
   *  one before context record number 1, the need to subtract 1 from a
   *  hco when mapping it to a pco is eliminated.
   */

  if((rc = BMPInit(VM_MAX_CONTEXT_RECORDS,      /* Max. context records */
                   sizeof(VMCO),                /* blocksize */
                   PG_RESIDENT,                 /* Resident BMP32 object */
                   VMCOOWNER,                   /* VM Context Record owner */
                   vmIsBusyCoBMP,               /* busy function */
                   &pcovmOne)) != NO_ERROR)     /* Pointer to context table
                                                    returned here */
    {
      panic("VMInit: Error creating CRT");
    }
  pcovmZero = pcovmOne - 1;

  /*
   *  (28) Initialize the remaining public resident and swappable heaps
   */

  vmInitPublicHeaps();

  /*
   *  (29) Donate free page fragments created by PGInit() to resident heap.
   *  All free page fragments are donated.  Note that we look at the physical
   *  size in the arenainfo record (defined by (pai+1)->a_paddr - pai->a_paddr)
   *  to identify fragments and not the linear size (pai->a_size).
   */

  for(pai = pArenaInfo; !(pai->a_aflags & AF_PEND); ++pai)
    {
      if(pai->a_aflags & AF_FREE)
        {
          /*
           *  This record defines a free region.
           */

          cbfb = (pai+1)->a_paddr - pai->a_paddr;       /* size of region */

          if(pai->a_paddr & PAGEMASK)
            {
              /*
               *  There is a partial free page at the front of the region.
               *  There must be a preceding record that maps the same frame
               *  and has a linear mapping.
               */

              vmAssert(pai > pArenaInfo &&
                       ((pai-1)->a_aflags & (AF_LADDR|AF_PADDR)));

              /*
               *  Get the size and address of the fragment we will donate.
               *  Account for the fact that it might not end at a page boundary.
               */

              cb = min(cbfb, PAGESIZE - (pai->a_paddr & PAGEMASK));
              cbfb -= cb;
              pb = (char *)(pai->a_paddr - (pai-1)->a_paddr + (pai-1)->a_laddr);

              VMDonateKHB(pb, cb, PG_W);
            }

          if(((pai+1)->a_paddr & PAGEMASK) && cbfb > 0)
            {
              /*
               *  There is a partial free page at the end of the region.
               *  The following record must map the same frame and have a
               *  linear mapping.
               */

              vmAssert((pai+1)->a_aflags & (AF_LADDR|AF_PADDR));

              /*
               *  Get the size and address of the fragment we will donate.
               */

              cb = (pai+1)->a_paddr & PAGEMASK;
              vmAssert(cb <= cbfb);
              pb = (char *)((pai+1)->a_laddr & ~PAGEMASK);

              VMDonateKHB(pb, cb, PG_W);
            }
        }
    }

  /*
   *  (30) Initialize named shared rmp records.
   */

  vmNameShareInit();

  /*
   *  (30a) donate HIGH2CODE and HIGH3CODE page fragments to the KRH
   */

  vmDonateHighCode();

  /*
   *  (31) Initialize discardable segments rmp records.
   */

  SELDiscSegInit();

  /*
   *  (32) Set user bit for SysInit's PTDA.  This is a temporary workaround
   *  for a B1 stepping error.
   */

  PGSetAccess((page_t) (((ulong_t) pPTDACur) >> PAGESHIFT),
               pPTDACur,
              (int) ((CBPTDA + PAGESIZE - 1) >> PAGESHIFT),
              (PG_W | PG_U));

  /*
   *  (33) Initialize alias records table.
   */

  vmInitAliasRec();

  /*
   *  (34) Verify that the local and global infoseg copies are in the shared
   *  tiled arena.  Code in VMInitTask relies on this for performance reasons.     *  The check is made here rather than in VMFreeTask so that it is only
   *  executed once.
   */

// GSRBUGBUG start
//  vmAssert((SEL_TASKINFOLADDR >= ahvmShr.ah_pat->at_laddrAbsMin) &&
//           (SEL_TASKINFOLADDR < ahvmShr.ah_pat->at_laddrAbsMax) &&
//           (SEL_SYSINFOLADDR >= ahvmShr.ah_pat->at_laddrAbsMin) &&
//           (SEL_SYSINFOLADDR < ahvmShr.ah_pat->at_laddrAbsMax));
// failed comparing hardcoded 1bfe0000 to 13ff0000

// lotus #ifdef SMP
// lotus   ac.ac_va = SEL_TASKINFOLADDR + _64K;
// lotus   rc = VMReserveMem(_4MEG - _64K,
// lotus                     VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL, HOBNULL,
// lotus                     0, SSToDS(&ac));
// lotus   vmAssert(rc == NO_ERROR && ac.ac_va == (SEL_TASKINFOLADDR + _64K));
// lotus #endif

  /*
   *  (35) Allocate linear space in the shared arena for the protected (also
   *  includes based) region and for the packed region. After processing
   *  config.sys these are'a may be freed. Freeing these regions would be
   *  done in routine vmInitProtect.
   */

  /**************************
  *  protected/based region *
  **************************/
  ac.ac_va = VM_PROTECTED_BASED_START;
  rc = VMReserveMem(1, VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL, HOBNULL,
                    0, SSToDS(&ac));
  vmAssert(rc == NO_ERROR && ac.ac_va == VM_PROTECTED_BASED_START);

  od.od_laddr = VM_PROTECTED_BASED_START;
  od.od_pPTDA = pPTDACur;
  rc = VMGetOd(NA, SSToDS(&od));
  vmAssert(rc == ERROR_NO_OBJECT);
  parProtectSearchStart = vmArMap((od.od_par)->ar_harnext);
  VMProtectedMem = TRUE;

  /*****************
  *  packed region *
  ******************/
  ac.ac_va = VM_PACKED_START;
  rc = VMReserveMem(1, VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL, HOBNULL,
                    0, SSToDS(&ac));
  vmAssert(rc == NO_ERROR && ac.ac_va == VM_PACKED_START);

  od.od_laddr = VM_PACKED_START;
  od.od_pPTDA = pPTDACur;
  rc = VMGetOd(NA, SSToDS(&od));
  vmAssert(rc == ERROR_NO_OBJECT);
  parPackedSearchStart = vmArMap((od.od_par)->ar_harnext);
  vmPackedUBDRY = parPackedSearchStart->ar_ipg << PAGESHIFT;
  vmPackedLBDRY = (od.od_par)->ar_ipg << PAGESHIFT;
  VMPackedMem = TRUE;

  SelShrPackedStart = LaToSelTiled(vmPackedLBDRY);
  SelShrPackedEnd   = LaToSelTiled(parPackedSearchStart->ar_ipg << PAGESHIFT);

/* GSR start */
  /************************
  *  global shared region *
  *************************/
  ac.ac_va = VM_GLOBALSHR_START;
  rc = VMReserveMem(1, VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL, HOBNULL,
                    0, SSToDS(&ac));
  vmAssert(rc == NO_ERROR && ac.ac_va == VM_GLOBALSHR_START);

  od.od_laddr = VM_GLOBALSHR_START;
  od.od_pPTDA = pPTDACur;
  rc = VMGetOd(NA, SSToDS(&od));
  vmAssert(rc == ERROR_NO_OBJECT);
  parGlobalShrSearchStart = vmArMap((od.od_par)->ar_harnext);
  vmGlobalShrUBDRY = parPackedSearchStart->ar_ipg << PAGESHIFT;
  vmGlobalShrLBDRY = (od.od_par)->ar_ipg << PAGESHIFT;

  /***************************
  *  shared region r/w based *
  ***************************/
// GEB_HACK
//  ac.ac_va = MINRWBASINGLADDR;
//  rc = VMReserveMem(1, VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL, HOBNULL,
//                    0, SSToDS(&ac));
//  vmAssert(rc == NO_ERROR && ac.ac_va == MINRWBASINGLADDR);
//
//  od.od_laddr = MINRWBASINGLADDR;
//  od.od_pPTDA = pPTDACur;
//  rc = VMGetOd(NA, SSToDS(&od));
//  vmAssert(rc == ERROR_NO_OBJECT);
//  parRWBasedSearchStart = vmArMap((od.od_par)->ar_harnext);
//  vmGlobalShrUBDRY = parPackedSearchStart->ar_ipg << PAGESHIFT;
//  vmGlobalShrLBDRY = (od.od_par)->ar_ipg << PAGESHIFT;
/* GSR end */

  /*
   *  (35) Reset the shared arena free block hint pointer to point to the
   *  PACKSHR arena record just allocated.  The hint pointer will always
   *  point to an arena record in the unprotected, untiled region.
   */

  ahvmShr.ah_parFree = od.od_par;
#ifdef SMP
  ac.ac_va = SEL_TASKINFOLADDR + _64K;
  rc = VMReserveMem(_4MEG - _64K,
                    VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL, HOBNULL,
                    0, SSToDS(&ac));
  vmAssert(rc == NO_ERROR && ac.ac_va == (SEL_TASKINFOLADDR + _64K));
#endif
#ifdef PMDEBUG
  _asm int 3;
#endif
  return;

arobcoAllocPanic:
      panic("VMInit: Error allocating ar/ob/co");
pgAllocPanic:
      panic("VMInit: pgAlloc error");
arInitPanic:
      panic("VMInit: Error creating arena");
}


/***LP  vmInitAlloc - Allocate an object from the system arena
 *
 *      This routine carves out the specified space for an object from the
 *      system arena, allocates an arena record and object record
 *      for the object, links them together and commits the specified number
 *      of pages for the object.
 *
 *      vmInitAlloc is called by VMInit only, to create certain objects
 *      that must exist before VMAllocMem can be used.  VMInitAlloc requires the
 *      object record table, arena record table to already exist.  Note that
 *      the arena record is not linked into the system arena; VMInit does
 *      this.
 *
 *      ENTRY   ipg                     - base page of object
 *              cpgReserve              - size of object in pages
 *              cpgCommit               - number of pages to be committed
 *              hobowner                - owner of object
 *              ppob                    - where to return addr of object rec.
 *              ppar                    - where to return addr of arena record
 */

int
vmInitAlloc(page_t ipg,
            page_t cpgReserve,
            page_t cpgCommit,
            VMHOB hobowner,
            VMOB **ppob,
            VMAR **ppar)
{
  register VMAR *par;
  register VMOB *pob;
  int rc;

  /*
   *  Create the object record
   */

  if((rc = vmObAlloc(ppob)) != NO_ERROR)
    return(rc);
  pob = *ppob;
  pob->ob_hobowner = hobowner;

  /*
   *  Create the system arena record and doubly link it to the object record.
   */

  if((rc = vmArAlloc(ppar)) != NO_ERROR)
    {
      return(rc);
    }
  par = *ppar;
  par->ar_ul1 = 0;
  par->ar_hob = vmPobToHob(pob);
  pob->ob_har = vmParToHar(par);

  /*
   *  Set initial page, page count and flags in arena record
   */

  par->ar_ipg = ipg;                    /* Set base page */
  par->ar_cpg = cpgReserve;             /* Set size in pages */
  par->ar_f = AR_INUSE + AR_TAGREG;     /* Regular ar and in use */
  par->ar_hal = HALNULL;                /* Clear alias field */

  /*
   *  Commit the specified number of pages to the start of the
   *  region described by the arena record.
   */

  if((rc = PGAlloc(ipg,                         /* Start vpage */
                   pPTDACur,                    /* Sysinit's PTDA */
                   cpgCommit,                   /* Number of pages */
                   0,                           /* Not a loader object */
                   par->ar_hob,
                   0,                           /* hob-relative ipg */
                   PG_ZEROFILL+PG_RESIDENT+PG_R+PG_W))
                                                /* Zfill, resident,
                                                 * read/write
                                                 */
    != NO_ERROR)
    return(rc);
  }


/***LP  vmInitBMPInit - Create BMP Object within VMInit
 *
 *      vmInitBMPInit is called by VMInit to create and initialize
 *      BMP Objects in the system arena before VMAllocMem can be used.
 *
 *      ENTRY   The arena record table and object record table must
 *              already exist, but the few arena records already in
 *              existence need not be linked together yet.
 *
 *              cblocks         - maximum number of blocks
 *              cbblock         - size of a block in bytes
 *              hobowner        - owner of BMP object
 *              pfnisbusy       - free block identifier function
 *              ppblock         - place to put pointer to first block
 *              ipgFree         - upper vpage boundary of BMP header
 *              cblocksfree     - Number of blocks on initial free list
 *              ppob            - Pointer to whare object record pointer
 *                                will be returned
 *              ppar            - Pointer to where arena record pointer
 *                                will be returned
 */

int
vmInitBMPInit(ulong_t cblocks,    /* Maximum number of blocks */
              ulong_t cbblock,    /* Size of a block in bytes */
              VMHOB hobowner,
              int (*pfnisbusy)(), /* Busy block identifier function */
              void **ppblock,     /* Place to return pointer */
              ulong_t *ipgFree,   /* Upper boundary vpage for BMP object */
              ulong_t cblocksfree,/* Initial # blocks on freelist */
              VMOB **ppob,        /* Pointer to returned object record */
              VMAR **ppar)        /* Pointer to returned system arena record */
{
  int           rc;
  ulong_t       ipg, cpgReserve, cpgCommit;
  ulong_t       cbobject;       /* max usable size of object in bytes */

  /*
   *  Calculate base page and size of object in pages.
   */

  cbobject = sizeof(VMBH) + (cblocks*cbblock);
                                /* Max usable object size = header + entries */
  ipg = *ipgFree - ((cbobject + PAGESIZE - 1) >> PAGESHIFT);
  cpgReserve = *ipgFree - ipg;
  cpgCommit = (sizeof(VMBH) + (cblocksfree*cbblock) + PAGESIZE - 1)
          >> PAGESHIFT;
  *ipgFree = ipg;               /* Update free upper boundary */

  /*
   *  Reserve virtual memory for the BMP object, create object record and
   *  arena record, link them together.  Commit sufficient physical
   *  pages so that a free list containing the specified minimum number
   *  of blocks can be created.
   */

  if((rc = vmInitAlloc(ipg,cpgReserve,cpgCommit,hobowner,ppob,ppar))
    != NO_ERROR)
    {
      return(rc);
    }

  /*
   *  Initialize the BMP header and free list.
   */

  vmInitBMPObject((VMBH *) (ipg << PAGESHIFT),
                  vmPobToHob(*ppob),
                  cbblock,
                  vm_BMP_GROW | PG_RESIDENT,
                  pfnisbusy,
                  ppblock,
                  cbobject,
                  cpgCommit << PAGESHIFT);
  return(NO_ERROR);
}


/***EP  VMExchangeSel - Move selector from one object to other
 *
 *      VMExchangeSel is called be SELReinit during initialization to
 *      mov GDT selector from one arena record to another
 *
 *      ENTRY   ipgold  - Address of the old object
 *              ipgnew  - Address of the new object
 *      RETURN  NONE
 *
 *      VMExchangeSel(ulong_t ipgold, ulong_t ipgnew)
 *
 *      PseduoCode
 *
 *      Map ipgold and ipgnew to their ARs
 *      vmAssert(ipgnew and ipgold are in system arena)
 *      vmAssert (parnew->ob_hobowner == SELGDTOWNER)
 *      Set parnew->ob_sel = parold->ob_sel
 *      set parnew->ob_f |= AR_SELMAP
 *      set parold->ob_sel = NULL
 *      set parold->ob_f &= ~AR_SELMAP
 *      return
 */

void    VMExchangeSel(ipgold, ipgnew)
ulong_t                 ipgold;
ulong_t                 ipgnew;
{
  VMAR                  *parold;        /* AR for old GDT */
  VMAR                  *parnew;        /* AR for new GDT */
  VMOD                  od;             /* Object data */
  int                   rc;             /* Return code */

  vmAssert(VMSysArenaPg(ipgold));
  vmAssert(VMSysArenaPg(ipgnew));
  od.od_pPTDA = NULL;
  od.od_laddr = ipgold << PAGESHIFT;
  rc = VMGetOd(NA, SSToDS(&od));
  vmAssert(rc == NO_ERROR);
  parold = od.od_par;
  od.od_laddr = ipgnew << PAGESHIFT;
  rc = VMGetOd(NA, SSToDS(&od));
  parnew = od.od_par;
  vmAssert(rc == NO_ERROR);
  vmAssert((vmHandleMap(parnew->ar_hob))->ob_hobowner == SELGDTOWNER);
  parnew->ar_sel = parold->ar_sel;      /* Store selector in new AR */
  parnew->ar_f |= AR_SELMAP;
  parold->ar_sel = NULL;            /* Remove selector from old AR */
  parold->ar_f &= ~AR_SELMAP;
  return;
}


/***EP  VMInitProtect - Initialize protected region of shared arena
 *
 *      VMInitProtect is called at initialization time after parsing
 *      config.sys to initialize the protected region, the based region, and
 *      the packed region of the shared arena. Each region is freed if the
 *      region is not to exist.
 *
 *      ENTRY   NONE
 *      RETURN  NONE
 *
 *      VMInitProtect()
 *
 *      PSEUDOCODE
 *
 *           If any of the regions should not exist
 *               Free the packed region
 *
 *               If Based region should not exist
 *                   Free Based region
 *
 *               If protected region should not exist
 *                   Free Protected region
 *
 *               If Packed region should exist
 *                   Reallocate Packed Region
 *
 *
 */

void    VMInitProtect()
{
  int           rc;
  VMAC          ac;             /* VMAllocMem return buffer */
  VMOD          od;             /* Object data */

  /*
   *  Free the reserved area's in the shared arena if necessary.
   */
// BUGBUG force protect region always be off

  VMProtectedMem = 0;
  parGlobalShrSearchStart = parProtectSearchStart;
  /*
   *  Adjust the flat user descriptor limits up to 512M.  Currently
   *  they are set to 512M - 64M.
   *  Note that these calls assume the base linear address of the
   *  descriptors is 0.
   */

  SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_DBIG) << BYTESHIFT | D_DATA2,
            R2DS, 0x20000000, 0, 0, 0, 0);
  SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_DBIG) << BYTESHIFT | D_DATA3,
            R3DS, 0x20000000, 0, 0, 0, 0);
  SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_COPER32) << BYTESHIFT |
            D_CODE2 | D_CONFORM,
            R3CS, 0x20000000, 0, 0, 0, 0);
  SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_DBIG) << BYTESHIFT | D_DATA3,
            R3THKDS, 0x20000000, 0, 0, 0, 0);

  if(!(VMPackedMem))
  {
      rc = VMFreeMem(VM_PACKED_START, HOBNULL, VMFM_GC);
      vmAssert(rc == NO_ERROR);
      vmPackedLBDRY = parPackedSearchStart->ar_ipg << PAGESHIFT;
      vmPackedLBDRY = vmPackedUBDRY;

//ACW Need to change ahvmShr->ah_parFree ONLY if Packed region is
//ACW NOT part of GSR...
//    ahvmShr.ah_parFree = parPackedSearchStart;


//ACW if(!(VMProtectedMem))
//ACW {
//ACW     ahvmShr.ah_parFree   = parProtectSearchStart;
//ACW     parPackedSearchStart = parProtectSearchStart;
//ACW     vmPackedUBDRY = (vmSentAr(parPackedSearchStart)) ?
//ACW                              parPackedSearchStart->ar_ipgmax << PAGESHIFT :
//ACW                              parPackedSearchStart->ar_ipg << PAGESHIFT;
//ACW
//ACW     vmPackedLBDRY = vmPackedUBDRY;
//ACW
//ACW     rc = VMFreeMem(VM_PROTECTED_BASED_START, HOBNULL, VMFM_GC);
//ACW     vmAssert(rc == NO_ERROR);
//ACW
//ACW     /*
//ACW      *  Adjust the flat user descriptor limits up to 512M.  Currently
//ACW      *  they are set to 512M - 64M.
//ACW      *  Note that these calls assume the base linear address of the
//ACW      *  descriptors is 0.
//ACW      */
//ACW
//ACW     SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_DBIG) << BYTESHIFT | D_DATA2,
//ACW               R2DS, 0x20000000, 0, 0, 0, 0);
//ACW     SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_DBIG) << BYTESHIFT | D_DATA3,
//ACW               R3DS, 0x20000000, 0, 0, 0, 0);
//ACW     SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_COPER32) << BYTESHIFT |
//ACW               D_CODE2 | D_CONFORM,
//ACW               R3CS, 0x20000000, 0, 0, 0, 0);
//ACW     SELSetDescInfo(SELSD_LIMIT, (D_UVIRT + D_DBIG) << BYTESHIFT | D_DATA3,
//ACW               R3THKDS, 0x20000000, 0, 0, 0, 0);
//ACW }
//ACW
//ACW if(VMPackedMem)
//ACW {
//ACW     ac.ac_va = vmPackedLBDRY - VM_PACKED_SIZE;
//ACW     rc = VMReserveMem(1, VMAC_ARENASHR | VMAC_LOCSPECIFIC | VMAC_ALIGNSEL,
//ACW                           HOBNULL, 0, SSToDS(&ac));
//ACW     vmAssert(rc == NO_ERROR);
//ACW     vmAssert(ac.ac_va == vmPackedLBDRY - VM_PACKED_SIZE);
//ACW
//ACW     od.od_laddr = vmPackedLBDRY - VM_PACKED_SIZE;
//ACW     od.od_pPTDA = pPTDACur;
//ACW     rc = VMGetOd(NA, SSToDS(&od));
//ACW     vmAssert(rc == ERROR_NO_OBJECT);
//ACW
//ACW     ahvmShr.ah_parFree = od.od_par;
//ACW
//ACW     /*
//ACW      * Have already verified that there is no protected region or no
//ACW      * packed region or neither exists. Since the packed region does exist
//ACW      * then there must be no protected region so it is safe to
//ACW      * move the protected region search starting arena record down.
//ACW      */
//ACW     parProtectSearchStart = od.od_par;
//ACW
//ACW     vmPackedLBDRY = (od.od_par)->ar_ipg << PAGESHIFT;
//ACW     parPackedSearchStart = vmArMap((od.od_par)->ar_harnext);
//ACW
//ACW }
      SelShrPackedStart = LaToSelTiled(vmPackedLBDRY);
      SelShrPackedEnd   = LaToSelTiled(vmSentAr(parPackedSearchStart) ?
                                    parPackedSearchStart->ar_ipgmax << PAGESHIFT :
                                    parPackedSearchStart->ar_ipg << PAGESHIFT);
  }

  return;
}

#pragma code_seg()
