#define SCCSID  "@(#)selkh.c    6.6 91/10/01"

/*
 *       IBM/Microsoft Confidential
 *
 *       Copyright (c) IBM Corporation 1987, 1989
 *       Copyright (c) Microsoft Corporation 1987, 1989
 *
 *       All Rights Reserved
 *
 *  72417  12/22/95  MLM - Moved find.h after tkexport.h since most dirent
 *                         stuff is now in tkexport.h
 * 147968  05/06/96  RJM - Removed FSD and DD owner limits.
 */

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

#define INCL_DOSP
#include <os2p.h>

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

#include                <mi.h>
#include                <dossymc.h>
#include                <sigdef.h>
#include                <except.h>
#include                <infoseg.h>
#include                <curdir.h>
#include                <dirent.h>
#include                <screen.h>
#include                <sem.h>
#include                <seldesc.h>
#include                <vmowner.h>
#include                <pgexport.h>
#include                <vmexport.h>
#include                <selxport.h>
#include                <tkexport.h>
#include                <find.h>             // 72417 moved after tkexport.h
#include                <tkptda.h>
#include                <ldrxport.h>
#include                <sellocal.h>

#define FOR_EXEHDR        1          /* 147968 */
#include                <exe386.h>   /* 147968 */
#include                <ldrvars.h>  /* 147968 */
#include                <vmlocal.h>  /* 147968 */


/***EP  SELAllocKHB - Allocate selector mapped block from a kernel heap.
 *
 *      This function allocates a selector-mapped block from a Kernel Heap.
 *      Certain properties of the block are specifiable.  A selector-mapped
 *      block may be reallocated or freed (see SELReallocKHB, SELFreeKHB).
 *
 *      int SELAllocKHB(VMHKH hkh
 *                      ulong_t cb,
 *                      ulong_t fl,
 *                      ulong_t flSelMgr,
 *                      VMHOB hobOwner,
 *                      VMKHBI *pkhbi)
 *
 *      ENTRY           hkh             - Kernel heap header handle
 *                                        created by VMCreateKH.  Special
 *                                        values map the public heaps:
 *                                        - VM_HKH_PUB_RES_RW
 *                                          Public Resident RW Heap
 *                                        - VM_HKH_PUB_RES_RO
 *                                          Public Resident RO Heap
 *                                        - VM_HKH_PUB_SWAP_RW
 *                                          Public Swappable RW Heap
 *                                        - VM_HKH_PUB_SWAP_RO
 *                      cb              - Size of block requested.  The actual
 *                                        size requested will be rounded up to
 *                                        dword granularity.  This rounded value
 *                                        minus 1 is set in the GDT selector's
 *                                        limit.
 *                      fl              - VM and PG flags specific to this
 *                                        request
 *                                        PG_CONTIG
 *                                        - heap object needs contiguous
 *                                          allocation (PG_RESIDENT only)
 *                                        PG_1M - physical memory below 1Meg
 *                                          required (PG_RESIDENT only)
 *                                        PG_16M - physical memory below 16Meg
 *                                          required (PG_RESIDENT only)
 *                                        VMAC_NOXPAGE - do not cross pages
 *                                          (Allocations from swappable heaps
 *                                           only)
 *                                        VMAC_ALIGNPAGE - align start of
 *                                          block's data to a page boundary
 *                                        PG_R,PG_W,PG_U -read, write, user
 *                                          access
 *                      flSelMgr        - Selector Manager flags specific to
 *                                          this request.
 *                                        SELAL_ALLOCATED - use GDT selector
 *                                          already allocated
 *                                        SELAL_CODE, SELAL_W, SELAL_R,
 *                                        SELAL_CONFORM,
 *                                        (0, 1, 2, 3  << SELAL_PRIVSHIFT)
 *                      hobOwner        - Owner handle
 *                      pkhbi           - Pointer to heap block info
 *                                        The address of the block's data,
 *                                        selector and owner are filled in.
 *
 *      EXIT            *pkhbi          - Linear address, selector, hobOwner
 *      RETURN          int             - Result code (NO_ERROR = success)
 */

