home *** CD-ROM | disk | FTP | other *** search
- /***
- * vm.c -
- *
- * Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
- *
- *Purpose:
- *
- * PUBLIC Functions:
- *
- * FVmInitialize
- * This function initializes the virtual memory manager.
- *
- * VmTerminate
- * This function terminates the virtual memory manager. All
- * resources allocated by the VMM are released.
- *
- * FVmAllocatePageVp
- * This function will allocate a virtual page at a specific
- * virtual address. The page must not allocated already.
- *
- * VpVmAllocatePage
- * This function allocates a virtual page and returns the virtual
- * address of the allocated block.
- *
- * PVmLoadVp
- * This function returns the physical address for a virtual page.
- * If the page is not already present in memory, the page is loaded.
- *
- * PRIVATE Functions:
- *
- * FVmSwapInPage
- * This function loads a specific virtual page into a specific
- * physical page.
- *
- * LOCAL Functions:
- *
- * PVmLoadVpEms
- * This function maps a virtual page stored in EMS into the EMS
- * page frame.
- *
- *******************************************************************************/
-
- #pragma title("Virtual Memory Manager")
- #pragma subtitle("Core routines")
-
- #include <version.h>
- #include <system.h>
- #include <error.h>
- #include <vmassert.h>
- #include <vm.h>
- #include <vmm.h>
- #include <vmp.h>
- #include <vmlist.h>
-
- #include <limits.h>
- #include <stdlib.h>
-
-
- PT _far _ptRoot;
- VPVOID _vpAllocNext;
-
- unsigned _near _timeCur; /* Current timestamp value */
-
- unsigned _near _fVmInit = 0; /* TRUE when VM is initialized */
- VPVOID const _hbkMin = (VPVOID)vpptMax; /* lowest legal handle address */
- VPVOID const _hbkMax = (VPVOID)vpMax; /* highest legal handle address */
-
- #ifdef VMDEBUG
-
- int _near _fVmFillPages = TRUE;
- char _near _bVmFillPages = 0xf;
-
- #endif /* VMDEBUG */
-
- #if VMPROFILE
-
- int _near _fVmProfile;
- unsigned long _near _cVmRefPage;
- unsigned long _near _cVmRefPageEms;
- unsigned long _near _cVmHitPage;
- unsigned long _near _cVmHitPageEms;
-
- #endif /* VMPROFILE */
-
- #if VMTRACE
-
- int _near _fVmTrace = 0;
-
- #endif /* VMTRACE */
-
- PFBD _pfbdVirtHead = pfbdNil;
- PFBD _pfbdVirtCurr = pfbdNil;
- unsigned long _cVirtPageMax = 0;
-
-
- #pragma page()
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * FVmInitialize
- *
- * This function initializes the virtual memory manager.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Entry Conditions:
- *
- * The parameter cVmParaMin is the minimum number of paragraphs
- * to be allocated from conventional DOS memory.
- *
- * Parameter ParaVmDosMax is the maximum number of paragraphs
- * of conventional DOS memory to use.
- *
- * The bitSwapArea parameter indicates which memory storage types
- * to use for swapping.
- *
- * The virtual memory manager must not have been previously
- * initialized without an intermediate call to VmTerminate.
- *
- *
- * Exit Conditions:
- *
- * The function returns TRUE if the initialization is successful.
- * Otherwise it returns FALSE. Initialization can fail if there is
- * not enough available DOS memory to allocate the miniumum number
- * of pages or if there is not enough memory in the near heap to
- * allocate the page descriptors for the minimum number of pages.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
- int PUBLIC __FVmInitialize(unsigned cVmParaMin, unsigned cParaVmDosMax,
- unsigned bitSwapArea)
- {
- unsigned iPage;
-
- VmTracePrintf(("FVmInitialize\n"));
-
- if (_fVmInit)
- return FALSE;
-
- /* fail if bad swap flags passed in */
- if (bitSwapArea & ~bitUseAll || !bitSwapArea)
- return FALSE;
-
- /* Set the appropriate swap area flags (all are enabled by default) */
-
- if (!(bitSwapArea & fUseEMS))
- _fVmDisableEms = TRUE;
- else _fVmDisableEms = FALSE; /* JWM */
-
- if (!(bitSwapArea & fUseXMS))
- _fVmDisableXms = TRUE;
- else _fVmDisableXms = FALSE; /* JWM */
-
- if (!(bitSwapArea & fUseDisk))
- _fVmDisableDisk = TRUE;
- else _fVmDisableDisk = FALSE; /* JWM */
-
-
- #if defined(OS2)
- if (_osmode == DOS_MODE)
- #endif /* defined(OS2) */
- {
- /* Initialize physical memory manager */
-
- if (!__FVmInitializePhys(cVmParaMin, cParaVmDosMax))
- return(FALSE); /* It failed. Pass this on. */
-
- /* Initialize swap code */
-
- __VmInitializeEms();
- __VmInitializeXms();
- __VmInitializeDisk();
- }
-
- /* Initialize the root page table */
-
- for (iPage = 0; iPage < (cbVmPage / sizeof(PTE)); iPage++)
- _ptRoot[iPage] = (PTE) 0;
-
- _vpAllocNext = vpptMax; /* First virtual address to allocate */
-
- #if VMPROFILE
-
- _cVmRefPage = 0;
- _cVmRefPageEms = 0;
- _cVmHitPage = 0;
- _cVmHitPageEms = 0;
-
- #endif /* VMPROFILE */
-
- _fVmInit = TRUE;
-
- return(TRUE);
- }
-
- #pragma page()
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * VmTerminate
- *
- * This function terminates the virtual memory manager. All
- * resources allocated by the VMM are released.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Entry Conditions:
- *
- * The virtual memory manager must have previously been initialized
- * by a successful call to FVmInitialize.
- *
- *
- * Exit Conditions:
- *
- * All resources allocated by the virtual memory manager have been
- * released.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
- void PUBLIC __VmTerminate(void)
- {
- VmTracePrintf(("VmTerminate\n"));
-
- if (!_fVmInit)
- return;
-
- VmProfilePrintf(("VmProfile:\t_cVmRefPage = %lu, _cVmHitPage = %lu\n"
- "\t\t_cVmRefPageEms = %lu, _cVmHitPageEms = %lu\n",
- _cVmRefPage, _cVmHitPage, _cVmRefPageEms, _cVmHitPageEms));
-
- #if defined(OS2)
- if (_osmode == DOS_MODE)
- #endif /* defined(OS2) */
- {
- __VmTerminatePhys();
-
- __VmTerminateDisk();
- __VmTerminateXms();
- __VmTerminateEms();
- __VmFreeFreeBlock(&_pfbdVirtHead, &_pfbdVirtCurr, &_cVirtPageMax);
- }
-
- _fVmInit = FALSE;
- }
-
-
- #pragma page()
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * FVmSwapInPage
- *
- * This function loads a specific virtual page into a specific
- * physical page.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Entry Conditions:
- *
- * The pte parameter is the page table entry describing the page to
- * be loaded. The hpgd parameter is the handle to the physical page
- * into which the virtual page is to be loaded. The vp parameter is
- * the virtual address of the page being loaded.
- *
- *
- * Exit Conditions:
- *
- * If successful, the virtual page is loaded into memory and the
- * function returns TRUE. If not successful, the function returns
- * FALSE.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
- static char CODECONST rgbMagic[7] = "\x56\x4d\x42\x59\x52\x4d\x53";
-
-
- int PRIVATE __FVmSwapInPage(PTE pte, HPGD hpgd)
- {
- int fSuccessful;
-
- VmTracePrintf(("FVmSwapInPage: pte = %08lX, hpgd = %04X\n", pte, (unsigned) hpgd));
-
- Assert(PpgdOfHpgd(hpgd)->Flags & fAllocatedPgd);
-
- Assert(pte & (fEmsPte | fXmsPte | fDiskPte));
-
- if (pte & fUnreferencedPte)
- {
- #ifdef VMDEBUG
- /*
- * If debug version and _fVmFillPages then fill page with
- * filler byte to help trap references to uninitialized
- * virtual memory.
- */
-
- if (_fVmFillPages)
- {
- unsigned cb;
- char _far * pb = PPageOfHpgd(hpgd);
-
- for (cb = cbVmPage; cb != 0; cb--)
- *pb++ = _bVmFillPages;
- }
- #endif /* VMDEBUG */
-
- fSuccessful = TRUE;
- }
-
- else if (pte & fXmsPte)
- fSuccessful = __FVmSwapInXmsPage(pte, hpgd);
-
- else if (pte & fEmsPte)
- fSuccessful = __FVmSwapInEmsPage(pte, hpgd);
-
- else
- {
- Assert(pte & fDiskPte);
-
- fSuccessful = __FVmSwapInDiskPage(pte, hpgd);
- }
-
- return(fSuccessful);
- }
-
-
- #pragma page()
-
- /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * PVmLoadVp
- *
- * This function returns the physical address for a virtual page.
- * If the page is not already present in memory, the page is loaded.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- * Entry Conditions:
- *
- * The vp parameter is the virtual address of the byte to be loaded.
- * The fDirty paraneter indicates whether the page should be considered
- * dirty and swapped out instead of discarded should the physical page
- * in which it resides be needed.
- *
- *
- * Exit Conditions:
- *
- * If successful, the virtual page containing this byte is loaded
- * into memory and the function returns the address of this byte. If
- * not successful, the function returns NULL.
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
- PVOID PUBLIC __PVmLoadVp(VPVOID vp, int fDirty)
- {
- HPGD hpgd;
- PPTE ppte;
- PTE pte;
- unsigned ipgd;
-
- VmTracePrintf(("PVmLoadVp: vp = %08lX, fDirty = %u.\n", vp, fDirty));
-
- Assert((vp >= (VPVOID)cbVmPage) && (vp < vpMax));
- Assert(_osmode == DOS_MODE);
-
-
- /* Check if resident. If so, return pointer to current location */
-
- if ((hpgd = __HpgdSearchCache(vp)) != hpgdNil)
- {
- #if VMPROFILE
- _cVmHitPage++;
- #endif /* VMPROFILE */
-
- goto ProcessHit;
- }
-
-
- /* Load page table entry for this page to determine current location */
- /* This page better have been allocated previously */
-
- if (vp < vpptMax)
- ppte = &_ptRoot[PageOfVp(vp)];
-
- else
- {
- ppte = __PVmLoadVp(VppteOfVp(vp), FALSE);
- Assert(ppte != NULL);
- // can't load page table or trying to load unallocated page
- if (ppte == NULL || !(*ppte & fAllocatedPte))
- return(NULL);
- }
-
- pte = *ppte; /* Save in case of swapping below */
- Assert(pte & fAllocatedPte);
-
- if (pte & fUnreferencedPte)
- {
- if (vp >= vpptMax) /* Don't mark _ptRoot as dirty */
- __PVmLoadVp(VppteOfVp(vp), TRUE); /* Mark page as dirty */
-
- *ppte &= ~fUnreferencedPte; /* No longer unreferenced. */
- }
-
- hpgd = __HpgdVmAllocate(1); /* Allocate a physical page */
- if (hpgd == hpgdNil) /* Can't allocate physical page */
- {
- *ppte = pte; /* Restore fUnreferencedPte */
- return(NULL);
- }
-
- __FVmSwapInPage(pte, hpgd); /* Load page into memory */
-
- PpgdOfHpgd(hpgd)->vp = VpPageOfVp(vp); /* Associate with this virtual page */
- PpgdOfHpgd(hpgd)->pte = pte & ~fUnreferencedPte;
-
- /*
- * The PGD returned by HpgdVmAllocateEms and HpgdVmAllocate will have
- * already been unlinked from the hash table. It is necessary to
- * restore it so it will be found by subsequent calls. Linking
- * to the front of the chain will make lookup faster on the
- * assumption that recently referenced pages are more likely to
- * be referenced.
- */
-
- PpgdOfHpgd(hpgd)->hpgdHashNext = _rghpgdHash[ipgd = IpgdHashOfVp(PpgdOfHpgd(hpgd)->vp)];
- _rghpgdHash[ipgd] = hpgd;
-
- ProcessHit:
- if (++_timeCur == UINT_MAX)
- __VmUpdateTimestamps();
-
- PpgdOfHpgd(hpgd)->timeRef = _timeCur;
-
- if (fDirty) /* Mark page as dirty if requested */
- PpgdOfHpgd(hpgd)->Flags |= fDirtyPgd;
-
-
- #if VMPROFILE
- _cVmRefPage++;
- #endif /* VMPROFILE */
-
-
- return(PPageOfHpgd(hpgd)+IbOfVp(vp));
- }
-