/*      SCCSID = @(#)vmkh.h     6.3 91/10/30 */

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

/***LD Block - Heap block format
 *
 *      Kernel resident heap blocks are of two types, regular and
 *      attributed.
 *
 *      (1)     Regular blocks
 *
 *      These are the simplest and most common type. They have the
 *      form  <simple header><data>
 *
 *      <simple header> is a dword (32-bits) having the following layout
 *
 *      <owner><prev block free flag><size in dwords><yielded flag><type flag>
 *
 *      Field           Bits            Description
 *
 *      owner           16-31           Owner of heap block.  This is
 *                                      either a system owner (value between
 *                                      VMMINOWNER and VMMAXOWNER, or a
 *                                      memory handle/pseudo handle such as
 *                                      an MTE pseudo-handle.
 *      previous block  15              1 if previous block is free, else 0
 *      free flag
 *      size in dwords  14-2            Size of the block including the
 *                                      header in dwords.
 *      yielded flag    1               1 if a free block search yielded
 *                                      the CPU while looking at this block,
 *                                      else 0
 *      type flag       0               0 (indicates Regular Block)
 *
 *      (2)  Extended blocks
 *
 *      These blocks contain a two-part header and have the following
 *      form
 *
 *      <size header><data><header extension>
 *
 *      <size header> is a dword (32-bits) having the following layout
 *
 *      <extra flags><size in dwords><yielded flag><type flag>.
 *
 *      Field           Bits            Description
 *
 *      extra flags     31-24           Additional flags.
 *                                      Bit 31 - set if block is free
 *                                      Bit 30 - set if prev block is free
 *                                      Bits 29-24 - reserved and 0
 *      size in dwords  23-2            Size of the block including the
 *                                      header in dwords.
 *      yielded flag    1               1 if a free block search yielded
 *                                      the CPU while looking at this block,
 *                                      else 0
 *      type flag       0               1 (indicates Extended Block)
 *
 *      <data> is the data area available for use by the client and is
 *      always dword granular and dword aligned.
 *
 *      <header extension> is a dword-granular structure containing
 *      the following information
 *
 *      <owner><selector>
 *
 *      Field           Bits            Description
 *
 *      owner           31-16           Owner of heap block.  This is
 *                                      either a system owner (value between
 *                                      VMMINOWNER and VMMAXOWNER, or a
 *                                      memory handle/pseudo handle such as
 *                                      an MTE pseudo-handle.
 *      selector        15-1            GDT selector mapping block's data
 *                                      else null.
 *
 *      When a block is free, its data portion contains additional
 *      information.  The first two dwords contain forward and backward
 *      pointers to the next and previous blocks on the free list.  The
 *      last dword contains a copy of the previous block pointer.  Note that
 *      extended free blocks do not have an owner field, so bit 31 of their
 *      header is set indicating that they are free.
 */


/***LK+ Kernel Heap Constants (common to resident and swappable heaps) */

#define hkh_MIN         1               /* Max heap header handle */
#define hkh_MAX         8               /* Max heap header handle */
#define VM_KH_HEAP_VAL  1               /* Enable heap checking */
#define VM_KH_HEAP_TEST 2               /* Enable heap testing */
#define VM_KH_DON_TEST  4               /* Test donate code */

/*end*/

/***LK+ KRHC Kernel Resident Heap Constants */

#define krh_RESERVE (VMAC_ARENASYS | VMAC_ALIGNPAGE | VMAC_OBSHRINK | \
                     PG_RESIDENT | PG_ZEROFILL)
                                        /* Initial heap reservation flags */
#define krh_COMMIT    (VMS_COMMIT | PG_RESIDENT | PG_ZEROFILL | PG_R)
#define krh_CFREELIST   5               /* Number of free list sections */
#define PKRHBNULL       NULL            /* Null Block Descriptor Pointer */
#define PKRHNULL        NULL            /* Null Heap Header Pointer */
#define PKRHSNULL       NULL            /* Null Freelist Section Hdr Pointer */
#define VM_MAX_RES_RW_HEAP_SIZE   _4MEG
#define VM_MAX_RES_RO_HEAP_SIZE   _4MEG
/*end*/

/***LK+ KSHC - Kernel Swappable Heap Global Constants */

#define VM_MAX_SWAP_RW_HEAP_SIZE  _16MEG
#define VM_MAX_SWAP_RO_HEAP_SIZE  _4MEG
/*end*/

/***LK+ KRHBC - Kernel Resident Heap Block Constants */

#define krhb_PFREE      ((ulong_t) 0x00008000)   /* Prev block is Free flag */
#define krhb_PBBACK     ((ulong_t) 0x00000002)   /* Back pointer flag */
#define krhb_YIELD      ((ulong_t) 0x00000002)   /* Yielded at this block */
#define krhb_CR_NEW     ((ulong_t) 0x00000004)   /* New block flag */
#define krhb_CR_NXVAL   ((ulong_t) 0x00000010)   /* Next block valid flag */
#define krhb_CR_NOMERGE ((ulong_t) 0x00000020)   /* Do not merge free blocks */
#define krhb_CR_NOINSFR ((ulong_t) 0x00000040)   /* Do not add residual block
                                                    to free list */
#define krhb_CR_USEDECO ((ulong_t) 0x00000080)   /* Must use decommitted mem
                                                    in free block */
#define krhb_SMALL      ((ulong_t) 0x00000800)   /* Small allocation */
#define krhb_STATUS_MASK (krhb_YIELD | krhb_ATTR) /* Block status mask */
#define krhb_OWNER_MASK ((ulong_t) 0xffff0000)   /* Mask of owner field */
#define krhb_OWNER_SHIFT 16                      /* Displ of owner field */
#define krhb_REG_SIZE_MASK ((ulong_t) 0x00007ffc)/* Regular Block Size Mask */
#define krhb_REG_MIN_SIZE ((ulong_t) sizeof(VMKRHF))
                                                 /* Min Size of regular KRHB */
#define krhb_REG_MAX_SIZE ((ulong_t) 0x00007ffc) /* Max Size of regular KRHB */
#define krhb_ATTR_SIZE_MASK ((ulong_t) 0x00fffffc)/* Attr Block Size Mask */
#define krhb_ATTR_MIN_SIZE ((ulong_t) sizeof(VMKRHF) + sizeof(VMKHBA))
                                                 /* Attr Block Max Size */
#define krhb_ATTR_MAX_SIZE ((ulong_t) 0x00fffffc) /* Attr Block Max Size */
#define krhb_ATTR       ((ulong_t) 0x00000001)   /* Block is extended */
#define krhb_ATTR_FREE  ((ulong_t) 0x80000000)   /* Attr block is free */
#define krhb_ATTR_PFREE ((ulong_t) 0x40000000)   /* Attr blk pred is free */
#define krhb_GRAN_MASK  ((ulong_t) 0x00000003)   /* Heap block gran. mask */
#define krhb_MIN_SIZE   sizeof(VMKRHF)           /* Minimum block size */
#define krhb_MAXLOOP    5000            /* Number of loops before yielding */
#define krhb_MAXYIELD   8               /* Room for 8 yielding blocks */
#define krhb_CBEND sizeof(VMKRHB)       /* Size of end block */
/*end*/



/***LK+ KRHSC - Kernel resident heap free list section constants */

#define krhs_cbMax0     8L              /* Max blocksize for free section 0 */
                                        /* This section is not used but
                                         * allows "pkrhs - 1" to work where
                                         * pkrhs points to free list section
                                         * header 1.
                                         */