int SELAllocKHB(hkh, cb, fl, flSelMgr, hobOwner, pkhbi)
VMHKH                   hkh;            /* Handle to heap to use */
ulong_t                 cb;             /* Size of request in bytes */
ulong_t                 fl;             /* VM, PG flags specific to request */
ulong_t                 flSelMgr;       /* SELAL_ flags specific to request */
VMHOB                   hobOwner;       /* Owner handle */
register VMKHBI         *pkhbi;         /* Returned heap block info */
{
  int                   rc;             /* Result code */
  uchar_t               acc;            /* Descriptor access byte */

  /*
   *  Verify that LDT selector has not been specified.  If a writeable
   *  block requested, mark descriptor as a data descriptor.
   */

  selAssert(!(flSelMgr & SELAL_ALLOCATED) || !(pkhbi->khbi_sel & SEL_LDTBIT));
  if(VMIsReadOnlyKH(hkh))
    {
      selAssert(!(fl & PG_W));
    }
  else
    {
      flSelMgr |= D_DATA0;
    }
  pkhbi->khbi_hobOwner = hobOwner;

  /*
   *  Allocate GDT selector if not using a previously allocated one.
   */

  if((flSelMgr & SELAL_ALLOCATED) || ((rc = SELAllocGDT(&pkhbi->khbi_sel))
      == NO_ERROR))
    {
      /*
       *  Allocate attributed block from heap, storing the specified selector
       *  and owner in its attribute area.  If allocation fails, free selector
       *  (if newly allocated) and return.
       */

      if((rc = VMAllocKHB(hkh, cb, hobOwner, fl | VMAC_SELALLOC, pkhbi))
         != NO_ERROR)
        {
          if(!(flSelMgr & SELAL_ALLOCATED))
            {
              SELFreeGDT(pkhbi->khbi_sel);
            }
          return(rc);
        }

      /*
       *  Make the selector map the block's data by setting its base address
       *  and limit.
       */

      acc = (uchar_t) ((flSelMgr & (SELAL_CODE | SELAL_W | SELAL_PRIVMASK |
            SELAL_CONFORM)) | D_SEG | D_PRES);
      SELSetDescInfo(SELSD_ALL, acc, pkhbi->khbi_sel, cb,
                     (ulong_t) pkhbi->khbi_pbData, NA, NA, 0);
    }
  return(rc);
}


/***EP  SELReallocKHB - Realloc Selector-mapped Kernel Heap Block
 *
 *      This function reallocates a block allocated from the specified kernel
 *      heap.  The new blocksize may be larger than, smaller than, or
 *      equal to the original.  If the new size is zero, the block is freed.
 *      a new block is created, the data copied and the original block is
 *      freed.  The address of the new block may change.
 *      WARNING: This procedure is in swappable code.
 *
 *      int SELReallocKHB(VMHKH hkh,
 *                        SEL sel,
 *                        ulong_t cb,
 *                        ulong_t fl,
 *                        VMKHBI *pkhbi);
 *
 *      ENTRY           hkh             - Kernel heap header handle
 *                                        created by VMCreateKH.  Special
 *                                        values map the public heaps:
 *                                        - VM_HKH_PUB_RES_RW
 *                                          Public Resident RW Heap
 *                                        - VM_HKH_PUB_RES_RO
 *                                          Public Resident RO Heap
 *                                        - VM_HKH_PUB_SWAP_RW
 *                                          Public Swappable RW Heap
 *                                        - VM_HKH_PUB_SWAP_RO
 *
 *                                        if heap header handle is 0  B727267
 *                                        find the appropriate heap.  B727267
 *
 *      ENTRY           hkh             - handle to heap to use
 *                      sel             - Selector mapping the heap block. Must
 *                                        be the selector returned from
 *                                        SELAllocKHB.
 *                      cb              - New size of block
 *                      fl              - Allocation flags.
 *                                        One of PG_RESIDENT or PG_SWAPPABLE
 *                                        must be specified. Other flags are
 *                                        needed if the block is being grown
 *                                        but have no effect if the block is
 *                                        being shrunk.
 *                      pkhbi           - Points to location in which the new
 *                                        linear address of the heap block is
 *                                        to be returned.
 *
 *      RETURN          int             - Result code (NO_ERROR = success)
 *                      pkhbi->khbi_pbData  - New linear address of heap block
 */

