home *** CD-ROM | disk | FTP | other *** search
- /***
- * vmalloc.c -
- *
- * Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
- *
- *Purpose:
- *
- * PUBLIC Functions:
- *
- * FVmAllocatePageVp
- * This function will allocate a virtual page at a specific
- * virtual address. The page must not allocated already.
- *
- * VpVmAllocateCb
- * This function allocates a block of pages large enough to store
- * therequested number of bytes and returns the virtual address of
- * this allocation.
- *
- * VpVmAllocatePage
- * This function allocates a virtual page and returns the address
- * ofthis allocation.
- *
- * LOCAL Functions:
- *
- * FVmAllocatePageHelper
- * This function is an internal routine allocates a virtual page
- * data specific address and assigns swap storage if appropriate.
- *
- *******************************************************************************/
-
- #pragma title("Virtual Memory Manager")
- #pragma subtitle("Core routines")
-
- #include <version.h>
- #include <vmassert.h>
- #include <system.h>
- #include <error.h>
- #include <vm.h>
- #include <vmp.h>
- #include <vmlist.h>
-
- #include <stdlib.h>
-
-
- extern VPVOID _vpAllocNext;
-
- int _near _fVmSwapping = TRUE;
-
- extern PFBD _pfbdVirtHead;
- extern PFBD _pfbdVirtCurr;
- extern unsigned long _cVirtPageMax;
-
- #pragma page()
-
- int LOCAL __FVmAllocatePageHelper(PPTE ppte, VPVOID vp)
- {
- VmTracePrintf(("FVmAllocatePageHelper: vp = %08lX.\n", vp));
-
- Assert(!(*ppte & (fAllocatedPte | fXmsPte | fDiskPte)));
-
-
- /* If swap storage has already been allocated for this */
- /* virtual page then just go ahead and use it. */
-
- if (*ppte & (fEmsPte | fXmsPte | fDiskPte))
- {
- *ppte |= fAllocatedPte | fUnreferencedPte;
-
- return(TRUE);
- }
-
-
- Assert(*ppte == 0);
-
- if (!_fVmSwapping)
- {
- HPGD hpgd;
- unsigned ipgd;
-
- /* Note: The following call to HpgdVmAllocate may invalidate the */
- /* Note: ppte parameter. However, if the call fails, then no */
- /* Note: physical memory movement occured and the ppte parameter is */
- /* Note: still valid and can be used to reset the allocated flag. */
-
- *ppte = fAllocatedPte | fUnreferencedPte;
-
- if ((hpgd = __HpgdVmAllocate(1)) != hpgdNil)
- {
- PpgdOfHpgd(hpgd)->vp = vp;
- PpgdOfHpgd(hpgd)->pte = fAllocatedPte;
- PpgdOfHpgd(hpgd)->hpgdHashNext = _rghpgdHash[ipgd = IpgdHashOfVp(vp)];
- _rghpgdHash[ipgd] = hpgd;
- return(TRUE);
- }
-
- *ppte = 0;
-
- _fVmSwapping = TRUE;
- }
-
- /* Once swapping starts, all pages must be assigned swap storage */
- /* before the allocation can be considered successful. */
-
- /* Note: It is necessary to ensure that swap storage is available for */
- /* Note: every virtual page that is allocated or else it isn't */
- /* Note: meaningful to assume that a successful virtual memory */
- /* Note: allocation implies that the virtual memory is available. */
-
- if (!__FVmAllocateEmsPage(ppte, vp))
- if (!__FVmAllocateXmsPage(ppte))
- if (!__FVmAllocateDiskPage(ppte))
- {
- Assert(*ppte == 0);
-
- return(FALSE); /* Can't allocate physical page */
- }
-
- Assert((*ppte & fAllocatedPte) && (*ppte & (fEmsPte | fXmsPte | fDiskPte)));
-
- return(TRUE);
- }
-
- #pragma page()
-
- int PUBLIC __FVmAllocatePageVp(VPVOID vp)
- {
- VPPTE vppte;
- PPTE ppte;
- PPT ppt;
-
- /*
- * Virtual memory is organized into two types. The lower region
- * of memory is occupied by page table pages. Page tables describe
- * pages of virtual memory and how to access those pages. Even
- * the page tables themselves are described by other page tables.
- * The page tables are handled by the virtual memory manager and
- * should not be accessed by the application. The remainder of
- * virtual memory is reserved for the application.
- *
- * The page tables are split into two levels. The first level of
- * page table pages describe themselves and all other page tables.
- * The second level of page tables describe the application region
- * of the virtual address space. In this implementation, the first
- * level of page tables is limited to one page. Based on a page
- * size of 2048 bytes and a page table entry size of four bytes,
- * the virtual memory region reserved for both levels of page tables
- * is 1 megabyte. This also imposes a limit of 511 megabytes on the
- * application region of virtual memory.
- *
- * In order to allocate a page at a specific virtual address in the
- * application region, it is necessary to ensure that the page table
- * page describing this region is allocated. The root page that
- * describes all page table pages is always allocated.
- */
-
-
- VmTracePrintf(("FVmAllocatePageVp: vp = %08lX.\n", vp));
-
- Assert(IbOfVp(vp) == 0); /* Only whole pages can be allocated */
- Assert((vp >= vpptMax) && (vp < vpMax));
-
-
- vppte = VppteOfVp(vp); /* Virtual address of page table entry */
- ppte = &_ptRoot[PageOfVp(vppte)];
-
- if (!(*ppte & fAllocatedPte))
- {
- unsigned iPage;
-
- /* The page table that describes the page to be allocated has not */
- /* yet been allocated. Allocate this page and initialize it. */
-
- if (!__FVmAllocatePageHelper(ppte, VpPageOfVp(vppte)))
- return(FALSE);
-
- ppt = __PVmLoadVp(VpPageOfVp(vppte), TRUE);
-
- for (iPage = 0; iPage < (cbVmPage / sizeof(PTE)); iPage++)
- (*ppt)[iPage] = (PTE) 0;
- }
-
-
- ppte = __PVmLoadVp(vppte, TRUE);
- Assert(ppte != NULL);
- if (ppte == NULL) /* Can't load page table */
- return(FALSE);
-
- if (*ppte & fAllocatedPte) /* Page already allocated */
- return(FALSE);
-
- return(__FVmAllocatePageHelper(ppte, vp));
- }
-
- #pragma page()
-
- VPVOID PUBLIC __VpVmAllocateCb(unsigned long cb)
- {
- unsigned long cPage;
- VPVOID vp;
- VPVOID vpT;
- unsigned long iPage;
- unsigned fNewAlloc = 0;
-
- VmTracePrintf(("VpVmAllocateCb: cb = %08lX.\n", cb));
-
- Assert(cb != 0);
-
- cPage = (unsigned) ((cb + cbVmPage - 1UL) / cbVmPage);
-
- Assert(cPage > 0);
-
- // reallocate freed VM pages
- if (!__VmGetFreeBlock(&_pfbdVirtHead, &_pfbdVirtCurr, &_cVirtPageMax, cPage, &vp))
- {
- fNewAlloc = 1;
- vp = _vpAllocNext;
- }
-
- Assert (vp + cb < vpMax);
-
- RetryAllocation:
-
- vpT = vp;
- for (iPage = 0; iPage < cPage; iPage++)
- {
- if (!__FVmAllocatePageVp(vpT))
- {
- Assert(((vp & 16383UL) == 0) || (iPage == 0));
-
- #if VMFREE
- for (; iPage > 0; iPage--)
- __VmFreePageVp(vpT -= cbVmPage);
- #endif /* VMFREE */
-
- if (vp & 16383UL)
- if ((vp = (vp + 16383UL) & ~16383UL) != (VPVOID) 0)
- goto RetryAllocation;
-
- return(vpNil);
- }
-
- vpT += cbVmPage;
- }
-
- // if this was a 'new' allocation (as opposed to reusing vm space),
- // bump the global alloc pointer. If alloc fails, not changed.
- if (fNewAlloc)
- _vpAllocNext = vpT;
-
- return(vp);
- }
-
- #pragma page()
-
- VPVOID PUBLIC __VpVmAllocatePage(void)
- {
- return(__VpVmAllocateCb(cbVmPage));
- }
-