home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / library / mslang / vm / src / vm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  11.7 KB  |  450 lines

  1. /***
  2. * vm.c -
  3. *
  4. *       Copyright (c) 1989-1992, Microsoft Corporation.  All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. * PUBLIC Functions:
  9. *
  10. *       FVmInitialize
  11. *       This function initializes the virtual memory manager.
  12. *
  13. *       VmTerminate
  14. *       This function terminates the virtual memory manager.  All
  15. *       resources allocated by the VMM are released.
  16. *
  17. *       FVmAllocatePageVp
  18. *       This function will allocate a virtual page at a specific
  19. *       virtual address.  The page must not allocated already.
  20. *
  21. *       VpVmAllocatePage
  22. *       This function allocates a virtual page and returns the virtual
  23. *       address of the allocated block.
  24. *
  25. *       PVmLoadVp
  26. *       This function returns the physical address for a virtual page.
  27. *       If the page is not already present in memory, the page is loaded.
  28. *
  29. * PRIVATE Functions:
  30. *
  31. *       FVmSwapInPage
  32. *       This function loads a specific virtual page into a specific
  33. *       physical page.
  34. *
  35. * LOCAL Functions:
  36. *
  37. *       PVmLoadVpEms
  38. *       This function maps a virtual page stored in EMS into the EMS
  39. *       page frame.
  40. *
  41. *******************************************************************************/
  42.  
  43. #pragma title("Virtual Memory Manager")
  44. #pragma subtitle("Core routines")
  45.  
  46. #include <version.h>
  47. #include <system.h>
  48. #include <error.h>
  49. #include <vmassert.h>
  50. #include <vm.h>
  51. #include <vmm.h>
  52. #include <vmp.h>
  53. #include <vmlist.h>
  54.  
  55. #include <limits.h>
  56. #include <stdlib.h>
  57.  
  58.  
  59. PT       _far  _ptRoot;
  60. VPVOID _vpAllocNext;
  61.  
  62. unsigned _near _timeCur;               /* Current timestamp value */
  63.  
  64. unsigned _near _fVmInit = 0; /* TRUE when VM is initialized */
  65. VPVOID const _hbkMin = (VPVOID)vpptMax;   /* lowest legal handle address */
  66. VPVOID const _hbkMax = (VPVOID)vpMax;     /* highest legal handle address */
  67.  
  68. #ifdef  VMDEBUG
  69.  
  70. int      _near _fVmFillPages = TRUE;
  71. char     _near _bVmFillPages = 0xf;
  72.  
  73. #endif  /* VMDEBUG */
  74.  
  75. #if     VMPROFILE
  76.  
  77. int            _near _fVmProfile;
  78. unsigned long  _near _cVmRefPage;
  79. unsigned long  _near _cVmRefPageEms;
  80. unsigned long  _near _cVmHitPage;
  81. unsigned long  _near _cVmHitPageEms;
  82.  
  83. #endif  /* VMPROFILE */
  84.  
  85. #if     VMTRACE
  86.  
  87. int      _near _fVmTrace = 0;
  88.  
  89. #endif  /* VMTRACE */
  90.  
  91. PFBD _pfbdVirtHead = pfbdNil;
  92. PFBD _pfbdVirtCurr = pfbdNil;
  93. unsigned long _cVirtPageMax = 0;
  94.  
  95.  
  96. #pragma page()
  97.  
  98. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  99.  *
  100.  *                         FVmInitialize
  101.  *
  102.  *     This function initializes the virtual memory manager.
  103.  *
  104.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  105.  *
  106.  * Entry Conditions:
  107.  *
  108.  *    The parameter cVmParaMin is the minimum number of paragraphs
  109.  * to be allocated from conventional DOS memory.
  110.  *
  111.  *    Parameter ParaVmDosMax is the maximum number of paragraphs
  112.  * of conventional DOS memory to use.
  113.  *
  114.  *    The bitSwapArea parameter indicates which memory storage types
  115.  * to use for swapping.
  116.  *
  117.  *    The virtual memory manager must not have been previously
  118.  * initialized without an intermediate call to VmTerminate.
  119.  *
  120.  *
  121.  * Exit Conditions:
  122.  *
  123.  *    The function returns TRUE if the initialization is successful.
  124.  * Otherwise it returns FALSE.  Initialization can fail if there is
  125.  * not enough available DOS memory to allocate the miniumum number
  126.  * of pages or if there is not enough memory in the near heap to
  127.  * allocate the page descriptors for the minimum number of pages.
  128.  *
  129.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  130.  
  131.  
  132. int PUBLIC __FVmInitialize(unsigned cVmParaMin, unsigned cParaVmDosMax,
  133.     unsigned bitSwapArea)
  134. {
  135.    unsigned iPage;
  136.  
  137.    VmTracePrintf(("FVmInitialize\n"));
  138.  
  139.    if (_fVmInit)
  140.       return FALSE;
  141.  
  142.    /* fail if bad swap flags passed in */
  143.    if (bitSwapArea & ~bitUseAll || !bitSwapArea)
  144.       return FALSE;
  145.  
  146.    /* Set the appropriate swap area flags (all are enabled by default) */
  147.  
  148.    if (!(bitSwapArea & fUseEMS))
  149.      _fVmDisableEms = TRUE;
  150.    else _fVmDisableEms = FALSE;                 /* JWM */
  151.  
  152.    if (!(bitSwapArea & fUseXMS))
  153.      _fVmDisableXms = TRUE;
  154.    else _fVmDisableXms = FALSE;                 /* JWM */
  155.  
  156.    if (!(bitSwapArea & fUseDisk))
  157.      _fVmDisableDisk = TRUE;
  158.    else _fVmDisableDisk = FALSE;                        /* JWM */
  159.  
  160.  
  161. #if defined(OS2)
  162.    if (_osmode == DOS_MODE)
  163. #endif /* defined(OS2) */
  164.    {
  165.       /* Initialize physical memory manager */
  166.  
  167.       if (!__FVmInitializePhys(cVmParaMin, cParaVmDosMax))
  168.      return(FALSE);                /* It failed.  Pass this on. */
  169.  
  170.       /* Initialize swap code */
  171.  
  172.       __VmInitializeEms();
  173.       __VmInitializeXms();
  174.       __VmInitializeDisk();
  175.    }
  176.  
  177.    /* Initialize the root page table */
  178.  
  179.    for (iPage = 0; iPage < (cbVmPage / sizeof(PTE)); iPage++)
  180.       _ptRoot[iPage] = (PTE) 0;
  181.  
  182.    _vpAllocNext = vpptMax;             /* First virtual address to allocate */
  183.  
  184. #if     VMPROFILE
  185.  
  186.    _cVmRefPage    = 0;
  187.    _cVmRefPageEms  = 0;
  188.    _cVmHitPage    = 0;
  189.    _cVmHitPageEms  = 0;
  190.  
  191. #endif  /* VMPROFILE */
  192.  
  193.    _fVmInit = TRUE;
  194.  
  195.    return(TRUE);
  196. }
  197.  
  198. #pragma page()
  199.  
  200. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  201.  *
  202.  *                          VmTerminate
  203.  *
  204.  *     This function terminates the virtual memory manager.  All
  205.  *   resources allocated by the VMM are released.
  206.  *
  207.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  208.  *
  209.  * Entry Conditions:
  210.  *
  211.  *    The virtual memory manager must have previously been initialized
  212.  * by a successful call to FVmInitialize.
  213.  *
  214.  *
  215.  * Exit Conditions:
  216.  *
  217.  *    All resources allocated by the virtual memory manager have been
  218.  * released.
  219.  *
  220.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  221.  
  222.  
  223. void PUBLIC __VmTerminate(void)
  224. {
  225.    VmTracePrintf(("VmTerminate\n"));
  226.  
  227.    if (!_fVmInit)
  228.       return;
  229.  
  230.    VmProfilePrintf(("VmProfile:\t_cVmRefPage = %lu, _cVmHitPage = %lu\n"
  231.             "\t\t_cVmRefPageEms = %lu, _cVmHitPageEms = %lu\n",
  232.             _cVmRefPage, _cVmHitPage, _cVmRefPageEms, _cVmHitPageEms));
  233.  
  234. #if defined(OS2)
  235.    if (_osmode == DOS_MODE)
  236. #endif /* defined(OS2) */
  237.    {
  238.       __VmTerminatePhys();
  239.  
  240.       __VmTerminateDisk();
  241.       __VmTerminateXms();
  242.       __VmTerminateEms();
  243.         __VmFreeFreeBlock(&_pfbdVirtHead, &_pfbdVirtCurr, &_cVirtPageMax);
  244.    }
  245.  
  246.    _fVmInit = FALSE;
  247. }
  248.  
  249.  
  250. #pragma page()
  251.  
  252. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  253.  *
  254.  *                         FVmSwapInPage
  255.  *
  256.  *     This function loads a specific virtual page into a specific
  257.  *   physical page.
  258.  *
  259.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  260.  *
  261.  * Entry Conditions:
  262.  *
  263.  *    The pte parameter is the page table entry describing the page to
  264.  * be loaded.  The hpgd parameter is the handle to the physical page
  265.  * into which the virtual page is to be loaded.  The vp parameter is
  266.  * the virtual address of the page being loaded.
  267.  *
  268.  *
  269.  * Exit Conditions:
  270.  *
  271.  *    If successful, the virtual page is loaded into memory and the
  272.  * function returns TRUE.  If not successful, the function returns
  273.  * FALSE.
  274.  *
  275.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  276.  
  277.  
  278. static char CODECONST rgbMagic[7] = "\x56\x4d\x42\x59\x52\x4d\x53";
  279.  
  280.  
  281. int PRIVATE __FVmSwapInPage(PTE pte, HPGD hpgd)
  282. {
  283.    int   fSuccessful;
  284.  
  285.    VmTracePrintf(("FVmSwapInPage: pte = %08lX, hpgd = %04X\n", pte, (unsigned) hpgd));
  286.  
  287.    Assert(PpgdOfHpgd(hpgd)->Flags & fAllocatedPgd);
  288.  
  289.    Assert(pte & (fEmsPte | fXmsPte | fDiskPte));
  290.  
  291.    if (pte & fUnreferencedPte)
  292.    {
  293. #ifdef  VMDEBUG
  294.       /*
  295.        *  If debug version and _fVmFillPages then fill page with
  296.        *  filler byte to help trap references to uninitialized
  297.        *  virtual memory.
  298.        */
  299.  
  300.       if (_fVmFillPages)
  301.       {
  302.      unsigned    cb;
  303.      char _far * pb = PPageOfHpgd(hpgd);
  304.  
  305.      for (cb = cbVmPage; cb != 0; cb--)
  306.         *pb++ = _bVmFillPages;
  307.       }
  308. #endif  /* VMDEBUG */
  309.  
  310.       fSuccessful = TRUE;
  311.    }
  312.  
  313.    else if (pte & fXmsPte)
  314.       fSuccessful = __FVmSwapInXmsPage(pte, hpgd);
  315.  
  316.    else if (pte & fEmsPte)
  317.      fSuccessful = __FVmSwapInEmsPage(pte, hpgd);
  318.  
  319.    else
  320.    {
  321.       Assert(pte & fDiskPte);
  322.  
  323.       fSuccessful = __FVmSwapInDiskPage(pte, hpgd);
  324.    }
  325.  
  326.    return(fSuccessful);
  327. }
  328.  
  329.  
  330. #pragma page()
  331.  
  332. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  333.  *
  334.  *                         PVmLoadVp
  335.  *
  336.  *     This function returns the physical address for a virtual page.
  337.  *   If the page is not already present in memory, the page is loaded.
  338.  *
  339.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  340.  *
  341.  * Entry Conditions:
  342.  *
  343.  *    The vp parameter is the virtual address of the byte to be loaded.
  344.  * The fDirty paraneter indicates whether the page should be considered
  345.  * dirty and swapped out instead of discarded should the physical page
  346.  * in which it resides be needed.
  347.  *
  348.  *
  349.  * Exit Conditions:
  350.  *
  351.  *    If successful, the virtual page containing this byte is loaded
  352.  * into memory and the function returns the address of this byte.  If
  353.  * not successful, the function returns NULL.
  354.  *
  355.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  356.  
  357.  
  358. PVOID PUBLIC __PVmLoadVp(VPVOID vp, int fDirty)
  359. {
  360.    HPGD     hpgd;
  361.    PPTE     ppte;
  362.    PTE      pte;
  363.    unsigned ipgd;
  364.  
  365.    VmTracePrintf(("PVmLoadVp: vp = %08lX, fDirty = %u.\n", vp, fDirty));
  366.  
  367.    Assert((vp >= (VPVOID)cbVmPage) && (vp < vpMax));
  368.    Assert(_osmode == DOS_MODE);
  369.  
  370.  
  371.    /* Check if resident.  If so, return pointer to current location */
  372.  
  373.    if ((hpgd = __HpgdSearchCache(vp)) != hpgdNil)
  374.    {
  375. #if     VMPROFILE
  376.      _cVmHitPage++;
  377. #endif  /* VMPROFILE */
  378.  
  379.       goto ProcessHit;
  380.    }
  381.  
  382.  
  383.     /* Load page table entry for this page to determine current location */
  384.     /* This page better have been allocated previously */
  385.  
  386.     if (vp < vpptMax)
  387.         ppte = &_ptRoot[PageOfVp(vp)];
  388.  
  389.    else
  390.     {
  391.         ppte = __PVmLoadVp(VppteOfVp(vp), FALSE);
  392.         Assert(ppte != NULL);
  393.         // can't load page table or trying to load unallocated page
  394.         if (ppte == NULL || !(*ppte & fAllocatedPte))
  395.             return(NULL);
  396.     }
  397.  
  398.    pte = *ppte;                        /* Save in case of swapping below */
  399.    Assert(pte & fAllocatedPte);
  400.  
  401.    if (pte & fUnreferencedPte)
  402.    {
  403.       if (vp >= vpptMax)               /* Don't mark _ptRoot as dirty */
  404.      __PVmLoadVp(VppteOfVp(vp), TRUE);  /* Mark page as dirty */
  405.  
  406.       *ppte &= ~fUnreferencedPte;      /* No longer unreferenced. */
  407.    }
  408.  
  409.    hpgd = __HpgdVmAllocate(1);         /* Allocate a physical page */
  410.    if (hpgd == hpgdNil)                /* Can't allocate physical page */
  411.    {
  412.       *ppte = pte;                     /* Restore fUnreferencedPte */
  413.       return(NULL);
  414.    }
  415.  
  416.    __FVmSwapInPage(pte, hpgd);         /* Load page into memory */
  417.  
  418.    PpgdOfHpgd(hpgd)->vp  = VpPageOfVp(vp); /* Associate with this virtual page */
  419.    PpgdOfHpgd(hpgd)->pte = pte & ~fUnreferencedPte;
  420.  
  421.    /*
  422.     *  The PGD returned by HpgdVmAllocateEms and HpgdVmAllocate will have
  423.     *  already been unlinked from the hash table.  It is necessary to
  424.     *  restore it so it will be found by subsequent calls.  Linking
  425.     *  to the front of the chain will make lookup faster on the
  426.     *  assumption that recently referenced pages are more likely to
  427.     *  be referenced.
  428.     */
  429.  
  430.    PpgdOfHpgd(hpgd)->hpgdHashNext = _rghpgdHash[ipgd = IpgdHashOfVp(PpgdOfHpgd(hpgd)->vp)];
  431.    _rghpgdHash[ipgd] = hpgd;
  432.  
  433. ProcessHit:
  434.     if (++_timeCur == UINT_MAX)
  435.         __VmUpdateTimestamps();
  436.  
  437.     PpgdOfHpgd(hpgd)->timeRef = _timeCur;
  438.  
  439.     if (fDirty)                    /* Mark page as dirty if requested */
  440.         PpgdOfHpgd(hpgd)->Flags |= fDirtyPgd;
  441.  
  442.  
  443. #if     VMPROFILE
  444.      _cVmRefPage++;
  445. #endif  /* VMPROFILE */
  446.  
  447.  
  448.    return(PPageOfHpgd(hpgd)+IbOfVp(vp));
  449. }
  450.