int SELReallocKHB(hkh, sel, cb, fl, pkhbi)
VMHKH                   hkh;            /* Handle to heap to use */
SEL                     sel;            /* Selector mapping the block */
ulong_t                 cb;             /* Newsize requested in bytes */
ulong_t                 fl;             /* Alloc flags (grow only) */
VMKHBI                  *pkhbi;         /* Block data address pointer */
{
  struct seldesc_s desc_info;           /* Descriptor info for selector */
  int                   rc;             /* Result code */
  VMKHBI                khbi;           /* Heap Block Info */

  //
  //  Get descriptor information for the selector. If the heap header handle
  //  is not supplied, find the heap the data is in. Verify that the base
  //  address is plausibly the starting address of a heap block whose
  //  attribute area (resident blocks) or descriptor (swappable blocks)
  //  contains the given selector.
  //

  rc = SELGetDescInfo(sel,0,SSToDS(&desc_info));
  selAssert (rc==NO_ERROR);
  pkhbi->khbi_pbData = (char *) desc_info.desc_laddr;

  if (!(hkh))                                                      // B727267
  {                                                                // B727267
     khbi.khbi_pbData = pkhbi->khbi_pbData;                        // B727267
     selAssert(VMGetKHBI(VMKHBI_HEAP, SSToDS(&khbi)) == NO_ERROR); // B727267
     hkh = khbi.khbi_hkh;                     /* Heap handle */    // B727267
  }                                                                // B727267
  selAssert(VMSelKHB(hkh, pkhbi->khbi_pbData) == sel);             // B727267

  /*
   *  Reallocate the heap block, indicating that the new block will be
   *  selector-mapped.  Specify user access if the selector is ring 3.  An
   *  An attributed block will be allocated so that the selector can be stored.
   *  If allocation is successful, update the selector's descriptor to reflect
   *  the new base address and size of the heap object; return the new base
   *  address via the supplied pointer.
   */

  if((desc_info.desc_acc & D_PRIV) == D_DPL3)
    {
      fl |= PG_U;
    }
  if((rc = VMReallocKHB(hkh, pkhbi, cb, fl)) == NO_ERROR)
    {
      SELSetDescInfo(SELSD_ALL, (ushort_t)(desc_info.desc_attr << BYTESHIFT)
        | (ushort_t) (desc_info.desc_acc), sel, cb,
        (ulong_t) pkhbi->khbi_pbData, NA,NA,0);
    }
  return(rc);
}



/***EP  SELFreeKHB - Free Selector-mapped block from a Kernel Heap
 *
 *      This function frees a block allocated from the specified kernel
 *      heap.  The block is marked free but the memory remains
 *      committed.
 *
 *      void SELFreeKHB(VMHKH hkh, ulong_t fl, SEL sel)
 *
 *      ENTRY           hkh             - Heap handle
 *                      fl              - Flags (Not used - must be null)
 *                                         - SEL_KHB_OVERRIDE if sel address
 *                                           not in specified heap search other
 *                                           heaps for that address
 *                                           currently used by the loader only
 *                                           to free device drivers that locked
 *                                           an extra code segment but returned
 *                                           carry at init time
 *                      sel             - Selector mapping the block to be freed
 *      RETURN          void            - Function internal errors if an error
 *                                        is detected.
 */

void  SELFreeKHB(hkh, fl, sel)
VMHKH                   hkh;            /* Heap header handle */
ulong_t                 fl;             /* flags */
register SEL            sel;            /* Selector mapping the block to free */
{
  char                  *pbData;        /* Pointer to block's data */
  struct seldesc_s      desc_info;      /* Descriptor info for selector */
  int                   rc;             /* Result code */
  VMKHBI                khbi;         /* Address of heap block info */

  selAssert( (fl & ~SEL_FREE_KHB_OVERRIDE) == 0);
  /*
   *  Get descriptor information for the selector and verify that its base
   *  address is plausibly the start address of a heap block whose
   *  attribute area (resident blocks) or descriptor (swappable blocks)
   *  contains the given selector.
   */

  rc = SELGetDescInfo(sel,0,SSToDS(&desc_info));
  selAssert (rc==NO_ERROR);
  pbData = (char *) desc_info.desc_laddr;

  if (fl & SEL_FREE_KHB_OVERRIDE)  {
     khbi.khbi_pbData = pbData;
     rc = VMGetKHBI(VMKHBI_HEAP, SSToDS(&khbi));
     selAssert (rc == NO_ERROR);
     hkh = khbi.khbi_hkh;                     /* Heap handle */
  }
  selAssert(VMSelKHB(hkh, pbData) == sel);

  rc = SELFreeGDT(sel);
  selAssert (rc == NO_ERROR);
  VMFreeKHB(hkh, pbData);
}



/***EP  SELMoveKHB - Move given heap block into resident heap.
 *
 *      SELMoveKHB moves given swappable heap block to resident heap. This
 *      function is used to lock down swappable device driver and FSD
 *      segments permanently.  Various properties of the new resident block
 *      can be specified.
 *
 *      WARNING: This routine changes the linear address of the heap block.
 *
 *      ENTRY           hkhSource       - Swappable source heap handle
 *                      hkhDest         - Resident target heap handle
 *                      sel             - Selector mapping block
 *                      fl              - Flags specifying properties
 *                                        of new resident block.
 *                                        - PG_CONTIG - physical contiguity
 *                                          PG_16M - phys mem < 16Meg address
 *                                          VMAC_ALIGNPAGE - page alignment
 *                                          VMAC_ALIGNPARA - para alignment
 *                                          NOTE:  Low memory (address < 1Meg)
 *                                                 is specified by choosing
 *                                                 a low-memory heap as the
 *                                                 destination heap.
 *      RETURN          int             - Result code (NO_ERROR if no error)
 */