#define krhs_cbMax1     64L             /* Max blocksize for free section 1 */
#define krhs_cbMax2     PAGESIZE + sizeof(VMKRHF)
                                        /* Max blocksize for free section 2 */
#define krhs_cbMax3     krhb_REG_MAX_SIZE
                                        /* Max blocksize for free section 3 */
                                        /* Max blocksize for free section 4 */
#define krhs_cbMax4     krhb_ATTR_MAX_SIZE
                                        /* Default max blocksize for free
                                         * section 4; gets reset when a heap
                                         * is initialized.
                                         */
/*end*/


/***LC  VMKRHB - Kernel Resident Heap Block Header
 *
 *      All blocks in a kernel resident heap are dword-aligned and are a
 *      multiple of a dword in length.  The heap consists of a contiguous
 *      region of virtual memory subdivided into busy and free blocks.
 *
 *      Each block is prepended with a 4 or 8 byte header.  Blocks of total
 *      size (including header) not exceeding 0x7ffc bytes have a 4-byte
 *      header and are called "regular" blocks.  The structures below are
 *      descriptive only; for efficiency, for efficiency, masks are used to
 *      manipulate their data.  A regular block's header is divided into
 *      fields as follows:
 *
 *      struct vmkrhb_s {
 *              ulong_t         krhb_attr:1;     // Attributed block flag
 *              ulong_t         krhb_yield:1;    // Thread-yielded-here flag
 *              ulong_t         krhb_size:13;    // Size of block in dwords
 *              ulong_t         krhb_pfree:1;    // Preceding block is free
 *              ulong_t         krhb_hobowner:16 // Owner
 *      };
 *
 *      Blocks of total size exceeding 0x7ffc are held in attributed block
 *      format.
 *
 *      Free blocks are doubly linked together into a single free list.
 *      Forward and backward links are kept in the data portion of the
 *      block (in the first two dwords).  The free list is divided into
 *      sections based on block size.  Each section has associated with it a
 *      maximum block size and is anchored to one member of an array of
 *      section headers.  The array of section headers is ordered by
 *      increasing maximum block size and each section contains all blocks
 *      whose size cb satisfies the relation:
 *
 *      maxsize(preceding freelist section) < cb <= maxsize(freelist section)
 */

struct _krhb_struct0
  {
    ushort_t _krhb_usSize;
    VMHOB    _krhb_hobOwner;
  };

struct _krhb_struct1
  {
    ulong_t _krhb_ulSize;
  };

struct vmkrhb_s
  {
    union
      {
        ulong_t _krhb_ulHdr;
        struct _krhb_struct0 krhb_struct0;
        struct _krhb_struct1 krhb_struct1;
      } krhb_union0;
  };

typedef struct vmkrhb_s VMKRHB;

#define krhb_ulHdr krhb_union0._krhb_ulHdr
#define krhb_usSize krhb_union0.krhb_struct0._krhb_usSize
#define krhb_hobOwner krhb_union0.krhb_struct0._krhb_hobOwner
#define krhb_ulSize krhb_union0.krhb_struct0._krhb_ulSize

struct vmkrhf_s
  {
    VMKRHB              krhf_struct0;
    char                *krhf_pbNext;           // Forward freelist link
    char                *krhf_pbPrev;           // Backward freelist link
  };

typedef struct vmkrhf_s VMKRHF;

#define krhf_ulHdr krhf_struct0.krhb_union0._krhb_ulHdr
#define krhf_usSize krhf_struct0.krhb_union0._krhb_struct0.krhb_usSize
#define krhf_hobOwner krhf_struct0.krhb_union0.krhb_struct0.krhb_hobOwner

struct vmkrhp_s
  {
    VMKRHB              krhp_struct0;
  };

typedef struct vmkrhp_s VMKRHP;

#define krhp_ulHdr krhp_struct0.krhb_union0._krhb_ulHdr
#define krhp_usSize krhp_struct0.krhb_union0._krhb_struct0.krhb_usSize
#define krhp_hobOwner krhp_struct0.krhb_union0.krhb_struct0.krhb_hobOwner

/*end*/


/***LT+ Kernel Resident Heap Free List Anchor Structure
 *
 *      Kernel Resident Heaps have a number of doubly linked free lists
 *      each containing free blocks whose size is within a given
 *      minimum and maximum interval.  Access to the free lists is via
 *      an array of free list descriptors.  Descriptors are ordered
 *      by increasing maximum size of the free blocks that are allowed
 *      on the list.  Each descriptor consists of a pointer to the free
 *      block at the head of the free list, and the maximum usable size
 *      (size - busy header) of blocks in this list.  Free blocks are always
 *      placed in the free list with lowest maximum size for which they
 *      qualify.
 *
 *      A fixed-size array of these descriptors is embedded within each
 *      kernel resident heap header structure (struct vmkrh_s).
 */

struct vmkrhs_s
  {
    ulong_t     krhs_cbMax;
    VMKRHF      krhs_krhfHead;
  };

typedef struct vmkrhs_s VMKRHS;

/*end*/


/***LT+ Kernel Resident Heap Yield List Structure */

#define krh_MAXYIELD    8               /* Room for 8 yielding blocks */

struct vmkrhy_s
  {
    char                *krhy_pb;       /* Block pointer */
    unsigned short      krhy_cyield;    /* Yield count */
  };

typedef struct vmkrhy_s VMKRHY;         /* Kernel resident heap yield struct */
/*end*/


/***LT+ VMKRH - Kernel Resident Heap Header */

struct vmkrh_s
  {
    ulong_t     krh_cBlocks;            /* Count of heap blocks */
    ulong_t     krh_cFreeBlocks;        /* Count of free heap blocks */
    char        *krh_pbFirst;           /* First Heap Block */
    char        *krh_pbLast;            /* Last Heap Block */
    char        *krh_pbEndRes;          /* Upper bound of reserved virt mem */
    char        *krh_pbEndCom;          /* Upper bound of committed virt mem */
    ulong_t     krh_lpgBase;            /* Start lin page of heap object */
    ulong_t     krh_cMods;              /* Count of heap modifications */
    ulong_t     krh_fl;                 /* Resident heap flags */
    VMKRHF      krh_krhfDummy;          /* Dummy free block */
    VMKRHS      *krh_pkrhsLast;         /* Last Freelist Section Pointer */
    VMKRHY      krh_akrhy[krh_MAXYIELD];/* Array of yield structures */
    VMKRHS      krh_akrhs[krh_CFREELIST]; /* Count of free list sections */
    VMHOB       krh_hob;                /* Heap object handle */
    KSEMMTX     krh_ksem;               /* KSEM for resident heap b700000 */
  };

typedef struct vmkrh_s VMKRH;

/*end*/

/***LP  vmMakeHdrRegKRHB - Compose Regular KRHB Header
 *
 *      This function combines input values into a KRHB header
 *
 *      ulong_t vmMakeHdrRegKRHB(VMHOB hobOwner, ulong_t cb, ulong_t fl)
 *
 *      ENTRY           hobOwner        - Block owner
 *                      cb              - Block Size (incl header)
 *                      fl              - Flags
 *      RETURN          ulong_t         - Header value
 */

#define vmMakeHdrRegKRHB(hobOwner, cb, fl) \
  ((((ulong_t) hobOwner) << 16) + (cb) + (fl))


/***LP  vmMakeHdrAttrKRHB - Compose Attributed KRHB Header
 *
 *      This function combines input values into a header for
 *      an attributed KRHB.
 *
 *      ulong_t vmMakeHdrAttrKRHB(ulong_t cb, ulong_t fl)
 *
 *      ENTRY           cb              - Block Size (incl header)
 *                      fl              - Flags
 *      RETURN          ulong_t         - Header value
 */

