summaryrefslogtreecommitdiffstats
path: root/private/ntos/mm/i386/init386.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/mm/i386/init386.c')
-rw-r--r--private/ntos/mm/i386/init386.c1326
1 files changed, 1326 insertions, 0 deletions
diff --git a/private/ntos/mm/i386/init386.c b/private/ntos/mm/i386/init386.c
new file mode 100644
index 000000000..2de988056
--- /dev/null
+++ b/private/ntos/mm/i386/init386.c
@@ -0,0 +1,1326 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ init386.c
+
+Abstract:
+
+ This module contains the machine dependent initialization for the
+ memory management component. It is specifically tailored to the
+ INTEL 486 machine.
+
+Author:
+
+ Lou Perazzoli (loup) 6-Jan-1990
+
+Revision History:
+
+--*/
+
+#include "mi.h"
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,MiInitMachineDependent)
+#endif
+
+extern ULONG MmAllocatedNonPagedPool;
+
+#define MM_BIOS_START (0xA0000 >> PAGE_SHIFT)
+#define MM_BIOS_END (0xFFFFF >> PAGE_SHIFT)
+
+
+VOID
+MiInitMachineDependent (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the necessary operations to enable virtual
+ memory. This includes building the page directory page, building
+ page table pages to map the code section, the data section, the'
+ stack section and the trap handler.
+
+ It also initializes the PFN database and populates the free list.
+
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the firmware setup loader block.
+
+Return Value:
+
+ None.
+
+Environment:
+
+ Kernel mode.
+
+--*/
+
+{
+ PMMPFN BasePfn;
+ PMMPFN BottomPfn;
+ PMMPFN TopPfn;
+ BOOLEAN PfnInKseg0 = FALSE;
+ ULONG HighPage;
+ ULONG PagesLeft;
+ ULONG Range;
+ ULONG i, j;
+ ULONG PdePageNumber;
+ ULONG PdePage;
+ ULONG PageFrameIndex;
+ ULONG NextPhysicalPage;
+ ULONG OldFreeDescriptorLowMemCount;
+ ULONG OldFreeDescriptorLowMemBase;
+ ULONG OldFreeDescriptorCount;
+ ULONG OldFreeDescriptorBase;
+ ULONG PfnAllocation;
+ ULONG NumberOfPages;
+ ULONG MaxPool;
+ PEPROCESS CurrentProcess;
+ ULONG DirBase;
+ ULONG MostFreePage = 0;
+ ULONG MostFreeLowMem = 0;
+ PLIST_ENTRY NextMd;
+ PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR FreeDescriptorLowMem;
+ PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
+ MMPTE TempPte;
+ PMMPTE PointerPde;
+ PMMPTE PointerPte;
+ PMMPTE LastPte;
+ PMMPTE Pde;
+ PMMPTE StartPde;
+ PMMPTE EndPde;
+ PMMPFN Pfn1;
+ PMMPFN Pfn2;
+ ULONG va;
+ ULONG SavedSize;
+ KIRQL OldIrql;
+ ULONG MapLargePages = 0;
+ PVOID NonPagedPoolStartVirtual;
+ ULONG LargestFreePfnCount = 0;
+ ULONG LargestFreePfnStart;
+
+ if ( InitializationPhase == 1) {
+
+ if ((KeFeatureBits & KF_LARGE_PAGE) &&
+ (MmNumberOfPhysicalPages > ((31*1024*1024) >> PAGE_SHIFT))) {
+
+ LOCK_PFN (OldIrql);
+
+ //
+ // Map lower 512MB of physical memory as large pages starting
+ // at address 0x80000000
+ //
+
+ PointerPde = MiGetPdeAddress (MM_KSEG0_BASE);
+ LastPte = MiGetPdeAddress (MM_KSEG2_BASE);
+ TempPte = ValidKernelPde;
+ TempPte.u.Hard.PageFrameNumber = 0;
+ TempPte.u.Hard.LargePage = 1;
+
+ do {
+ if (PointerPde->u.Hard.Valid == 1) {
+ PageFrameIndex = PointerPde->u.Hard.PageFrameNumber;
+ Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
+ Pfn1->u2.ShareCount = 0;
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u3.e1.PageLocation = StandbyPageList;
+ MI_SET_PFN_DELETED (Pfn1);
+ MiDecrementReferenceCount (PageFrameIndex);
+ KeFlushSingleTb (MiGetVirtualAddressMappedByPte (PointerPde),
+ TRUE,
+ TRUE,
+ (PHARDWARE_PTE)PointerPde,
+ TempPte.u.Flush);
+ KeFlushEntireTb (TRUE, TRUE); //p6 errata...
+ } else {
+ *PointerPde = TempPte;
+ }
+ TempPte.u.Hard.PageFrameNumber += MM_VA_MAPPED_BY_PDE >> PAGE_SHIFT;
+ PointerPde += 1;
+ } while (PointerPde < LastPte);
+
+ UNLOCK_PFN (OldIrql);
+ MmKseg2Frame = (512*1024*1024) >> PAGE_SHIFT;
+ }
+
+ return;
+ }
+
+ ASSERT (InitializationPhase == 0);
+
+ if (KeFeatureBits & KF_GLOBAL_PAGE) {
+ ValidKernelPte.u.Long |= MM_PTE_GLOBAL_MASK;
+ ValidKernelPde.u.Long |= MM_PTE_GLOBAL_MASK;
+ MmPteGlobal = 1;
+ }
+
+ TempPte = ValidKernelPte;
+
+ PointerPte = MiGetPdeAddress (PDE_BASE);
+
+ PdePageNumber = PointerPte->u.Hard.PageFrameNumber;
+
+ DirBase = PointerPte->u.Hard.PageFrameNumber << PAGE_SHIFT;
+
+ PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = *( (PULONG) &DirBase);
+
+ KeSweepDcache (FALSE);
+
+ //
+ // Unmap low 2Gb of memory.
+ //
+
+ PointerPde = MiGetPdeAddress(0);
+ LastPte = MiGetPdeAddress (MM_HIGHEST_USER_ADDRESS);
+
+ while (PointerPde <= LastPte) {
+ PointerPde->u.Long = 0;
+ PointerPde += 1;
+ }
+
+ //
+ // Get the lower bound of the free physical memory and the
+ // number of physical pages by walking the memory descriptor lists.
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+
+ MemoryDescriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if ((MemoryDescriptor->MemoryType != LoaderFirmwarePermanent) &&
+ (MemoryDescriptor->MemoryType != LoaderSpecialMemory)) {
+
+ MmNumberOfPhysicalPages += MemoryDescriptor->PageCount;
+ if (MemoryDescriptor->BasePage < MmLowestPhysicalPage) {
+ MmLowestPhysicalPage = MemoryDescriptor->BasePage;
+ }
+ if ((MemoryDescriptor->BasePage + MemoryDescriptor->PageCount) >
+ MmHighestPhysicalPage) {
+ MmHighestPhysicalPage =
+ MemoryDescriptor->BasePage + MemoryDescriptor->PageCount -1;
+ }
+
+ //
+ // Locate the largest free block and the largest free block
+ // below 16mb.
+ //
+
+ if ((MemoryDescriptor->MemoryType == LoaderFree) ||
+ (MemoryDescriptor->MemoryType == LoaderLoadedProgram) ||
+ (MemoryDescriptor->MemoryType == LoaderFirmwareTemporary) ||
+ (MemoryDescriptor->MemoryType == LoaderOsloaderStack)) {
+
+ if (MemoryDescriptor->PageCount > MostFreePage) {
+ MostFreePage = MemoryDescriptor->PageCount;
+ FreeDescriptor = MemoryDescriptor;
+ }
+ if (MemoryDescriptor->BasePage < 0x1000) {
+
+ //
+ // This memory descriptor is below 16mb.
+ //
+
+ if ((MostFreeLowMem < MemoryDescriptor->PageCount) &&
+ (MostFreeLowMem < ((ULONG)0x1000 - MemoryDescriptor->BasePage))) {
+
+ MostFreeLowMem = (ULONG)0x1000 - MemoryDescriptor->BasePage;
+ if (MemoryDescriptor->PageCount < MostFreeLowMem) {
+ MostFreeLowMem = MemoryDescriptor->PageCount;
+ }
+ FreeDescriptorLowMem = MemoryDescriptor;
+ }
+ }
+ }
+ }
+
+ NextMd = MemoryDescriptor->ListEntry.Flink;
+ }
+ NextPhysicalPage = FreeDescriptorLowMem->BasePage;
+
+ OldFreeDescriptorLowMemCount = FreeDescriptorLowMem->PageCount;
+ OldFreeDescriptorLowMemBase = FreeDescriptorLowMem->BasePage;
+
+ OldFreeDescriptorCount = FreeDescriptor->PageCount;
+ OldFreeDescriptorBase = FreeDescriptor->BasePage;
+
+ NumberOfPages = FreeDescriptorLowMem->PageCount;
+
+ if (MmNumberOfPhysicalPages < 1100) {
+ KeBugCheckEx (INSTALL_MORE_MEMORY,
+ MmNumberOfPhysicalPages,
+ MmLowestPhysicalPage,
+ MmHighestPhysicalPage,
+ 0);
+ }
+
+ //
+ // Build non-paged pool using the physical pages following the
+ // data page in which to build the pool from. Non-page pool grows
+ // from the high range of the virtual address space and expands
+ // downward.
+ //
+ // At this time non-paged pool is constructed so virtual addresses
+ // are also physically contiguous.
+ //
+
+ if ((MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT) >
+ (7 * (MmNumberOfPhysicalPages << 3))) {
+
+ //
+ // More than 7/8 of memory allocated to nonpagedpool, reset to 0.
+ //
+
+ MmSizeOfNonPagedPoolInBytes = 0;
+ }
+
+ if (MmSizeOfNonPagedPoolInBytes < MmMinimumNonPagedPoolSize) {
+
+ //
+ // Calculate the size of nonpaged pool.
+ // Use the minimum size, then for every MB about 4mb add extra
+ // pages.
+ //
+
+ MmSizeOfNonPagedPoolInBytes = MmMinimumNonPagedPoolSize;
+
+ MmSizeOfNonPagedPoolInBytes +=
+ ((MmNumberOfPhysicalPages - 1024)/256) *
+ MmMinAdditionNonPagedPoolPerMb;
+ }
+
+ if (MmSizeOfNonPagedPoolInBytes > MM_MAX_INITIAL_NONPAGED_POOL) {
+ MmSizeOfNonPagedPoolInBytes = MM_MAX_INITIAL_NONPAGED_POOL;
+ }
+
+ //
+ // Align to page size boundary.
+ //
+
+ MmSizeOfNonPagedPoolInBytes &= ~(PAGE_SIZE - 1);
+
+ //
+ // Calculate the maximum size of pool.
+ //
+
+ if (MmMaximumNonPagedPoolInBytes == 0) {
+
+ //
+ // Calculate the size of nonpaged pool. If 4mb of less use
+ // the minimum size, then for every MB about 4mb add extra
+ // pages.
+ //
+
+ MmMaximumNonPagedPoolInBytes = MmDefaultMaximumNonPagedPool;
+
+ //
+ // Make sure enough expansion for pfn database exists.
+ //
+
+ MmMaximumNonPagedPoolInBytes += (ULONG)PAGE_ALIGN (
+ MmHighestPhysicalPage * sizeof(MMPFN));
+
+ MmMaximumNonPagedPoolInBytes +=
+ ((MmNumberOfPhysicalPages - 1024)/256) *
+ MmMaxAdditionNonPagedPoolPerMb;
+ }
+
+ MaxPool = MmSizeOfNonPagedPoolInBytes + PAGE_SIZE * 16 +
+ (ULONG)PAGE_ALIGN (
+ MmHighestPhysicalPage * sizeof(MMPFN));
+
+ if (MmMaximumNonPagedPoolInBytes < MaxPool) {
+ MmMaximumNonPagedPoolInBytes = MaxPool;
+ }
+
+ if (MmMaximumNonPagedPoolInBytes > MM_MAX_ADDITIONAL_NONPAGED_POOL) {
+ MmMaximumNonPagedPoolInBytes = MM_MAX_ADDITIONAL_NONPAGED_POOL;
+ }
+
+ //
+ // Add in the PFN database size.
+ //
+
+ PfnAllocation = 1 + ((((MmHighestPhysicalPage + 1) * sizeof(MMPFN)) +
+ (MmSecondaryColors * sizeof(MMCOLOR_TABLES)*2))
+ >> PAGE_SHIFT);
+
+ MmMaximumNonPagedPoolInBytes += PfnAllocation << PAGE_SHIFT;
+
+ MmNonPagedPoolStart = (PVOID)((ULONG)MmNonPagedPoolEnd
+ - MmMaximumNonPagedPoolInBytes);
+
+ MmNonPagedPoolStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolStart);
+
+ MmPageAlignedPoolBase[NonPagedPool] = MmNonPagedPoolStart;
+
+ //
+ // Calculate the starting PDE for the system PTE pool which is
+ // right below the nonpaged pool.
+ //
+
+ MmNonPagedSystemStart = (PVOID)(((ULONG)MmNonPagedPoolStart -
+ ((MmNumberOfSystemPtes + 1) * PAGE_SIZE)) &
+ (~PAGE_DIRECTORY_MASK));
+
+ if (MmNonPagedSystemStart < MM_LOWEST_NONPAGED_SYSTEM_START) {
+ MmNonPagedSystemStart = MM_LOWEST_NONPAGED_SYSTEM_START;
+ MmNumberOfSystemPtes = (((ULONG)MmNonPagedPoolStart -
+ (ULONG)MmNonPagedSystemStart) >> PAGE_SHIFT)-1;
+ ASSERT (MmNumberOfSystemPtes > 1000);
+ }
+
+ StartPde = MiGetPdeAddress (MmNonPagedSystemStart);
+
+ EndPde = MiGetPdeAddress ((PVOID)((PCHAR)MmNonPagedPoolEnd - 1));
+
+ //
+ // Start building nonpaged pool with the largest free chunk of
+ // memory below 16mb.
+ //
+
+ while (StartPde <= EndPde) {
+ ASSERT(StartPde->u.Hard.Valid == 0);
+
+ //
+ // Map in a page directory page.
+ //
+
+ TempPte.u.Hard.PageFrameNumber = NextPhysicalPage;
+ NumberOfPages -= 1;
+ NextPhysicalPage += 1;
+ *StartPde = TempPte;
+ PointerPte = MiGetVirtualAddressMappedByPte (StartPde);
+ RtlZeroMemory (PointerPte, PAGE_SIZE);
+ StartPde += 1;
+ }
+
+ ASSERT (NumberOfPages > 0);
+
+//fixfix - remove later
+ if ((KeFeatureBits & KF_LARGE_PAGE) &&
+ (MmNumberOfPhysicalPages > ((31*1024*1024) >> PAGE_SHIFT))) {
+
+ //
+ // Map lower 512MB of physical memory as large pages starting
+ // at address 0x80000000
+ //
+
+ PointerPde = MiGetPdeAddress (MM_KSEG0_BASE);
+ LastPte = MiGetPdeAddress (MM_KSEG2_BASE) - 1;
+ if (MmHighestPhysicalPage < MM_PAGES_IN_KSEG0) {
+ LastPte = MiGetPdeAddress (MM_KSEG0_BASE +
+ (MmHighestPhysicalPage << PAGE_SHIFT));
+ }
+ PointerPte = MiGetPteAddress (MM_KSEG0_BASE);
+
+ TempPte = ValidKernelPde;
+ j = 0;
+
+ do {
+ PMMPTE PPte;
+
+ Range = 0;
+ if (PointerPde->u.Hard.Valid == 0) {
+ TempPte.u.Hard.PageFrameNumber = NextPhysicalPage;
+ NextPhysicalPage += 1;
+ NumberOfPages -= 1;
+ if (NumberOfPages == 0) {
+ ASSERT (NextPhysicalPage != (FreeDescriptor->BasePage +
+ FreeDescriptor->PageCount));
+ NextPhysicalPage = FreeDescriptor->BasePage;
+ NumberOfPages = FreeDescriptor->PageCount;
+ }
+ *PointerPde = TempPte;
+ Range = 1;
+ }
+ PPte = PointerPte;
+ for (i = 0; i < PTE_PER_PAGE; i++) {
+ if (Range || (PPte->u.Hard.Valid == 0)) {
+ *PPte = ValidKernelPte;
+ PPte->u.Hard.PageFrameNumber = i + j;
+ }
+ PPte += 1;
+ }
+ PointerPde += 1;
+ PointerPte += PTE_PER_PAGE;
+ j += PTE_PER_PAGE;
+ } while (PointerPde <= LastPte);
+ MapLargePages = 1; //fixfix save this line!
+ }
+//end of remove
+
+ PointerPte = MiGetPteAddress(MmNonPagedPoolStart);
+ NonPagedPoolStartVirtual = MmNonPagedPoolStart;
+
+ //
+ // Fill in the PTEs for non-paged pool.
+ //
+
+ SavedSize = MmSizeOfNonPagedPoolInBytes;
+
+ if (MapLargePages) {
+ if (MmSizeOfNonPagedPoolInBytes > (NumberOfPages << (PAGE_SHIFT))) {
+ MmSizeOfNonPagedPoolInBytes = NumberOfPages << PAGE_SHIFT;
+ }
+
+ NonPagedPoolStartVirtual = (PVOID)((PCHAR)NonPagedPoolStartVirtual +
+ MmSizeOfNonPagedPoolInBytes);
+
+ //
+ // No need to get page table pages for these as we can reference
+ // them via large pages.
+ //
+
+ MmNonPagedPoolStart =
+ (PVOID)(MM_KSEG0_BASE | (NextPhysicalPage << PAGE_SHIFT));
+ NextPhysicalPage += MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT;
+ NumberOfPages -= MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT;
+ if (NumberOfPages == 0) {
+ ASSERT (NextPhysicalPage != (FreeDescriptor->BasePage +
+ FreeDescriptor->PageCount));
+ NextPhysicalPage = FreeDescriptor->BasePage;
+ NumberOfPages = FreeDescriptor->PageCount;
+ }
+
+ MmSubsectionBase = (ULONG)MmNonPagedPoolStart;
+ if (NextPhysicalPage < (MM_SUBSECTION_MAP >> PAGE_SHIFT)) {
+ MmSubsectionBase = MM_KSEG0_BASE;
+ MmSubsectionTopPage = MM_SUBSECTION_MAP >> PAGE_SHIFT;
+ }
+ MmPageAlignedPoolBase[NonPagedPool] = MmNonPagedPoolStart;
+ MmNonPagedPoolExpansionStart = (PVOID)((PCHAR)NonPagedPoolStartVirtual +
+ (SavedSize - MmSizeOfNonPagedPoolInBytes));
+ } else {
+
+ LastPte = MiGetPteAddress((ULONG)MmNonPagedPoolStart +
+ MmSizeOfNonPagedPoolInBytes - 1);
+ while (PointerPte <= LastPte) {
+ TempPte.u.Hard.PageFrameNumber = NextPhysicalPage;
+ NextPhysicalPage += 1;
+ NumberOfPages -= 1;
+ if (NumberOfPages == 0) {
+ ASSERT (NextPhysicalPage != (FreeDescriptor->BasePage +
+ FreeDescriptor->PageCount));
+ NextPhysicalPage = FreeDescriptor->BasePage;
+ NumberOfPages = FreeDescriptor->PageCount;
+ }
+ *PointerPte = TempPte;
+ PointerPte++;
+ }
+ MmNonPagedPoolExpansionStart = (PVOID)((PCHAR)NonPagedPoolStartVirtual +
+ MmSizeOfNonPagedPoolInBytes);
+ }
+
+ //
+ // Non-paged pages now exist, build the pool structures.
+ //
+
+ MmPageAlignedPoolBase[NonPagedPool] = MmNonPagedPoolStart;
+
+ MmMaximumNonPagedPoolInBytes -= (SavedSize - MmSizeOfNonPagedPoolInBytes);
+ MiInitializeNonPagedPool (MmNonPagedPoolStart);
+ MmMaximumNonPagedPoolInBytes += (SavedSize - MmSizeOfNonPagedPoolInBytes);
+
+ //
+ // Before Non-paged pool can be used, the PFN database must
+ // be built. This is due to the fact that the start and end of
+ // allocation bits for nonpaged pool are maintained in the
+ // PFN elements for the corresponding pages.
+ //
+
+ //
+ // Calculate the number of pages required from page zero to
+ // the highest page.
+ //
+ // Get secondary color value from registry.
+ //
+
+ MmSecondaryColors = MmSecondaryColors >> PAGE_SHIFT;
+
+ if (MmSecondaryColors == 0) {
+ MmSecondaryColors = MM_SECONDARY_COLORS_DEFAULT;
+ } else {
+
+ //
+ // Make sure value is power of two and within limits.
+ //
+
+ if (((MmSecondaryColors & (MmSecondaryColors -1)) != 0) ||
+ (MmSecondaryColors < MM_SECONDARY_COLORS_MIN) ||
+ (MmSecondaryColors > MM_SECONDARY_COLORS_MAX)) {
+ MmSecondaryColors = MM_SECONDARY_COLORS_DEFAULT;
+ }
+ }
+
+ MmSecondaryColorMask = MmSecondaryColors - 1;
+
+ //
+ // Get the number of secondary colors and add the arrary for tracking
+ // secondary colors to the end of the PFN database.
+ //
+
+ HighPage = FreeDescriptor->BasePage + FreeDescriptor->PageCount;
+ PagesLeft = HighPage - NextPhysicalPage;
+
+ if (MapLargePages &&
+ (PagesLeft >= PfnAllocation) &&
+ (HighPage < MM_PAGES_IN_KSEG0)) {
+
+ //
+ // Allocate the PFN database in kseg0.
+ //
+ // Compute the address of the PFN by allocating the appropriate
+ // number of pages from the end of the free descriptor.
+ //
+
+ PfnInKseg0 = TRUE;
+ MmPfnDatabase = (PMMPFN)(MM_KSEG0_BASE |
+ ((HighPage - PfnAllocation) << PAGE_SHIFT));
+
+ RtlZeroMemory(MmPfnDatabase, PfnAllocation * PAGE_SIZE);
+ FreeDescriptor->PageCount -= PfnAllocation;
+
+ //
+ // The PFN database was NOT allocated in virtual memory, make sure
+ // the extended nonpaged pool size is not too large.
+ //
+
+ if (MmTotalFreeSystemPtes[NonPagedPoolExpansion] >
+ (MM_MAX_ADDITIONAL_NONPAGED_POOL >> PAGE_SHIFT)) {
+ //
+ // Reserve the expanded pool PTEs so they cannot be used.
+ //
+
+ MiReserveSystemPtes (
+ MmTotalFreeSystemPtes[NonPagedPoolExpansion] -
+ (MM_MAX_ADDITIONAL_NONPAGED_POOL >> PAGE_SHIFT),
+ NonPagedPoolExpansion,
+ 0,
+ 0,
+ TRUE);
+ }
+ } else {
+
+ //
+ // Calculate the start of the Pfn Database (it starts a physical
+ // page zero, even if the Lowest physical page is not zero).
+ //
+
+
+
+ PointerPte = MiReserveSystemPtes (PfnAllocation,
+ NonPagedPoolExpansion,
+ 0,
+ 0,
+ TRUE);
+
+ MmPfnDatabase = (PMMPFN)(MiGetVirtualAddressMappedByPte (PointerPte));
+
+ //
+ // Go through the memory descriptors and for each physical page
+ // make the PFN database has a valid PTE to map it. This allows
+ // machines with sparse physical memory to have a minimal PFN
+ // database.
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+
+ MemoryDescriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if ((MemoryDescriptor->MemoryType != LoaderFirmwarePermanent) &&
+ (MemoryDescriptor->MemoryType != LoaderSpecialMemory)) {
+
+ PointerPte = MiGetPteAddress (MI_PFN_ELEMENT(
+ MemoryDescriptor->BasePage));
+
+ LastPte = MiGetPteAddress (((PCHAR)(MI_PFN_ELEMENT(
+ MemoryDescriptor->BasePage +
+ MemoryDescriptor->PageCount))) - 1);
+
+ while (PointerPte <= LastPte) {
+ if (PointerPte->u.Hard.Valid == 0) {
+ TempPte.u.Hard.PageFrameNumber = NextPhysicalPage;
+ NextPhysicalPage += 1;
+ NumberOfPages -= 1;
+ if (NumberOfPages == 0) {
+ ASSERT (NextPhysicalPage != (FreeDescriptor->BasePage +
+ FreeDescriptor->PageCount));
+ NextPhysicalPage = FreeDescriptor->BasePage;
+ NumberOfPages = FreeDescriptor->PageCount;
+ }
+ *PointerPte = TempPte;
+ RtlZeroMemory (MiGetVirtualAddressMappedByPte (PointerPte),
+ PAGE_SIZE);
+ }
+ PointerPte++;
+ }
+ }
+
+ NextMd = MemoryDescriptor->ListEntry.Flink;
+ }
+ }
+
+ //
+ // Initialize support for colored pages.
+ //
+
+ MmFreePagesByColor[0] = (PMMCOLOR_TABLES)
+ &MmPfnDatabase[MmHighestPhysicalPage + 1];
+ MmFreePagesByColor[1] = &MmFreePagesByColor[0][MmSecondaryColors];
+
+ //
+ // Make sure the PTEs are mapped.
+ //
+
+ if (MmFreePagesByColor[0] > (PMMCOLOR_TABLES)MM_KSEG2_BASE) {
+ PointerPte = MiGetPteAddress (&MmFreePagesByColor[0][0]);
+
+ LastPte = MiGetPteAddress (
+ (PVOID)((PCHAR)&MmFreePagesByColor[1][MmSecondaryColors] - 1));
+
+ while (PointerPte <= LastPte) {
+ if (PointerPte->u.Hard.Valid == 0) {
+ TempPte.u.Hard.PageFrameNumber = NextPhysicalPage;
+ NextPhysicalPage += 1;
+ NumberOfPages -= 1;
+ if (NumberOfPages == 0) {
+ ASSERT (NextPhysicalPage != (FreeDescriptor->BasePage +
+ FreeDescriptor->PageCount));
+ NextPhysicalPage = FreeDescriptor->BasePage;
+ NumberOfPages = FreeDescriptor->PageCount;
+
+ }
+ *PointerPte = TempPte;
+ RtlZeroMemory (MiGetVirtualAddressMappedByPte (PointerPte),
+ PAGE_SIZE);
+ }
+ PointerPte++;
+ }
+ }
+
+ for (i = 0; i < MmSecondaryColors; i++) {
+ MmFreePagesByColor[ZeroedPageList][i].Flink = MM_EMPTY_LIST;
+ MmFreePagesByColor[FreePageList][i].Flink = MM_EMPTY_LIST;
+ }
+
+#if MM_MAXIMUM_NUMBER_OF_COLORS > 1
+ for (i = 0; i < MM_MAXIMUM_NUMBER_OF_COLORS; i++) {
+ MmFreePagesByPrimaryColor[ZeroedPageList][i].ListName = ZeroedPageList;
+ MmFreePagesByPrimaryColor[FreePageList][i].ListName = FreePageList;
+ MmFreePagesByPrimaryColor[ZeroedPageList][i].Flink = MM_EMPTY_LIST;
+ MmFreePagesByPrimaryColor[FreePageList][i].Flink = MM_EMPTY_LIST;
+ MmFreePagesByPrimaryColor[ZeroedPageList][i].Blink = MM_EMPTY_LIST;
+ MmFreePagesByPrimaryColor[FreePageList][i].Blink = MM_EMPTY_LIST;
+ }
+#endif
+
+ //
+ // Add nonpaged pool to PFN database if mapped via KSEG0.
+ //
+
+ PointerPde = MiGetPdeAddress (PTE_BASE);
+
+ if (MmNonPagedPoolStart < (PVOID)MM_KSEG2_BASE) {
+ j = MI_CONVERT_PHYSICAL_TO_PFN (MmNonPagedPoolStart);
+ Pfn1 = MI_PFN_ELEMENT (j);
+ i = MmSizeOfNonPagedPoolInBytes >> PAGE_SHIFT;
+ do {
+ PointerPde = MiGetPdeAddress (MM_KSEG0_BASE + (j << PAGE_SHIFT));
+ Pfn1->PteFrame = PointerPde->u.Hard.PageFrameNumber;
+ Pfn1->PteAddress = (PMMPTE)(j << PAGE_SHIFT);
+ Pfn1->u2.ShareCount += 1;
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.PageColor = 0;
+ j += 1;
+ Pfn1 += 1;
+ i -= 1;
+ } while ( i );
+ }
+
+ //
+ // Go through the page table entries and for any page which is
+ // valid, update the corresponding PFN database element.
+ //
+
+ Pde = MiGetPdeAddress (NULL);
+ va = 0;
+
+ for (i = 0; i < PDE_PER_PAGE; i++) {
+
+ if ((Pde->u.Hard.Valid == 1) && (Pde->u.Hard.LargePage == 0)) {
+
+ PdePage = Pde->u.Hard.PageFrameNumber;
+ Pfn1 = MI_PFN_ELEMENT(PdePage);
+ Pfn1->PteFrame = PointerPde->u.Hard.PageFrameNumber;
+ Pfn1->PteAddress = Pde;
+ Pfn1->u2.ShareCount += 1;
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.PageColor = 0;
+
+ PointerPte = MiGetPteAddress (va);
+
+ //
+ // Set global bit.
+ //
+
+ Pde->u.Long |= MiDetermineUserGlobalPteMask (PointerPte) &
+ ~MM_PTE_ACCESS_MASK;
+ for (j = 0 ; j < PTE_PER_PAGE; j++) {
+ if (PointerPte->u.Hard.Valid == 1) {
+
+ PointerPte->u.Long |= MiDetermineUserGlobalPteMask (PointerPte) &
+ ~MM_PTE_ACCESS_MASK;
+ Pfn1->u2.ShareCount += 1;
+
+ if ((PointerPte->u.Hard.PageFrameNumber <=
+ MmHighestPhysicalPage) &&
+ (MiGetVirtualAddressMappedByPte(PointerPte) >
+ (PVOID)MM_KSEG2_BASE)) {
+ Pfn2 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
+
+ if (MmIsAddressValid(Pfn2) &&
+ MmIsAddressValid((PUCHAR)(Pfn2+1)-1)) {
+
+ Pfn2->PteFrame = PdePage;
+ Pfn2->PteAddress = PointerPte;
+ Pfn2->u2.ShareCount += 1;
+ Pfn2->u3.e2.ReferenceCount = 1;
+ Pfn2->u3.e1.PageLocation = ActiveAndValid;
+ Pfn2->u3.e1.PageColor = 0;
+ }
+ }
+ }
+ va += PAGE_SIZE;
+ PointerPte++;
+ }
+ } else {
+ va += (ULONG)PDE_PER_PAGE * (ULONG)PAGE_SIZE;
+ }
+ Pde++;
+ }
+
+ KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
+ KeFlushCurrentTb();
+ KeLowerIrql (OldIrql);
+
+ //
+ // If page zero is still unused, mark it as in use. This is
+ // temporary as we want to find bugs where a physical page
+ // is specified as zero.
+ //
+
+ Pfn1 = &MmPfnDatabase[MmLowestPhysicalPage];
+ ASSERT (Pfn1->u3.e2.ReferenceCount == 0);
+ if (Pfn1->u3.e2.ReferenceCount == 0) {
+
+ //
+ // Make the reference count non-zero and point it into a
+ // page directory.
+ //
+
+ Pde = MiGetPdeAddress (0xb0000000);
+ PdePage = Pde->u.Hard.PageFrameNumber;
+ Pfn1->PteFrame = PdePageNumber;
+ Pfn1->PteAddress = Pde;
+ Pfn1->u2.ShareCount += 1;
+ Pfn1->u3.e2.ReferenceCount = 0xfff0;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.PageColor = 0;
+ }
+
+ // end of temporary set to physical page zero.
+
+ //
+ //
+ // Walk through the memory descriptors and add pages to the
+ // free list in the PFN database.
+ //
+
+ if (NextPhysicalPage <= (FreeDescriptorLowMem->PageCount +
+ FreeDescriptorLowMem->BasePage)) {
+
+ //
+ // We haven't used the other descriptor.
+ //
+
+ FreeDescriptorLowMem->PageCount -= NextPhysicalPage -
+ OldFreeDescriptorLowMemBase;
+ FreeDescriptorLowMem->BasePage = NextPhysicalPage;
+
+ } else {
+ FreeDescriptorLowMem->PageCount = 0;
+ FreeDescriptor->PageCount -= NextPhysicalPage - OldFreeDescriptorBase;
+ FreeDescriptor->BasePage = NextPhysicalPage;
+
+ }
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+
+ MemoryDescriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ i = MemoryDescriptor->PageCount;
+ NextPhysicalPage = MemoryDescriptor->BasePage;
+
+ switch (MemoryDescriptor->MemoryType) {
+ case LoaderBad:
+ while (i != 0) {
+ MiInsertPageInList (MmPageLocationList[BadPageList],
+ NextPhysicalPage);
+ i -= 1;
+ NextPhysicalPage += 1;
+ }
+ break;
+
+ case LoaderFree:
+ case LoaderLoadedProgram:
+ case LoaderFirmwareTemporary:
+ case LoaderOsloaderStack:
+
+ if (i > LargestFreePfnCount) {
+ LargestFreePfnCount = i;
+ LargestFreePfnStart = NextPhysicalPage;
+ }
+ Pfn1 = MI_PFN_ELEMENT (NextPhysicalPage);
+ while (i != 0) {
+ if (Pfn1->u3.e2.ReferenceCount == 0) {
+
+ //
+ // Set the PTE address to the phyiscal page for
+ // virtual address alignment checking.
+ //
+
+ Pfn1->PteAddress =
+ (PMMPTE)(NextPhysicalPage << PTE_SHIFT);
+ MiInsertPageInList (MmPageLocationList[FreePageList],
+ NextPhysicalPage);
+ }
+ Pfn1++;
+ i -= 1;
+ NextPhysicalPage += 1;
+ }
+ break;
+
+ case LoaderFirmwarePermanent:
+ case LoaderSpecialMemory:
+ break;
+
+ default:
+
+ PointerPte = MiGetPteAddress (0x80000000 +
+ (NextPhysicalPage << PAGE_SHIFT));
+
+ Pfn1 = MI_PFN_ELEMENT (NextPhysicalPage);
+ while (i != 0) {
+
+ //
+ // Set page as in use.
+ //
+
+ PointerPde = MiGetPdeAddress (0x80000000 +
+ (NextPhysicalPage << PAGE_SHIFT));
+
+ if (Pfn1->u3.e2.ReferenceCount == 0) {
+ Pfn1->PteFrame = PdePageNumber;
+ if (!MapLargePages) {
+ Pfn1->PteFrame = PointerPde->u.Hard.PageFrameNumber;
+ }
+ Pfn1->PteAddress = PointerPte;
+ Pfn1->u2.ShareCount += 1;
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.PageColor = 0;
+ }
+ Pfn1++;
+ i -= 1;
+ NextPhysicalPage += 1;
+ PointerPte += 1;
+ }
+ break;
+ }
+
+ NextMd = MemoryDescriptor->ListEntry.Flink;
+ }
+
+
+ if (PfnInKseg0 == FALSE) {
+
+ //
+ // Indicate that the PFN database is allocated in NonPaged pool.
+ //
+
+ PointerPte = MiGetPteAddress (&MmPfnDatabase[MmLowestPhysicalPage]);
+ Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
+ Pfn1->u3.e1.StartOfAllocation = 1;
+
+ //
+ // Set the end of the allocation.
+ //
+
+ PointerPte = MiGetPteAddress (&MmPfnDatabase[MmHighestPhysicalPage]);
+ Pfn1 = MI_PFN_ELEMENT(PointerPte->u.Hard.PageFrameNumber);
+ Pfn1->u3.e1.EndOfAllocation = 1;
+
+ } else {
+
+ //
+ // The PFN database is allocated in KSEG0.
+ //
+ // Mark all pfn entries for the pfn pages in use.
+ //
+
+ PageFrameIndex = MI_CONVERT_PHYSICAL_TO_PFN (MmPfnDatabase);
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+ do {
+ Pfn1->PteAddress = (PMMPTE)(PageFrameIndex << PTE_SHIFT);
+ Pfn1->u3.e1.PageColor = 0;
+ Pfn1->u3.e2.ReferenceCount += 1;
+ PageFrameIndex += 1;
+ Pfn1 += 1;
+ PfnAllocation -= 1;
+ } while (PfnAllocation != 0);
+
+ // Scan the PFN database backward for pages that are completely zero.
+ // These pages are unused and can be added to the free list
+ //
+
+ BottomPfn = MI_PFN_ELEMENT(MmHighestPhysicalPage);
+ do {
+
+ //
+ // Compute the address of the start of the page that is next
+ // lower in memory and scan backwards until that page address
+ // is reached or just crossed.
+ //
+
+ if (((ULONG)BottomPfn & (PAGE_SIZE - 1)) != 0) {
+ BasePfn = (PMMPFN)((ULONG)BottomPfn & ~(PAGE_SIZE - 1));
+ TopPfn = BottomPfn + 1;
+
+ } else {
+ BasePfn = (PMMPFN)((ULONG)BottomPfn - PAGE_SIZE);
+ TopPfn = BottomPfn;
+ }
+
+ while (BottomPfn > BasePfn) {
+ BottomPfn -= 1;
+ }
+
+ //
+ // If the entire range over which the PFN entries span is
+ // completely zero and the PFN entry that maps the page is
+ // not in the range, then add the page to the appropriate
+ // free list.
+ //
+
+ Range = (ULONG)TopPfn - (ULONG)BottomPfn;
+ if (RtlCompareMemoryUlong((PVOID)BottomPfn, Range, 0) == Range) {
+
+ //
+ // Set the PTE address to the physical page for virtual
+ // address alignment checking.
+ //
+
+ PageFrameIndex = MI_CONVERT_PHYSICAL_TO_PFN (BasePfn);
+ Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+
+ ASSERT (Pfn1->u3.e2.ReferenceCount == 1);
+ ASSERT (Pfn1->PteAddress == (PMMPTE)(PageFrameIndex << PTE_SHIFT));
+ Pfn1->u3.e2.ReferenceCount == 0;
+ PfnAllocation += 1;
+ Pfn1->PteAddress = (PMMPTE)(PageFrameIndex << PTE_SHIFT);
+ Pfn1->u3.e1.PageColor = 0;
+ MiInsertPageInList(MmPageLocationList[FreePageList],
+ PageFrameIndex);
+ }
+
+ } while (BottomPfn > MmPfnDatabase);
+ }
+
+ //
+ // Indicate that nonpaged pool must succeed is allocated in
+ // nonpaged pool.
+ //
+
+ PointerPte = MiGetPteAddress(MmNonPagedMustSucceed);
+ i = MmSizeOfNonPagedMustSucceed;
+ while ((LONG)i > 0) {
+ Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber);
+ Pfn1->u3.e1.StartOfAllocation = 1;
+ Pfn1->u3.e1.EndOfAllocation = 1;
+ i -= PAGE_SIZE;
+ PointerPte += 1;
+ }
+
+ //
+ // Adjust the memory descriptors to indicate that free pool has
+ // been used for nonpaged pool creation.
+ //
+
+ FreeDescriptorLowMem->PageCount = OldFreeDescriptorLowMemCount;
+ FreeDescriptorLowMem->BasePage = OldFreeDescriptorLowMemBase;
+
+ FreeDescriptor->PageCount = OldFreeDescriptorCount;
+ FreeDescriptor->BasePage = OldFreeDescriptorBase;
+
+// moved from above for pool hack routines...
+ KeInitializeSpinLock (&MmSystemSpaceLock);
+
+ KeInitializeSpinLock (&MmPfnLock);
+
+ //
+ // Initialize the nonpaged available PTEs for mapping I/O space
+ // and kernel stacks.
+ //
+
+ PointerPte = MiGetPteAddress (MmNonPagedSystemStart);
+ ASSERT (((ULONG)PointerPte & (PAGE_SIZE - 1)) == 0);
+
+ MmNumberOfSystemPtes = MiGetPteAddress(NonPagedPoolStartVirtual) - PointerPte - 1;
+
+ MiInitializeSystemPtes (PointerPte, MmNumberOfSystemPtes, SystemPteSpace);
+
+ //
+ // Add pages to nonpaged pool if we could not allocate enough physically
+ // configuous.
+ //
+
+ j = (SavedSize - MmSizeOfNonPagedPoolInBytes) >> PAGE_SHIFT;
+
+ if (j) {
+ ULONG CountContiguous;
+
+ CountContiguous = LargestFreePfnCount;
+ PageFrameIndex = LargestFreePfnStart - 1;
+
+ PointerPte = MiGetPteAddress (NonPagedPoolStartVirtual);
+ TempPte = ValidKernelPte;
+
+ while (j) {
+
+ if (CountContiguous) {
+ PageFrameIndex += 1;
+ MiUnlinkFreeOrZeroedPage (PageFrameIndex);
+ CountContiguous -= 1;
+ } else {
+ PageFrameIndex = MiRemoveAnyPage (
+ MI_GET_PAGE_COLOR_FROM_PTE (PointerPte));
+ }
+ Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
+
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u2.ShareCount = 1;
+ Pfn1->PteAddress = PointerPte;
+ Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE;
+ Pfn1->PteFrame = MiGetPteAddress(PointerPte)->u.Hard.PageFrameNumber;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+ *PointerPte = TempPte;
+ PointerPte += 1;
+
+ j -= 1;
+ }
+ Pfn1->u3.e1.EndOfAllocation = 1;
+ Pfn1 = MI_PFN_ELEMENT (MiGetPteAddress(NonPagedPoolStartVirtual)->u.Hard.PageFrameNumber);
+ Pfn1->u3.e1.StartOfAllocation = 1;
+
+ Range = MmAllocatedNonPagedPool;
+ MiFreePoolPages (NonPagedPoolStartVirtual);
+ MmAllocatedNonPagedPool = Range;
+ }
+
+ //
+ // Initialize the nonpaged pool.
+ //
+
+ InitializePool (NonPagedPool, 0);
+
+
+ //
+ // Initialize memory management structures for this process.
+ //
+
+ //
+ // Build working set list. This requires the creation of a PDE
+ // to map HYPER space and the page table page pointed to
+ // by the PDE must be initialized.
+ //
+ // Note, we can't remove a zeroed page as hyper space does not
+ // exist and we map non-zeroed pages into hyper space to zero.
+ //
+
+ TempPte = ValidPdePde;
+
+ PointerPte = MiGetPdeAddress(HYPER_SPACE);
+ PageFrameIndex = MiRemoveAnyPage (0);
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+ *PointerPte = TempPte;
+ KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
+ KeFlushCurrentTb();
+ KeLowerIrql (OldIrql);
+
+// MiInitializePfn (PageFrameIndex, PointerPte, 1L);
+
+ //
+ // Point to the page table page we just created and zero it.
+ //
+
+ PointerPte = MiGetPteAddress(HYPER_SPACE);
+ RtlZeroMemory ((PVOID)PointerPte, PAGE_SIZE);
+
+ //
+ // Hyper space now exists, set the necessary variables.
+ //
+
+ MmFirstReservedMappingPte = MiGetPteAddress (FIRST_MAPPING_PTE);
+ MmLastReservedMappingPte = MiGetPteAddress (LAST_MAPPING_PTE);
+
+ MmWorkingSetList = WORKING_SET_LIST;
+ MmWsle = (PMMWSLE)((PUCHAR)WORKING_SET_LIST + sizeof(MMWSL));
+
+ //
+ // Initialize this process's memory management structures including
+ // the working set list.
+ //
+
+ //
+ // The pfn element for the page directory has already been initialized,
+ // zero the reference count and the share count so they won't be
+ // wrong.
+ //
+
+ Pfn1 = MI_PFN_ELEMENT (PdePageNumber);
+ Pfn1->u2.ShareCount = 0;
+ Pfn1->u3.e2.ReferenceCount = 0;
+
+ CurrentProcess = PsGetCurrentProcess ();
+
+ //
+ // Get a page for the working set list and map it into the Page
+ // directory at the page after hyperspace.
+ //
+
+ PointerPte = MiGetPteAddress (HYPER_SPACE);
+ PageFrameIndex = MiRemoveAnyPage (0);
+
+ CurrentProcess->WorkingSetPage = PageFrameIndex;
+ TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+ PointerPde = MiGetPdeAddress (HYPER_SPACE) + 1;
+
+ *PointerPde = TempPte;
+ PointerPte = MiGetVirtualAddressMappedByPte (PointerPde);
+ KeRaiseIrql (DISPATCH_LEVEL, &OldIrql);
+ KeFlushCurrentTb();
+ KeLowerIrql (OldIrql);
+ RtlZeroMemory ((PVOID)PointerPte, PAGE_SIZE);
+
+ CurrentProcess->Vm.MaximumWorkingSetSize = MmSystemProcessWorkingSetMax;
+ CurrentProcess->Vm.MinimumWorkingSetSize = MmSystemProcessWorkingSetMin;
+
+ MmInitializeProcessAddressSpace (CurrentProcess,
+ (PEPROCESS)NULL,
+ (PVOID)NULL);
+ *PointerPde = ZeroPte;
+
+ //
+ // Check to see if moving the secondary page structures to the end
+ // of the PFN database is a waste of memory. And if so, copy it
+ // to paged pool.
+ //
+ // If the PFN datbase ends on a page aligned boundary and the
+ // size of the two arrays is less than a page, free the page
+ // and allocate nonpagedpool for this.
+ //
+
+ if ((((ULONG)MmFreePagesByColor[0] & (PAGE_SIZE - 1)) == 0) &&
+ ((MmSecondaryColors * 2 * sizeof(MMCOLOR_TABLES)) < PAGE_SIZE)) {
+
+ PMMCOLOR_TABLES c;
+
+ c = MmFreePagesByColor[0];
+
+ MmFreePagesByColor[0] = ExAllocatePoolWithTag (NonPagedPoolMustSucceed,
+ MmSecondaryColors * 2 * sizeof(MMCOLOR_TABLES),
+ ' mM');
+
+ MmFreePagesByColor[1] = &MmFreePagesByColor[0][MmSecondaryColors];
+
+ RtlMoveMemory (MmFreePagesByColor[0],
+ c,
+ MmSecondaryColors * 2 * sizeof(MMCOLOR_TABLES));
+
+ //
+ // Free the page.
+ //
+
+ if (c > (PMMCOLOR_TABLES)MM_KSEG2_BASE) {
+ PointerPte = MiGetPteAddress(c);
+ PageFrameIndex = PointerPte->u.Hard.PageFrameNumber;
+ *PointerPte = ZeroKernelPte;
+ } else {
+ PageFrameIndex = MI_CONVERT_PHYSICAL_TO_PFN (c);
+ }
+
+ Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
+ ASSERT ((Pfn1->u2.ShareCount <= 1) && (Pfn1->u3.e2.ReferenceCount <= 1));
+ Pfn1->u2.ShareCount = 0;
+ Pfn1->u3.e2.ReferenceCount = 1;
+ MI_SET_PFN_DELETED (Pfn1);
+#if DBG
+ Pfn1->u3.e1.PageLocation = StandbyPageList;
+#endif //DBG
+ MiDecrementReferenceCount (PageFrameIndex);
+ }
+
+ //
+ // Handle physical pages in BIOS memory range (640k to 1mb) by
+ // explicitly initializing them in the PFN database so that they
+ // can be handled properly when I/O is done to these pages (or virtual
+ // reads accross process.
+ //
+
+ Pfn1 = MI_PFN_ELEMENT (MM_BIOS_START);
+ Pfn2 = MI_PFN_ELEMENT (MM_BIOS_END);
+
+ do {
+ if ((Pfn1->u2.ShareCount == 0) &&
+ (Pfn1->u3.e2.ReferenceCount == 0) &&
+ (Pfn1->PteAddress == 0)) {
+
+ //
+ // Set this as in use.
+ //
+
+ Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->PteAddress = (PMMPTE)0x7FFFFFFF;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.PageColor = 0;
+ }
+ Pfn1 += 1;
+ } while (Pfn1 <= Pfn2);
+ return;
+}
+