int     SELMoveKHB(hkhSource, hkhDest, sel, fl)
VMHKH                   hkhSource;      /* Handle to swappable heap */
VMHKH                   hkhDest;        /* Handle to resident heap */
SEL                     sel;            /* GDT selector mapping heap block */
ulong_t                 fl;             /* Flags */
{
  struct seldesc_s      desc;           /* Sel heap block descriptor */
  int                   rc;             /* Result code */

  /*
   *  Verify that the source heap is swappable, the destination heap
   *  is resident and the selector is not an LDT selector.
   */

  selAssert(VMIsSwappableKH(hkhSource));
  selAssert(VMIsResidentKH(hkhDest));
  selAssert(!(sel & SEL_LDTBIT));

  /*
   *  Get descriptor information from the selector.  If error, return.
   */

  if((rc = SELGetDescInfo(sel, HOBNULL, SSToDS(&desc))) == NO_ERROR)
    {
      /*
       *  Check that the specified selector matches that contained in the
       *  swappable heap source block's descriptor.
       */

      selAssert(VMSelKHB(hkhSource, (char *) desc.desc_laddr) == sel);

      /*
       *  If the selector is Ring3, set PG_U flag.
       */

      if(((desc.desc_acc & D_PRIV) == D_DPL3) ||
         ((desc.desc_acc & (D_CODE | D_CONFORM)) == (D_CODE | D_CONFORM)))
        {
          fl |= PG_U;
        }

      /*
       *  Move the block from the swappable heap to the resident heap.  If
       *  successful, remap the selector with the address of the new block.
       */

      if((rc = VMMoveKHB(hkhSource,
                         hkhDest,
                         fl,
                         (char **) SSToDS(&((char *)desc.desc_laddr))))
           == NO_ERROR)
        {
          SELSetDescInfo(SELSD_ALL, (ushort_t)(desc.desc_attr << BYTESHIFT) |
                (ushort_t)desc.desc_acc, sel, desc.desc_cb,
                desc.desc_laddr, HOBNULL, HOBNULL, NA);
        }
    }
  return(rc);
}


/***EP  SELGetKHBI - Get Kernel Heap Block Info for Selector-Mapped Heap Block
 *
 *      This function verifies that the given selector maps the data of a
 *      selector-mapped heap block, and that the selector isi the same as that
 *      recorded in the heap block's attribute area.  If the checks pass,
 *      the heap block info is returned.
 *
 *      int SELGetKHBI(ulong_t fl, VMKHBI *pkhbi)
 *
 *      ENTRY           fl              - Flags (not used, must be zero)
 *                      pkhbi           - Pointer to heap block info with
 *                                        only the  selector to be checked
 *                                        filled in.
 *      EXIT            pkhbi           - Pointer to heap block info with
 *                                        address (unchanged) and, if block
 *                                        is valid, the hobOwner and selector
 *                                        (if any, or NULL) filled in.
 *      RETURN          int             - Result code (NO_ERROR if no error)
 */

int SELGetKHBI(fl, pkhbi)
ulong_t                 fl;             /* Flags (not used, must be zero) */
VMKHBI                  *pkhbi;         /* Pointer to heap block info */
{
  int                   rc;             /* Result code */
  struct seldesc_s      desc;           /* Descriptor info */
  SEL                   sel = pkhbi->khbi_sel;
                                        /* Original selector passed in */
  selAssert(fl == NA);

  /*
   *  Get descriptor info for the given selector.  If successful, extract
   *  the base address mapped by the selector and get the info for the
   *  heap block (if any) whose data starts at that address.  Verify that
   *  the heap block is selector-mapped, and that the recorded selector
   *  is the same (apart from RPL bits) as the given selector.
   */

  if((rc = SELGetDescInfo(pkhbi->khbi_sel,HOBNULL,SSToDS(&desc)))==NO_ERROR)
    {
      pkhbi->khbi_pbData = (char *) desc.desc_laddr;
      if(((rc = VMGetKHBI(VMKHBI_HEAP | VMKHBI_BLOCK, pkhbi)) == NO_ERROR) &&
         (sel & SEL_RPLCLR) == (pkhbi->khbi_sel & SEL_RPLCLR))
        {
          return(NO_ERROR);
        }
    }

  return(ERROR_INVALID_PARAMETER);
}


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