#define vmMakeHdrAttrKRHB(cb, fl) ((cb + fl) | krhb_ATTR)


/***LP  vmIsHKH - Verify that given handle is a valid heap header handle
 *
 *      This function verifies that a given handle is a valid heap handle
 *
 *      int     vmIsHKH(VMHKH hkh)
 *
 *      ENTRY           hkh                     - Heap header handle
 *      RETURN          int                     TRUE if hkh is a resident
 *                                              heap header handle, else false
 *
 *      CALLS           NONE
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmIsHKH(hkh) \
  (hkh >= hkh_MIN && hkh <= hkhCurrMax && apkh[hkh].kh_pkrh != PKRHNULL)


/***LP  vmIsHKRH - Verify that given handle is a resident heap header handle
 *
 *      This function verifies that a given handle is a resident heap handle
 *
 *      int     vmIsHKRH(VMHKH hkh)
 *
 *      ENTRY           hkh                     - Heap header handle
 *      RETURN          int                     TRUE if hkh is a resident
 *                                              heap header handle, else false
 *
 *      CALLS           NONE
 *      EFFECTS         NONE
 *
 *      WARNINGS        This function is implemented as a macro.
 *                      The handle is assumed to be a vaild heap handle.
 */

#define vmIsHKRH(hkh) (apkh[hkh].kh_fl & PG_RESIDENT)


/***LP  vmIsHKSH - Verify that given handle is a swappable heap header handle
 *
 *      This function verifies that a given handle is a swappable heap header
 *      handle.
 *
 *      int     vmIsHKSH(VMHKH hkh)
 *
 *      ENTRY           hkh                     - Heap header handle
 *      RETURN          int                     TRUE if hkh is a swappable
 *                                              heap header handle, else FALSE
 *
 *      CALLS           NONE
 *      EFFECTS         NONE
 *
 *      WARNINGS        This function is implemented as a macro.
 *                      The handle is assumed to be a vaild heap handle.
 */

#define vmIsHKSH(hkh) ((apkh[hkh].kh_fl & PG_RESIDENT) == 0)



/***LP  vmWriteULKRHB - Set unsigned long word in kernel resident heap
 *
 *      This function stores the specified ulong value in the specified
 *      kernel resident heap ulong.  The target ulong may belong to a read-write
 *      or read-only heap.  Parameters are assuned to be valid.
 *
 *      void vmWriteULKRHB(VMKRH *pkrh, void *pul, ulong_t ulValue)
 *
 *      ENTRY           pkrh            - pointer to heap header
 *                      pul             - pointer to ulong
 *                      ulValue         - value to be stored
 *                                        PG_W - heap is writeable
 *      RETURN          void            - Any error causes a page fault
 *
 *      WARNING:  This function is implemented as a macro.
 */

#define vmWriteULKRHB(pkrh, pul, ulValue) \
{                                         \
  if(pkrh->krh_fl & PG_W)                 \
    {                                     \
      (*((ulong_t *)(pul)) = ulValue);    \
    }                                     \
  else                                    \
    {                                     \
      VMSetReadOnlyUL(pul, ulValue);      \
    }                                     \
}


/***LP  vmWriteUSKRHB - Set unsigned short in kernel resident heap
 *
 *      This function stores the specified ushort value in the specified
 *      kernel resident heap ushort.  The target ulong may belong to a
 *      read-write or read-only heap.  Parameters are assumed to be valid.
 *
 *      void vmWriteUSKRHB(VMKRH *pkrh, void *pus, ushort_t usValue)
 *
 *      ENTRY           pkrh            - pointer to heap header
 *                      pus             - pointer to ushort
 *                      usValue         - value to be stored
 *                                        PG_W - heap is writeable
 *      RETURN          void            - Any error causes a page fault
 *
 *      WARNING:  This function is implemented as a macro.
 */

#define vmWriteUSKRHB(pkrh, pus, usValue) \
{                                         \
  if(pkrh->krh_fl & PG_W)                 \
    {                                     \
      (*((ushort_t *)(pus)) = usValue);   \
    }                                     \
  else                                    \
    {                                     \
      VMSetReadOnlyUS(pus, usValue);      \
    }                                     \
}


/***LP  vmCeilKRHB - Round up address to resident heap block granularity
 *
 *      This function rounds a given virtual address up to the next
 *      address that is valid for use as a resident heap block address.
 *      The granularity of resident heap block addresses is 2**n where
 *      n is the number of status bits in a block header; currently n=2.
 *
 *      char *vmCeilKRHB(char *pb)
 *
 *      ENTRY           pb              - Unrounded pointer to block header
 *      RETURN          char *          - Rounded pointer to block header
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmCeilKRHB(pb) \
  ((char *)((((ulong_t)(pb)) + krhb_STATUS_MASK) & (~(krhb_STATUS_MASK))))


/***LP  vmFloorKRHB - round down address to resident heap block granularity
 *
 *      This function rounds a given virtual address down to the next
 *      address that is valid for use as a resident heap block address.
 *      The granularity of resident heap block addresses is 2**n where
 *      n is the number of status bits in a block header; currently n=2.
 *
 *      char *vmFloorKRHB(char *pb)
 *
 *      ENTRY           pb              - Unrounded pointer to block header
 *      RETURN          char *          - Rounded pointer to block header
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmFloorKRHB(pb) \
  ((char *)((ulong_t)(pb)  & (~(krhb_STATUS_MASK))))


/***LP  vmCanCoalesceKRHB - return true if block can be coalesced
 *
 *      This function returns true if the given block can be coalesced.  This
 *      means the block is neither busy, nor has any thread yielded at it.
 *
 *      int vmCanCoalesceKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - 0 if uncoalescible, non-zero otherwise
 *
 *      CALLS           vmHasYieldedKRHB, vmIsFreeKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmCanCoalesceKRHB(pb) (vmIsFreeKRHB(pb) && (!vmHasYieldedKRHB(pb)))


/***LP  vmYieldCheckKRHB - Update iteration count and yield if necessary
 *
 *      This function updates the specified iteration counter and yields if
 *      the specified threshhold is reached.
 *
 *      void vmYieldCheckKRHB(VMKRH *pkrh, char *pb, ulong_t cLoops)
 *
 *      ENTRY           pkrh            - Pointer to heap header
 *                      pb              - Pointer to block
 *                      cLoops          - Iteration counter
 *      RETURN          void
 *
 *      CALLS           vmYieldKRHB
 */

#define vmYieldCheckKRHB(pkrh, pb, cLoops) \
((++cLoops < krhb_MAXLOOP) ? 1 : (pb = vmYieldKRHB(pkrh, pb), cLoops = 0))