/***EP  SELIfsAlloc - Allocate heap/segment object for IFS
 *
 *      SELIfsAlloc allocates heap object/segment for IFS entry point.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY       fl  - Flags
 *                        0x1 Allocate in task space (heap space if not set)
 *                        0x2 Allocate swappable (fixed, contig if not set)
 *                        0x4000 Allocate Ring 2
 *                        0x6000 Allocate Ring 3
 *                  cb  - Size of memory
 *                  psel- Location to return selector
 *      RETURN      int - Error code, NO_ERROR if no error
 */
int         SELIfsAlloc(fl, cb, psel, owner)
ulong_t     fl;
ulong_t     cb;
SEL         *psel;
VMHOB       owner;
{
    int     rc;
    VMAC    ac;
    ulong_t flvm;
    ulong_t flsel;

    /* Check for validity of flags */

    if (fl & ~SEL_IFSFLAGS)
      {
        return(ERROR_INVALID_PARAMETER);
      };

    if (((fl & SEL_IFSRINGMASK) == SEL_IFSRING1) ||
        ((fl & SEL_IFSRINGMASK) == SEL_IFSRING2))       /* DCR 1043 */
      {
        return(ERROR_ACCESS_DENIED);
      };

    /*
     *  All GDT area allocations go to heap and have page-aligned linear
     *  address.
     */

    /* Set up VMAC_* flags */

    if (fl & SEL_IFSLDT)
      {

        if (((fl & SEL_IFSRINGMASK) == SEL_IFSRING0) ||
            !(fl & SEL_IFSSWAP))                    /* DCR 1043 */
          {
            return(ERROR_ACCESS_DENIED);
          };

        flvm = VMAC_LOCANY | VMAC_ALIGNSEL |  VMAC_ARENAPRV | VMAC_SELALLOC |
               VMAC_OBAPI;
      }
    else
      {
        flvm = VMAC_LOCANY | VMAC_ALIGNPAGE | VMAC_ARENAHEAP | VMAC_SELALLOC;
      };

    /* Set up PA?_* flags */

    if (fl & SEL_IFSSWAP)
      {
        /* Don't pass PG_* flag to heap */

        flvm |= PG_SWAPPABLE | PG_R | PG_W;
      }
    else
      {
        flvm |= PG_RESIDENT | PG_W | PG_R | PG_16M;
        if (!(fl & SEL_IFSNONCONTIG))
          {
            flvm |= PG_CONTIG;
          }
      };

    /* Set up SELAL_* flags */

    flsel = SELAL_SELMAP | SELAL_W |
        ((fl & SEL_IFSRINGMASK) >> SEL_IFSRINGSHFT);
    if ((fl & SEL_IFSRINGMASK) == SEL_IFSRING3) {
        flvm |= PG_U;
    };
    rc = VMAllocMem(cb, cb, flvm, HOBNULL,
            (VMHOB) ((fl & SEL_IFSLDT) ? pPTDACur->ptda_handle : FSHOWNER),
            owner , flsel, NULL, SSToDS(&ac));
    if (rc == NO_ERROR) {
        *psel = ac.ac_sel;
    }
    return(rc);
}


/***EP  SELIfsFree - Free an IFS segment/heap object
 *
 *      SELIfsFree frees an IFS object, whether it is in the heap or not.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY           sel             - Selector mapping the object
 *      RETURN          int             - Result code (NO_ERROR if no error)
 */

int                     SELIfsFree(sel)
SEL                     sel;
{
  int                   rc;             /* Result code */
  VMOD                  od;             /* Object info for non-heap item */
  struct seldesc_s      desc;           /* Descriptor info */
  VMKHBI                khbi;           /* Heap block info */

  /*
   *  Check if the given selector maps a selector-mapped heap block and
   *  matches (apart from RPL) the selector recorded in the heap block's
   *  attribute area.  If a match is found, free the heap block.
   */

  khbi.khbi_sel = sel;
  if((rc = SELGetKHBI(NA, SSToDS(&khbi))) == NO_ERROR)
    {
      if(IsFSDOwner(khbi.khbi_hobOwner) || IsFSHOwner(khbi.khbi_hobOwner) ||
         (khbi.khbi_hobOwner == pPTDACur->ptda_handle))
        {
          SELFreeKHB(khbi.khbi_hkh, NA, sel);
          return(NO_ERROR);
        }
    }

  /*
   *  The given address does not belong to a heap object.  Get the object
   *  info, check the owner is the file system, check that the object is
   *  not shared-content.
   */

  od.od_pPTDA = pPTDACur;
  if((rc = SELGetOd(VMGS_VERIFY,
                         sel,
                         SSToDS(&desc),
                         SSToDS(&od))) == NO_ERROR)
    {
      /*
       *  Check that the selector's base address maps the given address.
       *  If the two are equal, the memory is not shared, or its
       *  owner is one of (File System Helper, IFS, or the current
       *  task), free the memory from the current task.  Otherwise,
       *  return an error.
       */

      rc = ERROR_INVALID_PARAMETER;
      if(desc.desc_laddr == VMLaddrOd(od) &&
         (!(VMShrContOd(od))) &&
          (IsFSDOwner(VMOwnerOd(od)) || IsFSHOwner(VMOwnerOd(od)) ||
           (VMOwnerOd(od) == pPTDACur->ptda_handle)))
        {
          rc = VMFreeMem((ulong_t) khbi.khbi_pbData, HOBNULL, NA);
        }
    }
  return(rc);
}


/***EP  SELIfsRealloc - Reallocate an ifs owned segment/heap object.
 *
 *      SELIfsRealloc reallocates an ifs owned segment/heap object.
 *      WARNING: This procedure is in swappable code
 *
 *      ENTRY           sel             - Selector
 *                      cb              - New size
 *      RETURN          int             - Result code
 */

int     SELIfsRealloc(sel, cb)
SEL                     sel;            /* Selector */
ulong_t                 cb;             /* New size */
{
  int                   rc;             /* Result code */
  VMKHBI                khbi;           /* Heap block info */
  VMKHBI                *pkhbi = SSToDS(&khbi);
                                        /* Pointer to heap block info */

  /*
   *  Check if the given selector maps a selector-mapped heap block and
   *  matches (apart from RPL) the selector recorded in the heap block's
   *  attribute area.  If a match is found, realloc the heap block.
   */

  khbi.khbi_sel = sel;
  if((rc = SELGetKHBI(NA, pkhbi)) == NO_ERROR)
    {
      if(IsFSDOwner(khbi.khbi_hobOwner) || IsFSHOwner(khbi.khbi_hobOwner) ||
         (khbi.khbi_hobOwner == pPTDACur->ptda_handle))
        {
          khbi.khbi_fl |= (khbi.khbi_fl & PG_RESIDENT) ?
            PG_CONTIG : VMAC_ALIGNPAGE;
          if((rc = SELReallocKHB(khbi.khbi_hkh,
                                 sel,
                                 cb,
                                 khbi.khbi_fl & VMAC_KHBMASK,
                                 pkhbi)) == NO_ERROR)
            {
              return(NO_ERROR);
            }
        }
    }

  /*
   *  The object is not in the heap; call ifs_SegRealloc.
   */

  return(selIfsSegRealloc(cb, sel));
}


/***EP  SELIfsNoSwap - Make a swappable segment/heap object resident.
 *
 *      SELIfsNoSwap makes a swappable segment or selector-mapped heap object
 *      fixed and contiguous.  If the selector maps a heap object, an error
 *      will be returned if the heap object was not allocated as selector-
 *      mapped.
 *
 *      WARNING: This procedure is in swappable code.
 *
 *      int SELIfsNoSwap(SEL sel)
 *
 *      ENTRY           sel             - Selector mapping the segment
 *      RETURN          int             - Result code (NO_ERROR if no error)
 */