/***LP  vmHasYieldedKRHB - return true if someone has yielded here
 *
 *      This function returns true if the yield bit is set in the
 *      header of the given block.
 *
 *      int vmHasYieldedKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - 0 if yield bit clear, non-zero
 *                                        otherwise
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmHasYieldedKRHB(pb) (*((char *)(pb)) & krhb_YIELD)


/***LP  vmIsFreeKRHB - return true if block is free
 *
 *      This function returns true if the given block is free.
 *
 *      int vmIsFreeKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - 0 if busy, non-zero otherwise
 *
 *      CALLS           vmOwnerKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmIsFreeKRHB(pb) \
  ((vmIsRegKRHB(pb)) ? vmIsFreeRegKRHB(pb) : vmIsFreeAttrKRHB(pb))


/***LP  vmIsFreeRegKRHB - Return true if regular block is free
 *
 *      This function returns true if the given regular block is free.
 *
 *      int vmIsFreeRegKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - 0 if busy, non-zero otherwise
 *
 *      CALLS           vmOwnerRegKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmIsFreeRegKRHB(pb) (vmOwnerRegKRHB(pb) == VMKRHFOWNER)


/***LP  vmIsFreeAttrKRHB - Return true if extended block is free
 *
 *      This function returns true if the given extended block is free.
 *
 *      int vmIsFreeAttrKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - 0 if busy, non-zero otherwise
 *
 *      CALLS           vmOwnerAttrKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmIsFreeAttrKRHB(pb) (vmOwnerAttrKRHB(pb) == VMKRHFOWNER)



/***LP  vmIsDummyKRHB - return true if block is the dummy block
 *
 *      This function returns true if the given block is the special dummy
 *      block.  This block always remains on the free list and its purpose
 *      is to simplify free list operations by eliminating the need to
 *      special-case null pointers.
 *
 *      int vmIsDummyKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - TRUE if dummy, FALSE otherwise
 *
 *      CALLS           NONE
 *
 *      EFFECTS NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmIsDummyKRHB(pb) ((pb) == (char *)(&(pkrh->krh_krhfDummy)))



/***LP  vmOwnerKRHB - Get the owner of a Kernel Resident Heap Block
 *
 *      This function returns the owner of a kernel resident heap block
 *
 *      VMHOB vmOwnerKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          VMHOB           - Block's owner
 *
 *      CALLS           vmIsRegKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmOwnerKRHB(pb) \
  (vmIsRegKRHB(pb) ? vmOwnerRegKRHB(pb) : vmOwnerAttrKRHB(pb))


/***LP  vmOwnerRegKRHB - Get the owner of a regular Kernel Resident Heap Block
 *
 *      This function returns the owner of a regular kernel resident heap block
 *
 *      VMHOB vmOwnerRegKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to regular block header
 *      RETURN          VMHOB           - Block's owner
 *
 *      CALLS           vmIsRegKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmOwnerRegKRHB(pb) (((VMKRHB *)(pb))->krhb_hobOwner)


/***LP  vmOwnerAttrKRHB - Get Owner of an Attributed Kernel Resident Heap Block
 *
 *      This function returns the owner of a kernel resident heap block that
 *      has an attribute area.
 *
 *      VMHOB vmOwnerAttrKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to attributed block header
 *      RETURN          VMHOB           - Block's owner
 *
 *      CALLS           vmIsFreeAttrKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmOwnerAttrKRHB(pb) ((vmpkhbaKRHB(pb))->khba_hobOwner)


/***LP  vmCopyAttrKRHB - Copy Kernel Resident Heap Block Attribute Area
 *
 *      BUGBUG IDB 9/26/90 - This macro is necessary because the C
 *      compiler generates code which contains push ss; pop es thereby
 *      trashing flat ES when copying a VMKHBA structure to/from the
 *      stack.  Problem arises because the attribute area has been expanded.
 *
 *      This function copies a VMKHBA structure fromone location to
 *      another.  Individual fields are copied to bypass the above
 *      C compiler bug.
 *
 *      void vmCopyAttrKRHB(VMKHBA khbaDest, VMKHBA khbaSrc)
 *
 *      ENTRY           khbaDest        - Destination VMKHBA
 *                      khbaSrc         - Source VMKHBA
 *
 *      WARNING:        This function is implemented as a macro
 */

#define vmCopyAttrKRHB(khbaDest, khbaSrc)                               \
  {                                                                     \
    (khbaDest).khba_sel = (khbaSrc).khba_sel;                           \
    (khbaDest).khba_hobOwner = (khbaSrc).khba_hobOwner;                 \
    (khbaDest).khba_hobMTE = (khbaSrc).khba_hobMTE;                     \
  }


/***LP  vmSizeDataKRHB - Get Size of Kernel Resident heap Block's Data
 *
 *      This function retruns the size of the client-usable data portion of
 *      of a Kernel Resident Heap Block.  The size of the data is found by
 *      extracting the total block size from the header and then applying
 *      the following formulae:
 *
 *      Regular Blocks:
 *
 *      <size_client_data> = <total_block_size> - <size_block_header>
 *
 *      Attributed Blocks:
 *
 *      <size_client_data> = <total_block_size> - <size_block_header>
 *                           - <size_attribute_area>
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          ulong_t         - Size of client data in bytes
 *
 *      WARNING:        This function is implemented as a macro
 */

#define vmSizeDataKRHB(pb) \
  (vmIsRegKRHB(pb) ? vmSizeRegKRHB(pb) - sizeof(VMKRHB) : \
                     vmSizeAttrKRHB(pb) - sizeof(VMKRHB) - sizeof(VMKHBA))


/***LP  vmClrYieldKRHB - Clear Yield Bit In Kernel Resident Heap Block
 *
 *      This procedure clears the yield bit in the given block's header.
 *
 *      vmClrYieldKRHB(pkrh, pb)
 *
 *      ENTRY           pkrh            - Pointer to heap header
 *                      pb              - Pointer to block header
 *      RETURN          NONE
 *
 *      CALLS           vmSetHdrKRHB, vmHdrKRHB
 *
 *
 *      EFFECTS         Clears the yield bit in the specified block's header.
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmClrYieldKRHB(pkrh, pb) \
  vmSetHdrKRHB(pkrh, pb, vmHdrKRHB(pb) & ~krhb_YIELD)


/***LP  vmSetFreeKRHB - Mark the given block as free
 *
 *      This function marks the given block as free by setting the free owner
 *      in the header (regular blocks) or preceding header (large blocks).
 *
 *      vmSetFreeKRHB(pkrh, pb)
 *
 *      ENTRY           pkrh            - Pointer to heap header
 *                      pb              - Pointer to block header
 *      RETURN          NONE
 *
 *      CALLS           vmSetOwnerKRHB
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmSetFreeKRHB(pkrh, pb) vmSetOwnerKRHB(pkrh, pb, VMKRHFOWNER)


/***LP  vmphobOwnerKRHB - Point at owner field in a KRHB
 *
 *      This function returns a pointer to the owner field in a
 *      Kernel Resident Heap Block.
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          VMHOB *         - Pointer to owner
 */

#define vmphobOwnerKRHB(pb) \
(vmIsRegKRHB(pb) ? (VMHOB *)(pb) : \
(VMHOB *)(&(vmpkhbaKRHB(pb)->khba_hobOwner)))



/***LP  vmSetYieldKRHB - Set the yield bit for Kernel Resident Heap Block
 *
 *      This procedure sets the yield bit in the given KRHB's header.
 *
 *      vmSetYieldKRHB(pkrh, pb)
 *
 *      ENTRY           pkrh            - Pointer to heap header
 *                      pb              - Pointer to block header
 *      RETURN          NONE
 *
 *      CALLS           vmHdrKRHB, vmSetHdrKRHB
 *
 *      WARNING         This function is implemented as a macro.
 *
 *      EFFECTS         Sets the yield bit in the specified block's
 *                      header.
 */

#define vmSetYieldKRHB(pkrh, pb) \
  vmSetHdrKRHB(pkrh, pb, vmHdrKRHB(pb) | krhb_YIELD)