int     SELIfsNoSwap(sel)
SEL                     sel;            /* Selector mapping the segment */
{
  int                   rc;             /* Result code */
//VMOI                  oi;             /* Object info */
  VMOD                  od;
  struct seldesc_s      d;              /* Descriptor info */
  VMKHBI                khbi;           /* Heap block info */
  VMKHBI                *pkhbi = SSToDS(&khbi);
                                        /* Pointer to heap block info */

  if (sel & SEL_LDTBIT)                 /* DCR 1043 */
  {
      return(ERROR_ACCESS_DENIED);
  }

  /*
   *  Check to see if the selector maps a heap block.  If so, check that
   *  the given selector matches that in the returned heap block info,
   *  ignoring the RPL bits.
   */

  khbi.khbi_sel = sel;
  if((rc = SELGetKHBI(NA, pkhbi)) == NO_ERROR)
  {
      if(IsFSDOwner(khbi.khbi_hobOwner) || IsFSHOwner(khbi.khbi_hobOwner))
      {
          /*
           *  If the heap object mapped by the given selector is not already in
           *  the public read/write or readonly resident heap, move the heap
           *  object to the appropriate heap.
           */

           if(!((khbi.khbi_hkh == VM_HKH_PUB_RESRW) ||
                (khbi.khbi_hkh == VM_HKH_PUB_RESRO)))
           {
               return(SELMoveKHB(khbi.khbi_hkh,
                      ((pkhbi->khbi_fl & PG_W) ?
                       VM_HKH_PUB_RESRW : VM_HKH_PUB_RESRO),
                      sel,
                      PG_CONTIG | VMAC_ALIGNPAGE | PG_16M));           //b725036
           }
           else   // the object is already in a resident heap, return ok
           {
               return(NO_ERROR);
           }
      }
  }

  /*
   *  Get the object info, taking the handle semaphore.  Return error
   *  if unsuccessful.
   */

//if((rc = SELObjectInfo(VMGS_TAKESEM | VMGS_VERIFY, sel, HOBNULL,
//              SSToDS(&d), SSToDS(&oi))) != NO_ERROR)

  od.od_pPTDA = pPTDACur;
  if((rc = SELGetOd(VMGS_TAKESEM | VMGS_VERIFY, sel,
                        SSToDS(&d), SSToDS(&od))) != NO_ERROR)
  {
      return(ERROR_ACCESS_DENIED);
  }

  /*
   *  If the selector's base address does not map the object info base
   *  address, or the object is not owned either by the file system
   *  or the current task, deny access.
   */

//if((d.desc_laddr != oi.oi_va) ||
//   !((oi.oi_hobowner == pPTDACur->ptda_handle) ||
//   IsFSDOwner(oi.oi_hobowner) || IsFSHOwner(oi.oi_hobowner)))

  if((d.desc_laddr != od.od_laddr) ||
         !(((od.od_pob)->ob_hobowner == pPTDACur->ptda_handle) ||
         IsFSDOwner((od.od_pob)->ob_hobowner) ||
         IsFSHOwner((od.od_pob)->ob_hobowner)))
  {
//    VMClearSem(oi.oi_hob);
      VMClearSem(vmPobToHob(od.od_pob));
      return(ERROR_ACCESS_DENIED);
  };

//rc = PGSetType(oi.oi_va >> PAGESHIFT, pPTDACur,
//               (d.desc_cb + PAGEMASK) >> PAGESHIFT, PG_RESIDENT);
//VMClearSem(oi.oi_hob);

  rc = PGSetType(od.od_laddr >> PAGESHIFT, pPTDACur,
                 (d.desc_cb + PAGEMASK) >> PAGESHIFT, PG_RESIDENT);
  VMClearSem(vmPobToHob(od.od_pob));
  return(rc);
}


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

/***LP  selLockDD - Lock a DD segment permanently at init time
 *
 *      selLockDD locks a Device Driver segment permanently at init time.
 *      This procedure supports the old 16 bit permanent locks made via
 *      SegLockDM.
 *
 *      WARNING:        This procedure may change the linear address of the
 *                      segment.
 *
 *      ENTRY           sel             - Selector mapping the segment
 *      RETURN          int             - Result code (NO_ERROR if no error)
 *
 */

int selLockDD(sel)
SEL                     sel;            /* Selector mapping the segment */
{
  int                   rc;             /* Result code */
  VMKHBI                khbi;           /* Heap info block */

  /*
   *  Return error if an LDT selector has been specified.
   */

  if(sel & SEL_LDTBIT)
    {
      return(ERROR_INVALID_PARAMETER);
    }

  /*
   *  Check to see if the selector maps a heap block.  If so, check that
   *  the given selector matches that in the returned heap block info,
   *  ignoring the RPL bits.
   */

  khbi.khbi_sel = sel;
  if((rc = SELGetKHBI(NA, SSToDS(&khbi))) == NO_ERROR &&
     ((khbi.khbi_fl & PG_RESIDENT) == 0))
    {
      rc = SELMoveKHB(khbi.khbi_hkh,
                      (khbi.khbi_fl & PG_W) ? VM_HKH_PUB_RESRW :
                                              VM_HKH_PUB_RESRO,
                      sel, PG_CONTIG | PG_16M);
    }
  return(rc);
}


/***EP  SELRemoveAccess - Remove user level access from Devhlp objects.
 *
 *      SELRemoveAccess is called at the end of initialization to remove
 *      user level access from memory allocated by Devhlp.
 *      This memory may or may not be in the heap.
 *
 *      ENTRY           laddr           - Address of memory
 *                      sel             - Selector mapping memory (if exists)
 *      RETURN          NONE
 */

void   SELRemoveAccess(laddr, sel)
ulong_t                 laddr;          /* Address of memory */
SEL                     sel;            /* Selector mapping memory (if any) */
{
  int                   rc;             /* Result code */
  VMKHBI                khbi;           /* Heap info buffer */
//VMOI                  oi;             /* Object info buffer */
  VMOD                  od;             /* Object descriptor */
  struct seldesc_s      desc;           /* Descriptor info */
  struct  desctab       *d;             /* Descriptor table pointer */
  ulong_t               fl;             /* Flags */

  /*
   *  Check if given address points to a heap object.  If so, get its
   *  heap block info.
   */

  khbi.khbi_pbData =  (char *) laddr;
  if((rc = VMGetKHBI(VMKHBI_HEAP | VMKHBI_BLOCK, SSToDS(&khbi))) != NO_ERROR)
  {
      /*
       *  Address does not point to a heap object.  Take the handle semaphore
       *  and get object info when object is stable.  Operation must succeed.
       */

//    rc = VMGetMemInfo(VMGS_VERIFY, laddr, HOBNULL, SSToDS(&oi), NULL);

      od.od_laddr = laddr;
      od.od_pPTDA = pPTDACur;
      rc = VMGetOd(VMGS_VERIFY, SSToDS(&od));

      selAssert(rc == NO_ERROR);

      /*
       *  If a selector has been specified, the object must be a selector-
       *  mapped system arena object and the recorded selector must match the
       *  given selector (except for the RPL bits).
       */

      if(sel)
      {
//        selAssert((oi.oi_fsar & AR_SELMAP) &&
//                  VMSysArena(laddr) &&
//                  (oi.oi_sel & SEL_RPLCLR) == (sel & SEL_RPLCLR));
          selAssert(((od.od_par)->ar_f & AR_SELMAP) &&
                        VMSysArena(laddr) &&
                        (VMSelOd(od) & SEL_RPLCLR) == (sel & SEL_RPLCLR));
          selAssert((rc = SELGetDescInfo(sel, HOBNULL, SSToDS(&desc)))
                 == NO_ERROR);
          d = (struct desctab *)((ulong_t) SELGDTLaddr +
            (ulong_t)(sel & SEL_RPLCLR));
          d->d_access &= ~D_PRIV;
      }

//    fl =((oi.oi_fsar & AR_PERMMASK) >> AR_PERMSHFT) & ~PG_U;
//    rc = PGSetAccess(laddr >> PAGESHIFT, pPTDACur, oi.oi_cb >> PAGESHIFT,
//              fl | PG_SKIPFREE);
      fl = (((od.od_par)->ar_f & AR_PERMMASK) >> AR_PERMSHFT) & ~PG_U;
      rc = PGSetAccess(laddr >> PAGESHIFT, pPTDACur, (od.od_par)->ar_cpg,
                           fl | PG_SKIPFREE);
      selAssert(rc == NO_ERROR);
  }
  else
  {
      /*
       *  This is a heap object.  If a selector has been specified, the
       *  heap object must be selector-mapped and the given selector must
       *  agree with that contained in the attribute area.  Set the DPL to 0.
       */

      selAssert((sel & SEL_RPLCLR) == (khbi.khbi_sel & SEL_RPLCLR));
      if(sel)
      {
          if((rc = SELGetDescInfo(khbi.khbi_sel, HOBNULL, SSToDS(&desc)))
              == NO_ERROR && desc.desc_laddr == laddr)
          {
              d = (struct desctab *)((ulong_t) SELGDTLaddr +
                  (ulong_t)(khbi.khbi_sel & SEL_RPLCLR));
              d->d_access &= ~D_PRIV;
          }
      }
      VMRemoveUserAccessKHB(khbi.khbi_hkh, khbi.khbi_pbData);
  }
}

#pragma code_seg()
/*end*/


/***EP  SELValidateKHBAddress - Validate given heap address, return sel, owner
 *
 *      BUGBUG - This is being replaced
 *
 *      SELValidateKHBAddress validates that the given address corresponds to
 *      the start of a SEL or VM heap object, and it returns the owner and
 *      the selector of the object.
 *
 *      ENTRY           p               - Address to be validated
 *                      psel            - Location to return the selector
 *                                          (0 returned if VM heap)
 *                      phobOwner       - Location to return the owner of the
 *                                        heap object
 *      RETURN          int             - Result code (NO_ERROR if success)
 */

int                     SELValidateKHBAddress(p, psel, phobOwner)
char                    *p;
SEL                     *psel;
VMHOB                   *phobOwner;
{
  int                   rc;
  VMKHBI                khbi;

  khbi.khbi_pbData = p;
  if((rc = VMGetKHBI(VMKHBI_HEAP | VMKHBI_BLOCK, SSToDS(&khbi))) == NO_ERROR)
    {
      if(((ulong_t) psel) != VM_NO_ADDR)
        {
          *psel = khbi.khbi_sel;
        }
      if(((ulong_t) phobOwner) != VM_NO_ADDR)
        {
          *phobOwner = khbi.khbi_hobOwner;
        }
    }
  return(rc);
}