/***LP  vmSetHdrKRHB - Set Kernel Resident Heap Block Header
 *
 *      This function initializes a kernel resident heap block header
 *      to contain the given ulong value.
 *
 *      ENTRY           pkrh            - Pointer to heap header
 *                      pb              - Pointer to block header
 *                      ul              - Header value
 *      RETURN          void
 *
 *      CALLS           vmWriteULKRHB
 *
 *      WARNING         This function is implemented as a macro
 */

#define vmSetHdrKRHB(pkrh, pb, ul)                                      \
{                                                                       \
  if(pkrh->krh_fl & PG_W)                                               \
    {                                                                   \
      (((VMKRHB *)(pb))->krhb_ulHdr = ul);                              \
    }                                                                   \
  else                                                                  \
    {                                                                   \
      vmWriteULKRHB(pkrh, &(((VMKRHB *)(pb))->krhb_ulHdr), ul);         \
    }                                                                   \
}


/***LP  vmHdrKRHB - Get value of Kernel Resident Heap Block header
 *
 *      This function returns the current value of the given kernel
 *      resident heap block's header.
 *
 *      ulong_t vmHdrKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to heap header
 *      RETURN          ulong_t         - Content of header
 *
 *      CALLS           None
 *
 *      WARNING         This function is implemented as a macro
 *
 *      EFFECTS         None
 */

#define vmHdrKRHB(pb) (*((ulong_t *)(pb)))


/***LP  vmIsValidKRHB - Check that block is valid
 *
 *      This function checks whether the given block has a valid header.
 *      For regular blocks, the control word must contain a valid
 *      system owner or pseudo-handle value.  For large blocks, the
 *      control word must be marked large (krhb_EXTN set) and the word
 *      preceding the control word must contain a valid system owner or
 *      pseudo handle value.
 *
 *      int vmIsValidKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          int             - TRUE if signature valid else FALSE
 *
 *      CALLS           vmIsValidOwnerKRHB, vmOwnerKRHB
 *
 *      WARNING         This function is implemented as a macro.
 *
 *      EFFECTS         NONE
 */

#define vmIsValidKRHB(pb) (vmIsValidOwnerKRHB(vmOwnerKRHB(pb)))


/***LP  vmHasValidOwnerKRHB - Check if heap block has valid owner
 *
 *      This function checks if a given heap block's owner field contains a
 *      valid value.  Permitted values for heap block owners are special
 *      system owners and pseudo-handles.
 *
 *      int vmHasValidOwnerKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN                          TRUE if value is valid, else FALSE
 *
 *      CALLS           vmIsValidOwnerKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro
 */

#define vmHasValidOwnerKRHB(pb) \
(vmIsValidOwnerKRHB(vmOwnerKRHB(pb)))


/***LP  vmIsValidOwnerKRHB - Check if valid heap block owner
 *
 *      This function checks if a given value is acceptable for use as a
 *      heap block owner.  Permitted values for heap block owners are special
 *      system owners and pseudo-handles.
 *
 *      int vmIsValidOwnerKRHB(VMHOB hobOwner)
 *
 *      ENTRY           hobOwner        - Value to be validated
 *      RETURN                          TRUE if value is valid, else FALSE
 *
 *      CALLS           vmSystemOwner, VMHandleVerify
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro
 */

#define vmIsValidOwnerKRHB(hobOwner) \
  (vmSystemOwner(hobOwner) || (VMHandleVerify(hobOwner, 1, NA) == NO_ERROR))


/***LP  vmNeedsRegKRHB - Check if a regular or extended KRHB needed
 *
 *      Given a total block size and flags combination, this function checks
 *      if it is possible to create a regular KRHB of the specifed size taking
 *      into account the properties specified by flags.
 *
 *      int vmNeedsRegKRHB(ulong_t cb, ulong_t fl)
 *
 *      ENTRY           cb              - Total Size of block including
 *                                        header
 *                      fl              - Flags.  These include any subset
 *                                        of the flags specified to VMAllocKHB.
 *                                        The following flags result in FALSE
 *                                        being returned, meaning that an
 *                                        extended KRHB would be needed
 *
 *                                        VMAC_SELALLOC
 *
 *      RETURN          int             TRUE if a regular block only is needed,
 *                                      FALSE otherwise
 *
 *      CALLS           None
 *
 *      EFFECTS         None
 *
 *      WARNING         This function is implemented as a macro
 */

#define vmNeedsRegKRHB(cb, fl) \
  ((!(fl & VMAC_SELALLOC)) && ((cb) <= krhb_REG_MAX_SIZE))


/***LP  vmNeedsAttrKRHB - Check if an attributed KRHB needed
 *
 *      Given a total block size and flags combination, this function checks
 *      if an attributed KRHB is required for a block of the specifed size
 *      taking into account the properties specified by flags.
 *
 *      int vmNeedsAttrKRHB(ulong_t cb, ulong_t fl)
 *
 *      ENTRY           cb              - Total Size of block including
 *                                        header
 *                      fl              - Flags.  These include any subset
 *                                        of the flags specified to VMAllocKHB.
 *                                        The following flags result in TRUE
 *                                        being returned, meaning that an
 *                                        extended KRHB would be needed
 *
 *                                        VMAC_SELALLOC
 *
 *      RETURN          int             TRUE if an extended block is needed,
 *                                      FALSE otherwise
 */

#define vmNeedsAttrKRHB(cb, fl) \
  ((fl & VMAC_SELALLOC) || (cb > krhb_REG_MAX_SIZE))


/***LP  vmIsWithinKRH - Test if block pointer is in range
 *
 *      This function checks whether the given block pointer is within the
 *      range of addresses spanned by the heap.
 *
 *      vmIsWithinKRH(pkrh, pb)
 *
 *      ENTRY           pkrh            - Pointer to heap header
 *                      pb              - Pointer to block
 *      RETURN          int             - TRUE if in range else FALSE
 *
 *      CALLS           NONE
 *
 *      WARNING         This function is implemented as a macro.
 *
 *      EFFECTS NONE
 */

#define vmIsWithinKRH(pkrh, pb) \
  (pb >= pkrh->krh_pbFirst && pb < pkrh->krh_pbLast)


/***LP  vmSizeKRHB - return the size of the given block
 *
 *      This function returns the size in bytes of the given block.
 *      The size returned includes the block header.
 *
 *      NOTE:   Use this function if the block type (regular or attributed)
 *              is not known.  If the block type is known, use either
 *              vmSizeRegKRHB or vmSizeAttrKRHB.
 *
 *      vmSizeKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          ulong_t         - Size of the block in bytes
 *
 *      CALLS           vmIsRegKRHB, vmSizeRegKRHB, vmSizeAttrKRHB
 *
 *      WARNING         This function is implemented as a macro.
 *
 *      EFFECTS NONE
 */

#define vmSizeKRHB(pb) \
  (vmIsRegKRHB(pb) ? vmSizeRegKRHB(pb) : vmSizeAttrKRHB(pb))



/***LP  vmSizeRegKRHB - Return the size of the given regular block
 *
 *      This function returns the size of a regular kernel resident heap
 *      block, that is, a block not having an attribute area.
 *
 *      ulong_t vmSizeRegKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to regular block
 *      RETURN          ulong_t         - Size of block including header
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmSizeRegKRHB(pb) (*((ulong_t *)(pb)) & krhb_REG_SIZE_MASK)


/***LP  vmSizeRegKRHBD - Return the size of the given regular block's data
 *
 *      This function returns the size of a regular kernel resident heap
 *      block's data.
 *
 *      ulong_t vmSizeRegKRHBD(char *pbData)
 *
 *      ENTRY           pbData          - Pointer to regular block's data
 *      RETURN          ulong_t         - Size of block excluding header
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmSizeRegKRHBD(pbData) \
  (vmSizeRegKRHB(pbData - sizeof(VMKRHB)) - sizeof(VMKRHB))


/***LP  vmSizeAttrKRHB - Return the size of the given attributed KRHB
 *
 *      This function returns the size of an attributed KRHB.
 *
 *      ulong_t vmSizeAttrKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to attributed block header
 *      RETURN          ulong_t         - Size of block including header
 *
 *      CALLS           NONE
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmSizeAttrKRHB(pb) ((*((ulong_t *)(pb))) & krhb_ATTR_SIZE_MASK)


/***LP  vmIsRegKRHB - Check for Regular Kernel Resident Heap Block
 *
 *      This function tests a block to see if it is regular.
 *
 *      int vmIsRegKRHB(pb)
 *
 *      ENTRY           pb              - Pointer to regular block header
 *      RETURN          int             TRUE if regular, else FALSE
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmIsRegKRHB(pb) (!vmIsAttrKRHB(pb))


/***LP  vmIsAttrKRHB - Check for Attributed Kernel Resident Heap Block
 *
 *      This function tests a block to see if it has an attribute area.
 *
 *      int vmIsAttrKRHB(pb)
 *
 *      ENTRY           pb              - Pointer to Block
 *      RETURN          int             TRUE if attributed, else FALSE
 *
 *      CALLS           vmHdrKRHB
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmIsAttrKRHB(pb) ((*((ulong_t *)(pb))) & krhb_ATTR)


/***LP  vmNextKRHB - Point to next resident heap block
 *
 *      This function obtains the address of the next resident heap block.
 *      Use this function when the type of the given current heap block is
 *      not known; use vmNextRegKRHB() when the type of the current heap
 *      block is known to be regular.
 *
 *      char *vmNextKRHB(pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          char *          - Pointer to next block header
 *
 *      CALLS           vmSizeKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 *
 */

#define vmNextKRHB(pb) ((pb) + vmSizeKRHB(pb))


/***LP  vmNextRegKRHB - Point to next resident heap block after reg block
 *
 *      This function obtains the address of the next resident heap block
 *      following the given regular heap block.
 *
 *      char *vmNextRegKRHB(pb)
 *
 *      ENTRY           pb              - Pointer to regular block header
 *      RETURN          char *          - Pointer to next block header
 *
 *      CALLS           vmSizeRegKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 *
 */

#define vmNextRegKRHB(pb) ((pb) + vmSizeRegKRHB(pb))


/***LP  vmNextFreeKRHB - Point to next resident heap block on free list
 *
 *      This function obtains the address of the next resident heap block
 *      after the given one on the free list.
 *
 *      char *vmNextFreeKRHB(pb)
 *
 *      ENTRY           pb              - Pointer to free block header
 *      RETURN          char *          - Pointer to next free block header
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmNextFreeKRHB(pb) (((VMKRHF *)(pb))->krhf_pbNext)


/***LP  vmPrevFreeKRHB - Point to previous resident heap block on free list
 *
 *      This function obtains the address of the resident heap block
 *      preceding the given free block on the free list.
 *
 *
 *      char *vmPrevFreeKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to free block header
 *      RETURN          char *          - Pointer to previous free block header
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING         This function is implemented as a macro.
 */

#define vmPrevFreeKRHB(pb) (((VMKRHF *)(pb))->krhf_pbPrev)


/***LP  vmHasPrevFreeKRHB - Block has previous free block
 *
 *      This function checks if a block is preceded by a free block.
 *
 *      int     vmHasPrevFreeKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to free block header
 *      RETURN          int             - TRUE if preceding block freei,
 *                                        else FALSE
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmHasPrevFreeKRHB(pb) \
  (vmIsRegKRHB(pb) ?  vmHasPrevFreeRegKRHB(pb) : \
                      vmHasPrevFreeAttrKRHB(pb))


/***LP  vmHasPrevFreeRegKRHB - Regular block has previous free block
 *
 *      This function checks if a regular block is preceded by a free block.
 *
 *      int     vmHasPrevFreeRegKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to free block header
 *      RETURN          int             - TRUE if preceding block freei,
 *                                        else FALSE
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmHasPrevFreeRegKRHB(pb) (*((ulong_t *)(pb)) & krhb_PFREE)


/***LP  vmHasPrevFreeAttrKRHB - Attributed block has previous free block
 *
 *      This function checks if an attributed block is preceded by a free block.
 *
 *      int     vmHasPrevFreeAttrKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to free block header
 *      RETURN          int             - TRUE if preceding block freei,
 *                                        else FALSE
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING This function is implemented as a macro.
 */

#define vmHasPrevFreeAttrKRHB(pb) (*((ulong_t *)(pb)) & krhb_ATTR_PFREE)


/***LP  vmIsEmptyKRHS - Check if free list is empty
 *
 *      This function checks a free list to see if it is empty, that is,
 *      it contains only the dummy block.
 *
 *      int vmIsEmptyKRHS(VMKRHS *pKRHS)
 *
 *      ENTRY           pkrhs           - Pointer to free list header
 *      RETURN          int             - TRUE if empty, else FALSE
 *
 *      CALLS           vmHeadFreeKRHB, vmDummyFreeKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING - This function is implemented as a macro
 */

#define vmIsEmptyKRHS(pkrhs) vmHeadFreeKRHB(pkrhs) == vmDummyFreeKRHB(pkrhs)


/***LP  vmHeadFreeKRHB - Get head free block from free list.
 *
 *      This function returns a pointer to the block at the head of the given
 *      free list or, if the free list is empty, a pointer to the dummy free
 *      block embedded in the free list header.
 *
 *      char *vmHeadFreeKRHB(VMKRHS *pkrhs)
 *
 *      ENTRY           pkrhs           - Pointer to free list header
 *      RETURN          char *          - Pointer to head free block if list
 *                                        non-empty, else pointer to dummy free
 *                                        block.
 *
 *      CALLS           vmNextFreeKRHB, vmDummyFreeKRHB
 *
 *      EFFECTS         NONE
 *
 *      WARNING - This function is implemented as a macro
 */

#define vmHeadFreeKRHB(pkrhs) vmNextFreeKRHB(vmDummyFreeKRHB(pkrhs))


/***LP  vmDummyFreeKRHB - Get pointer to dummy free block in free list.
 *
 *      This function returns a pointer to the dummy free block that is
 *      embedded in the given free list header.
 *
 *      char *vmDummyFreeKRHB(VMKRHS *pkrhs)
 *
 *      ENTRY           pkrhs           - Pointer to free list header
 *      RETURN          char *          - Pointer to dummy free block.
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING - This function is implemented as a macro
 */

#define vmDummyFreeKRHB(pkrhs) ((char *)(&(pkrhs->krhs_krhfHead)))


/***LP  vmBlockSizeKRHS - Get maximum block size for given free list section.
 *
 *      Given a pointer to a free list section header, this function returns the
 *      maximum size of blocks that can be linked on that free list section.
 *
 *      ulong_t  vmBlockSizeKRHS(VMKRHS *pkrhs)
 *
 *      ENTRY           pkrhs           - Pointer to free list header
 *      RETURN          ulong_t         - Pointer to dummy free block.
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 *
 *      WARNING - This function is implemented as a macro
 */

#define vmBlockSizeKRHS(pkrhs) pkrhs->krhs_cbMax



/***LP  vmRoundSizeRegKRHB - Round up size to size of regular block needed
 *
 *      Given a size in bytes, this function returns the total size of the
 *      heap block required to contain a data portion of at least the
 *      given size.  The rounding takes into account the fact that heap block
 *      addresses must have a granularity determined by the number of bits
 *      of the header word that are used for flags.  Since the start of
 *      a successor heap block is computed by adding in the size to the
 *      address of a block, the same granularity restriction applies to
 *      heap block sizes.
 *
 *      ulong_t vmRoundSizeRegKRHB(ulong_t cb)
 *
 *      ENTRY           cb              - Unrounded block size in bytes
 *      RETURN          ulong_t         - Rounded block size
 *
 *      CALLS           NONE
 *
 *      EFFECTS         NONE
 */

#define vmRoundSizeRegKRHB(cb) \
  ((cb < sizeof(VMKRHF) - sizeof(VMKRHB)) ? sizeof(VMKRHF) : \
  ((cb + sizeof(VMKRHB) + krhb_GRAN_MASK) & ~(krhb_GRAN_MASK)))


/***LP  vmpkhbaKRHB - Get pointer to attribute data in Kernel Resident Heap
 *                      Block
 *
 *      This function returns a pointer to the attribute structure in an
 *      attributed Kernel Resident Heap Block.
 *
 *      VMKHBA  *vmpkhbaKRHB(char *pb)
 *
 *      ENTRY           pb              - Pointer to block header
 *      RETURN          VMKHBA *        - Pointer to attribute data
 */

#define vmpkhbaKRHB(pb) \
  ((VMKHBA *)(pb + vmSizeAttrKRHB(pb) - sizeof(VMKHBA)))


/***LP  vmDecommitMinKRHB - Return pointer to lower bound for decommitted
 *      region within block.
 *
 *      This function returns the lower bound for the decommitted region
 *      within a block.  Note that if a block does not have a decommitted
 *      region, the returned pointer may point beyond the end of the block.
 */

#define vmDecommitMinKRHB(pb) ((char *)(vmPageCeil(pb + sizeof(VMKRHF))))


/***LP  vmDecommitMaxKRHB - Return pointer to upper bound for decommitted
 *      region within block of specified size.
 *
 *      This function returns the upper bound for the decommitted region
 *      within a block of specified size.  Note that if a block does not
 *      have a decommitted region, the returned pointer may point before the
 *      beginning of the block.
 */

#define vmDecommitMaxKRHB(pb, cb) \
  ((char *)(vmPageFloor(pb + cb - sizeof(VMKHBA) - sizeof(char *))))


/***LP  vmPossWithinKH - Quick check to see if address possibly within KH
 *
 *      This function checks a linear address to see if it belongs within
 *      the region bounded by the minimum and maximum linear addresses
 *      assigned to kernel heaps.
 *
 *      ENTRY           laddr           - Linear address
 *      RETURN                          - TRUE if address is within
 *                                        range.  Address is likely
 *                                        to be a heap address.
 *                                        FALSE if address cannot be a
 *                                        heap address.
 */

#define vmPossWithinKH(laddr) \
  ((ulong_t)(laddr) >= vmladdrMinKH && (ulong_t)(laddr) < vmladdrMaxKH)


/***LK+ Local Kernel Swappable Heap Constants */

#define ksh_STATUS_MASK (ksh_FREE | ksh_YIELD)  /* Mask of status bits */
#define ksh_CREATE      ( VMAC_OBSHRINK | VMAC_ARENASYS | PG_SWAPPABLE | \
                          PG_ZEROFILL | PG_R)
#define ksh_COMMIT      ( VMS_COMMIT | PG_SWAPPABLE | PG_ZEROFILL | PG_R )
                                        /* Swappable heap growth flags */
#define ksh_MAXLOOP     50              /* Number of loops before yielding */
#define ksh_MAXSIZE     1024            /* 4G bytes maximum heap size */
#define hksh_MIN        1               /* Min swappable heap header handle */
#define hksh_MAX        16              /* Max swappable heap header handle */
#define KSHENDLIST      NULL

#define vm_KSH_MAX_BLOCKS  vm_MAX_BMP32_HANDLES
#define vm_KSH_MAX_SIZE    _4MEG

/*end*/

/***LT+ VMKSHD - Kernel Swappable Heap Descriptor Record for Free Blocks
 *
 */


struct vmkshd_s
  {
    ulong_t             kshd_size;       // Size of block in dwords
    struct vmkshd_s     *kshd_pNext;     // Next free block
    char                *kshd_pb;        // Address of block header
  };


typedef struct vmkshd_s VMKSHD;
/*end*/


/***LT+ Kernel Swappable Heap Block Header for Allocated blocks
 */

struct vmkshb_s
  {
    ulong_t     kshb_size;      // size of block
    VMHOB       kshb_hobowner;  // owner
    SEL         kshb_sel;       // Selector
  };

typedef struct vmkshb_s VMKSHB;

/*end*/

struct vmksh_s
  {
    VMKSHD      ksh_hdrEntry;
    VMKSHD      *ksh_pHint;             /* Pointer to last block touched     */
    VMKSHD      *ksh_pHPrev;            /* Ptr to PrevBlk of last touched    */
    ulong_t     ksh_HintSize;           /* Size of last block touched        */
    char        *ksh_pbEndRes;          /* Upper bound of reserved virt mem */
    char        *ksh_pbEndCom;          /* Upper bound of committed virt mem */
    ulong_t     ksh_fl;                 /* Swappable heap allocation flags */
    VMHOB       ksh_hob;                /* Heap object handle */
    char        *ksh_pbStart;           /* Lower bound of reserved virt mem */
    KSEMMTX     ksh_ksem;               /* KSEM for swappable heap b700000 */
#ifdef VMSTRICT
    ulong_t     ksh_ckshds;             /* Count of heap modifications */
    ulong_t     ksh_cFrees;             /* Count of heap modifications */
    ulong_t     ksh_cAllocs;            /* Count of heap modifications */
#endif
  };

typedef struct vmksh_s VMKSH;

/*end*/

#ifdef VMSTRICT

#define vmIncr_ksh_cAllocs(r,x) if ((r)==0) ((x)++)
#define vmIncr_ksh_cFrees(x)    ((x)++)
#define vmIncr_ksh_ckshds(x)    ((x)++)
#define vmDecr_ksh_ckshds(x)    ((x)--)

#else

#define vmIncr_ksh_cAllocs(r,x)  ;
#define vmIncr_ksh_cFrees(x)   ;
#define vmIncr_ksh_ckshds(x)   ;
#define vmDecr_ksh_ckshds(x)   ;

#endif

#define MULT8MSK        0x7

#define kshRoundUp(x)       (((x) + (sizeof(VMKSHB)+MULT8MSK)) & ~MULT8MSK)
#define kshb_SIG_VALUE  0x52000000      /* Swap. heap block signature */

/***
*   MACRO:    kshPgRoundUp
*
*   FUNCTION: given size, round up value (if neeeded) to next
*               multiple of 0x1000 (page boundary)
*
*   INPUT:    x - unsigned int offset
*
*   RETURNS:  x rounded up (if needed) to the next page boundary)
*/

#define kshPgRoundUp(x)    (((x) + (PAGESIZE-1)) & ~(PAGESIZE-1))

/* end */

/***LP   kshWriteKSHB
 *
 *    This function stores the specified ulong value in the specified
 *    kernel resident heap ulong.  The target ulong may belong to a read-write
 *    or read-only heap.  Parameters are assuned to be valid.
 *
 *    void vmWriteULKRHB(VMKRH *pkrh, void *pul, ulong_t ulValue)
 *
 *    ENTRY           ph              - pointer to heap header
 *                    pb              - pointer to area to store data
 *                    f               - flag of heap (read/write or readonly)
 *                    pbi             - pointer to information block
 *                    cbr             - KSH block size to be stored
 *                    hobo            - hobowner to be stored
 *                    tmp             - temporary storage value
 *    RETURN          void            - Any error causes a page fault
 *
 *    WARNING:  This function is implemented as a macro.
 *
 */

#define kshWriteKSHB(ph,pb,f,pbi,cbr,hobo,tmp)                      \
{                                                                   \
    if ( (ph)->ksh_fl & PG_W)                                       \
    {                                                               \
        (pb)->kshb_size = (cbr);                                    \
        (pb)->kshb_hobowner=(hobo);                                 \
        if ((f) & VMAC_SELALLOC)                                    \
        {                                                           \
            (pb)->kshb_sel = (pbi)->khbi_sel;                       \
        }                                                           \
        else                                                        \
        {                                                           \
            (pb)->kshb_sel = 0;                                     \
        }                                                           \
    }                                                               \
    else                                                            \
    {                                                               \
        VMSetReadOnlyUL(&( (pb)->kshb_size),(cbr));                 \
        if( (f) & VMAC_SELALLOC)                                    \
        {                                                           \
            (tmp) = pkhbi->khbi_sel << 16;                          \
        }                                                           \
        else                                                        \
        {                                                           \
            (tmp) = 0x0L;                                           \
        }                                                           \
        (tmp) += (hobo);                                            \
        VMSetReadOnlyUL(&( (pb)->kshb_hobowner),(tmp) );            \
    }                                                               \
}

/* end */


/***LP  kshbSetSize - return the size of the given block
 *
 *      Given a pointer to a kshb and a new size, set the kshb->ksh_size
 *      variables to the new size, if STRICT checking set the signature
 *      bits in the size field
 *
 *
 *      kshSize (pkshb)
 *
 *      ENTRY   pkshb     - pointer to KSH Block Descriptor
 *              cb        - byte count
 *      RETURN  ulong_t   - size of the block in bytes
 *
 *      CALLS   NONE
 *
 *      WARNING This function is implemented as a macro.
 *
 *      EFFECTS NONE
 */
#define kshbSetSize(cb)   ((cb) | kshb_SIG_VALUE)


/***LP  kshSize - return the size of the given block
 *
 *      This function returns the size in bytes of the given block.
 *
 *      kshSize (pkshb)
 *
 *      ENTRY   pkshb     - pointer to Block Descriptor
 *      RETURN  ulong_t   - size of the block in bytes
 *
 *      CALLS   NONE
 *
 *      WARNING This function is implemented as a macro.
 *
 *      EFFECTS NONE
 */
#define kshbSize(pkshb) (((pkshb)->kshb_size) & ~kshb_SIG_VALUE)




/***LT+ Kernel Heap Header */

struct vmkh_s
  {
    ulong_t     kh_fl;
    union
      {
        VMKRH   *_kh_pkrh;
        VMKSH   *_kh_pksh;
      } kh_union0;
  };

typedef struct vmkh_s VMKH;

#define kh_pkrh kh_union0._kh_pkrh
#define kh_pksh kh_union0._kh_pksh

/*end*/

/***LD+ Global heap data common to both resident and swappable heaps */

extern VMHKH    hkhCurrMax;             /* Current maximum heap handle */
extern ulong_t vmladdrMinKH;            /* Minimum heap address */
extern ulong_t vmladdrMaxKH;            /* Maximum heap address */
extern ulong_t  vmkhGflags;             /* Global heap flags */
extern VMKH     apkh[hkh_MAX + 1];      /* Array of heap header pointers */
/*end*/

/***LP+ Local heap procedures (not implemented as macros) */



/***LP+ Local heap procedures (not implemented as macros) */
extern int vmDonateFragKRH(char *pb, ulong_t cb, ulong_t fl);

extern int vmDonateFragKSH(char *pbRegion, ulong_t cbRegion, ulong_t fl);

extern int vmDonateFragKH(char *pbRegion, ulong_t cbRegion, ulong_t fl);

extern ulong_t vmRoundReqKRHB(ulong_t cb, ulong_t fl);

extern void vmSetOwnerKRHB(VMKRH *pkrh, char *pb, VMHOB hobOwner);

extern void vmSetAttrKRHB(VMKRH *, char *, VMKHBA *);

extern void vmGetAttrKRHB(char *, VMKHBA *);

extern int  vmCopyKHB(char *pbDest, char *pbSrc, ulong_t cb, ulong_t fl);

extern void vmCreateKRHB(register VMKRH *pkrh,
                         register char *pb,
                         register ulong_t cb,
                         VMKHBA *pkhba,
                         ulong_t fl);
extern char *vmYieldKRHB(VMKRH *pkrh, char *pb);
extern void vmCoalesceKRHB(VMKRH *pkrh, char *pb, ulong_t fl);
extern void vmCarveKRHB(VMKRH *pkrh,
                        register char *pb,
                        register ulong_t cbFirst,
                        register ulong_t cbTotal,
                        VMKHBA *pkhba,
                        ulong_t fl);
extern void vmGrowKRHB(VMKRH *pkrh, char *pb, ulong_t cbNew);
extern void vmRelinkFreeKRHB(VMKRH *pkrh, char *pb, ulong_t cbOld);
extern void vmInsertFreeKRHB(VMKRH *pkrh, char *pb);
extern void vmRemoveFreeKRHB(VMKRH *pkrh, char *pb);
extern void vmDecommitKRHB(VMKRH *pkrh, char *pb);
extern int vmCommitSubKRHB(VMKRH *pkrh,
                           char *pb,
                           ulong_t cbRound,
                           ulong_t cbAvail,
                           ulong_t fl);
extern int vmCommitSubAllocKRHB(VMKRH *pkrh,
                                 char *pb,
                                 char *pbAlloc,
                                 char *pbResid,
                                 ulong_t cbAvail,
                                 ulong_t fl);
extern VMKRHS *vmFirstPKRHS(VMKRH *pkrh, ulong_t cb);
extern VMKRHS *vmSizeToPKRHS(VMKRH *pkrh, ulong_t cb);
extern int vmIsValidKRH(VMKRH *pkrh);
extern int vmCreateKSH(ulong_t cb,
                ulong_t fl,
                VMHOB hobowner,
                VMHKH *phkh);

extern int vmAllocKSHB( VMHKH hkh,
                ulong_t cbReq,
                ulong_t fl,
                VMHOB   hobowner,
                void *ppb);

extern int vmReallocKSHB(VMHKH hkh,
                void **ppbData,
                ulong_t cb,
                ulong_t fl);

extern void vmShrinkKSHB(VMHKH hkh,
                void *pb,
                ulong_t cb);

extern void vmFreeKSHB(VMHKH hkh,
                void *pb);

extern int vmFindKSHB(VMKHBI *pkhbi);

extern int vmIsValidKSH(VMKSH *pksh);

extern void vmInitKSHDesc(VMKSHD *pkshd,
                          VMKSHD *pkshdNext,
                          char *pb,
                          ulong_t cb,
                          ulong_t fl,
                          VMHOB hobOwner);
/*end*/

// PERF - defect 98488
extern VMKSHD *pkshdVMDescs;        // Pointer to BMP32 package

// BUGBUG: defined for semaphore code, so that a unigue BMP package could be
//         allocated for the openq semaphores (if needed)

#define pBMPOpenQSem pkshdVMDescs   // defined
// end 98488

