Sync to trunk (r44371)
[reactos.git] / reactos / ntoskrnl / mm / amd64 / init.c
index 12cc704..2f59aea 100644 (file)
@@ -5,46 +5,25 @@
  * PURPOSE:         Memory Manager Initialization for amd64
  *
  * PROGRAMMERS:     Timo kreuzer (timo.kreuzer@reactos.org)
+ *                  ReactOS Portable Systems Group
  */
 
 /* INCLUDES ***************************************************************/
 
 #include <ntoskrnl.h>
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
 #include "../ARM3/miarm.h"
 
-#define MI_SESSION_SPACE_END (PVOID)0xFFFFF98000000000ULL
-#define MI_SESSION_VIEW_END 0xFFFFF97FFF000000ULL
-#define MI_NON_PAGED_SYSTEM_START_MIN 0x0FFFFFAA000000000ULL
+#ifndef KDBG
+extern PMMPTE MmDebugPte;
+#endif
 
 /* GLOBALS *****************************************************************/
 
-ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;
-PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL;
-PVOID MmSystemRangeStart = (PVOID)KSEG0_BASE; // FFFF080000000000
-
-/* Size of session view, pool, and image */
-ULONG64 MmSessionSize = MI_SESSION_SIZE;
-ULONG64 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
-ULONG64 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
-ULONG64 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
-
-/* Session space addresses */
-PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000
-PVOID MiSessionImageEnd;    // FFFFF98000000000 = MiSessionSpaceEnd
-PVOID MiSessionImageStart;  // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
-PVOID MiSessionViewEnd;     // FFFFF97FFF000000
-PVOID MiSessionViewStart;   //  = MiSessionViewEnd - MmSessionViewSize
-PVOID MiSessionPoolEnd;     //  = MiSessionViewStart
-PVOID MiSessionPoolStart;   // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
-PVOID MmSessionBase;        // FFFFF90000000000 = MiSessionPoolStart
-
-/* System view */
-ULONG64 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
-PVOID MiSystemViewStart;
-
+/* Sizes */
+ULONG64 MmBootImageSize;
 ULONG64 MmMinimumNonPagedPoolSize = 256 * 1024;
 ULONG64 MmSizeOfNonPagedPoolInBytes;
 ULONG64 MmMaximumNonPagedPoolInBytes;
@@ -52,50 +31,126 @@ ULONG64 MmMaximumNonPagedPoolPercent;
 ULONG64 MmMinAdditionNonPagedPoolPerMb = 32 * 1024;
 ULONG64 MmMaxAdditionNonPagedPoolPerMb = 400 * 1024;
 ULONG64 MmDefaultMaximumNonPagedPool = 1024 * 1024; 
-PVOID MmNonPagedSystemStart;
+ULONG64 MmSessionSize = MI_SESSION_SIZE;
+ULONG64 MmSessionViewSize = MI_SESSION_VIEW_SIZE;
+ULONG64 MmSessionPoolSize = MI_SESSION_POOL_SIZE;
+ULONG64 MmSessionImageSize = MI_SESSION_IMAGE_SIZE;
+ULONG64 MmSystemViewSize = MI_SYSTEM_VIEW_SIZE;
+ULONG64 MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
+ULONG64 MiNonPagedSystemSize;
+
+/* Address ranges */
+ULONG64 MmUserProbeAddress = 0x7FFFFFF0000ULL;
+PVOID MmHighestUserAddress = (PVOID)0x7FFFFFEFFFFULL;
+PVOID MmSystemRangeStart = (PVOID)0xFFFF080000000000ULL;
+PVOID MmSessionBase;                            // FFFFF90000000000 = MiSessionPoolStart
+PVOID MiSessionPoolStart;                       // FFFFF90000000000 = MiSessionPoolEnd - MmSessionPoolSize
+PVOID MiSessionPoolEnd;                         //                  = MiSessionViewStart
+PVOID MiSessionViewStart;                       //                  = MiSessionViewEnd - MmSessionViewSize
+PVOID MiSessionViewEnd;                         // FFFFF97FFF000000
+PVOID MiSessionImageStart;                      // ?FFFFF97FFF000000 = MiSessionImageEnd - MmSessionImageSize
+PVOID MiSessionImageEnd;                        // FFFFF98000000000 = MiSessionSpaceEnd
+PVOID MiSessionSpaceEnd = MI_SESSION_SPACE_END; // FFFFF98000000000
+PVOID MmSystemCacheStart;                       // FFFFF98000000000
+PVOID MmSystemCacheEnd;                         // FFFFFA8000000000
+PVOID MmPagedPoolStart = MI_PAGED_POOL_START;   // FFFFFA8000000000
+PVOID MmPagedPoolEnd;                           // FFFFFAA000000000
+PVOID MiSystemViewStart;
+PVOID MmNonPagedSystemStart;                    // FFFFFAA000000000
 PVOID MmNonPagedPoolStart;
 PVOID MmNonPagedPoolExpansionStart;
-PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END;
+PVOID MmNonPagedPoolEnd = MI_NONPAGED_POOL_END; // 0xFFFFFAE000000000
 
-ULONG64 MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
-PVOID MmPagedPoolStart = MI_PAGED_POOL_START;
-PVOID MmPagedPoolEnd;
+PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
+ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1; // FIXME: ULONG64
 
+ULONG MmNumberOfSystemPtes;
+PMMPTE MmSystemPagePtes;
+MMSUPPORT MmSystemCacheWs;
 
-ULONG64 MmBootImageSize;
-PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
 RTL_BITMAP MiPfnBitMap;
-ULONG MmNumberOfPhysicalPages, MmHighestPhysicalPage, MmLowestPhysicalPage = -1;
-ULONG64 MmNumberOfSystemPtes;
-PMMPTE MmSystemPagePtes;
 ULONG64 MxPfnAllocation;
-
-///////////////////////////////////////////////
+ULONG64 MxPfnSizeInBytes;
 
 PMEMORY_ALLOCATION_DESCRIPTOR MxFreeDescriptor;
 MEMORY_ALLOCATION_DESCRIPTOR MxOldFreeDescriptor;
+ULONG MiNumberDescriptors = 0;
+BOOLEAN MiIncludeType[LoaderMaximum];
 
 PFN_NUMBER MxFreePageBase;
 ULONG64 MxFreePageCount = 0;
+ULONG MxPhase = 0;
+
+PFN_NUMBER MmSystemPageDirectory;
+PFN_NUMBER MmSizeOfPagedPoolInPages = MI_MIN_INIT_PAGED_POOLSIZE / PAGE_SIZE;
+
+
+/* FUNCTIONS *****************************************************************/
+
+ULONG
+NoDbgPrint(const char *Format, ...)
+{
+    return 0;
+}
 
 VOID
 NTAPI
-MxSetupFreePageList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+MiEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
     PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
     PLIST_ENTRY ListEntry;
+    PFN_NUMBER LastPage;
+    ULONG i;
+
+    /* Get the size of the boot loader's image allocations */
+    MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned * PAGE_SIZE;
+    MmBootImageSize = ROUND_UP(MmBootImageSize, 4 * 1024 * 1024);
+
+    /* Instantiate memory that we don't consider RAM/usable */
+    for (i = 0; i < LoaderMaximum; i++) MiIncludeType[i] = TRUE;
+    MiIncludeType[LoaderBad] = FALSE;
+    MiIncludeType[LoaderFirmwarePermanent] = FALSE;
+    MiIncludeType[LoaderSpecialMemory] = FALSE;
+    MiIncludeType[LoaderBBTMemory] = FALSE;
 
     /* Loop the memory descriptors */
     for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
          ListEntry != &LoaderBlock->MemoryDescriptorListHead;
          ListEntry = ListEntry->Flink)
     {
-        /* Get the memory block */
+        /* Get the memory descriptor */
         MdBlock = CONTAINING_RECORD(ListEntry,
                                     MEMORY_ALLOCATION_DESCRIPTOR,
                                     ListEntry);
 
-        /* Check if this is free memory */
+        /* Count it */
+        MiNumberDescriptors++;
+
+        /* Skip pages that are not part of the PFN database */
+        if (!MiIncludeType[MdBlock->MemoryType])
+        {
+            continue;
+        }
+
+        /* Add this to the total of pages */
+        MmNumberOfPhysicalPages += MdBlock->PageCount;
+
+        /* Check if this is the new lowest page */
+        if (MdBlock->BasePage < MmLowestPhysicalPage)
+        {
+            /* Update the lowest page */
+            MmLowestPhysicalPage = MdBlock->BasePage;
+        }
+
+        /* Check if this is the new highest page */
+        LastPage = MdBlock->BasePage + MdBlock->PageCount - 1;
+        if (LastPage > MmHighestPhysicalPage)
+        {
+            /* Update the highest page */
+            MmHighestPhysicalPage = LastPage;
+        }
+
+        /* Check if this is currently free memory */
         if ((MdBlock->MemoryType == LoaderFree) ||
             (MdBlock->MemoryType == LoaderLoadedProgram) ||
             (MdBlock->MemoryType == LoaderFirmwareTemporary) ||
@@ -115,44 +170,54 @@ MxSetupFreePageList(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 
 PFN_NUMBER
 NTAPI
-MxGetNextPage(IN PFN_NUMBER PageCount)
+MxAllocEarlyPage()
 {
     PFN_NUMBER Pfn;
 
     /* Make sure we have enough pages */
-    if (PageCount > MxFreePageCount)
+    if (!MxFreePageCount)
     {
         /* Crash the system */
         KeBugCheckEx(INSTALL_MORE_MEMORY,
                      MmNumberOfPhysicalPages,
                      MxFreeDescriptor->PageCount,
                      MxOldFreeDescriptor.PageCount,
-                     PageCount);
+                     1);
     }
 
     /* Use our lowest usable free pages */
     Pfn = MxFreePageBase;
-    MxFreePageBase += PageCount;
-    MxFreePageCount -= PageCount;
+    MxFreePageBase++;
+    MxFreePageCount--;
     return Pfn;
 }
 
-VOID
-MxMapPage(PVOID Address)
+PFN_NUMBER
+NTAPI
+MxAllocPage()
+{
+    return (MxPhase == 0) ? MxAllocEarlyPage() : MmAllocPage(MC_SYSTEM, 0);
+}
+
+PMMPTE
+NTAPI
+MxGetPte(PVOID Address)
 {
     PMMPTE Pte;
-    MMPTE TmpPte;
+    MMPTE TmplPte;
 
-    TmpPte.u.Long = 0;
-    TmpPte.u.Hard.Valid = 1;
+    /* Setup template pte */
+    TmplPte.u.Long = 0;
+    TmplPte.u.Flush.Valid = 1;
+    TmplPte.u.Flush.Write = 1;
 
     /* Get a pointer to the PXE */
     Pte = MiAddressToPxe(Address);
     if (!Pte->u.Hard.Valid)
     {
         /* It's not valid, map it! */
-        TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
-        *Pte = TmpPte;
+        TmplPte.u.Hard.PageFrameNumber = MxAllocPage();
+        *Pte = TmplPte;
     }
 
     /* Get a pointer to the PPE */
@@ -160,8 +225,8 @@ MxMapPage(PVOID Address)
     if (!Pte->u.Hard.Valid)
     {
         /* It's not valid, map it! */
-        TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
-        *Pte = TmpPte;
+        TmplPte.u.Hard.PageFrameNumber = MxAllocPage();
+        *Pte = TmplPte;
     }
 
     /* Get a pointer to the PDE */
@@ -169,169 +234,211 @@ MxMapPage(PVOID Address)
     if (!Pte->u.Hard.Valid)
     {
         /* It's not valid, map it! */
-        TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
-        *Pte = TmpPte;
+        TmplPte.u.Hard.PageFrameNumber = MxAllocPage();
+        *Pte = TmplPte;
     }
 
     /* Get a pointer to the PTE */
     Pte = MiAddressToPte(Address);
-    if (!Pte->u.Hard.Valid)
-    {
-        /* It's not valid, map it! */
-        TmpPte.u.Hard.PageFrameNumber = MxGetNextPage(1);
-        *Pte = TmpPte;
-    }
+    return Pte;
 }
 
 VOID
-MxMapPageRange(PVOID Address, ULONG64 PageCount)
+NTAPI
+MxMapPage(PVOID Address)
 {
-    ULONG64 i;
+    MMPTE TmplPte, *Pte;
+
+    /* Setup template pte */
+    TmplPte.u.Long = 0;
+    TmplPte.u.Flush.Valid = 1;
+    TmplPte.u.Flush.Write = 1;
+    TmplPte.u.Hard.PageFrameNumber = MxAllocPage();
+
+    /* Get the PTE for that page */
+    Pte = MxGetPte(Address);
+    ASSERT(Pte->u.Hard.Valid == 0);
+
+    /* Map a physical page */
+    *Pte = TmplPte;
+}
 
-    for (i = 0; i < PageCount; i++)
+VOID
+MxMapPageRange(PVOID Address, ULONG64 PageCount)
+{
+    while (PageCount--)
     {
+        /* Map the page */
         MxMapPage(Address);
+
+        /* Goto next page */
         Address = (PVOID)((ULONG64)Address + PAGE_SIZE);
     }
 }
 
-
 VOID
 NTAPI
-MiArmIninializeMemoryLayout(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+MiPreparePfnDatabse(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    /* Get the size of the boot loader's image allocations */
-    MmBootImageSize = KeLoaderBlock->Extension->LoaderPagesSpanned;
-    MmBootImageSize *= PAGE_SIZE;
-    MmBootImageSize = (MmBootImageSize + (4 * 1024 * 1024) - 1) & ~((4 * 1024 * 1024) - 1);
-    ASSERT((MmBootImageSize % (4 * 1024 * 1024)) == 0);
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+    PLIST_ENTRY ListEntry;
+    PUCHAR Page, FirstPage;
+    SIZE_T Size;
+
+    /* Calculate the size of the PFN database and convert to pages */
+    MxPfnSizeInBytes = ROUND_TO_PAGES((MmHighestPhysicalPage + 1) * sizeof(MMPFN));
+    MxPfnAllocation = MxPfnSizeInBytes >> PAGE_SHIFT;
+
+    /* Simply start at hardcoded address */
+    MmPfnDatabase = MI_PFN_DATABASE;
+
+    /* Loop the memory descriptors */
+    for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+         ListEntry != &LoaderBlock->MemoryDescriptorListHead;
+         ListEntry = ListEntry->Flink)
+    {
+        /* Get the memory descriptor */
+        MdBlock = CONTAINING_RECORD(ListEntry,
+                                    MEMORY_ALLOCATION_DESCRIPTOR,
+                                    ListEntry);
 
+        /* Skip pages that are not part of the PFN database */
+        if (MiIncludeType[MdBlock->MemoryType])
+        {
+            /* Get the base and size of this pfn database entry */
+            FirstPage = PAGE_ALIGN(&MmPfnDatabase[MdBlock->BasePage]);
+            Size = ROUND_TO_PAGES(MdBlock->PageCount * sizeof(MMPFN));
+
+            /* Loop the pages of this Pfn database entry */
+            for (Page = FirstPage; Page < FirstPage + Size; Page += PAGE_SIZE)
+            {
+                /* Is the page already mapped? */
+                if (!MmIsAddressValid(Page))
+                {
+                    /* It's not, map it now */
+                    MxMapPage(Page);
+                }
+            }
+
+            /* Zero out the pages */
+            RtlZeroMemory(FirstPage, Size);
+        }
+    }
+}
+
+
+VOID
+NTAPI
+MiInitializeSessionSpace(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    /* Set up session space */
     MiSessionSpaceEnd = (PVOID)MI_SESSION_SPACE_END;
 
     /* This is where we will load Win32k.sys and the video driver */
     MiSessionImageEnd = MiSessionSpaceEnd;
-    MiSessionImageStart = (PVOID)((ULONG_PTR)MiSessionImageEnd -
-                                  MmSessionImageSize);
+    MiSessionImageStart = (PCHAR)MiSessionImageEnd - MmSessionImageSize;
 
     /* The view starts right below the session working set (itself below
      * the image area) */
-    MiSessionViewEnd = (PVOID)MI_SESSION_VIEW_END;
-    MiSessionViewStart = (PVOID)((ULONG_PTR)MiSessionViewStart -
-                                 MmSessionViewSize);
+    MiSessionViewEnd = MI_SESSION_VIEW_END;
+    MiSessionViewStart = (PCHAR)MiSessionViewEnd - MmSessionViewSize;
+    ASSERT(IS_PAGE_ALIGNED(MiSessionViewStart));
 
     /* Session pool follows */
     MiSessionPoolEnd = MiSessionViewStart;
-    MiSessionPoolStart = (PVOID)((ULONG_PTR)MiSessionPoolEnd -
-                                 MmSessionPoolSize);
+    MiSessionPoolStart = (PCHAR)MiSessionPoolEnd - MmSessionPoolSize;
+    ASSERT(IS_PAGE_ALIGNED(MiSessionPoolStart));
 
     /* And it all begins here */
     MmSessionBase = MiSessionPoolStart;
 
-    // Sanity check that our math is correct
-    //ASSERT((ULONG_PTR)MmSessionBase + MmSessionSize == PTE_BASE);
-
     /* System view space ends at session space, so now that we know where
      * this is, we can compute the base address of system view space itself. */
-    MiSystemViewStart = (PVOID)((ULONG_PTR)MmSessionBase -
-                                MmSystemViewSize);
-
-    /* Use the default */
-    MmNumberOfSystemPtes = 22000;
-
-    /* FIXME: should start below paged pool */
-    MmPfnDatabase = (PVOID)0xFFFFFD5FC0000000ULL;
+    MiSystemViewStart = (PCHAR)MmSessionBase - MmSystemViewSize;
+    ASSERT(IS_PAGE_ALIGNED(MiSystemViewStart));
 
+    /* Sanity checks */
+    ASSERT(MiSessionViewEnd <= MiSessionImageStart);
+    ASSERT(MmSessionBase <= MiSessionPoolStart);
 }
 
 VOID
-MiArmInitializePageTable()
+MiInitializePageTable()
 {
     ULONG64 PageFrameOffset;
-    PMMPTE StartPte, EndPte;
+    MMPTE TmplPte, *Pte;
+    PFN_NUMBER PageCount;
 
-    /* Set CR3 for the system process */
-    PageFrameOffset = ((PMMPTE)PXE_BASE)->u.Hard.PageFrameNumber << PAGE_SHIFT;
-    PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset;
+    /* HACK: don't use freeldr debug print anymore */
+    FrLdrDbgPrint = NoDbgPrint;
 
-    /* Clear user mode mappings in PML4 */
-    StartPte = MiAddressToPxe(0);
-    EndPte = MiAddressToPxe(MmSystemRangeStart);
-    RtlZeroMemory(StartPte, (EndPte - StartPte) * sizeof(MMPTE));
-}
+    /* Get current directory base */
+    MmSystemPageDirectory = ((PMMPTE)PXE_SELFMAP)->u.Hard.PageFrameNumber;
+    PageFrameOffset = MmSystemPageDirectory << PAGE_SHIFT;
+    ASSERT(PageFrameOffset == __readcr3());
 
+    /* Set directory base for the system process */
+    PsGetCurrentProcess()->Pcb.DirectoryTableBase[0] = PageFrameOffset;
 
-VOID
-NTAPI
-MiArmEvaluateMemoryDescriptors(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
-{
-    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
-    PLIST_ENTRY ListEntry;
-    PFN_NUMBER BasePage, LastPage, PageCount;
+    /* Enable global pages */
+    __writecr4(__readcr4() | CR4_PGE);
+    ASSERT(__readcr4() & CR4_PGE);
 
-    /* Loop the memory descriptors */
-    for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
-         ListEntry != &LoaderBlock->MemoryDescriptorListHead;
-         ListEntry = ListEntry->Flink)
+    /* Loop the user mode PXEs */
+    for (Pte = MiAddressToPxe(0);
+         Pte <= MiAddressToPxe(MmHighestUserAddress);
+         Pte++)
     {
-        /* Get the descriptor */
-        MdBlock = CONTAINING_RECORD(ListEntry,
-                                    MEMORY_ALLOCATION_DESCRIPTOR,
-                                    ListEntry);
+        /* Zero the PXE, clear all mappings */
+        Pte->u.Long = 0;
+    }
 
-        /* Skip pages that are not part of the PFN database */
-        if ((MdBlock->MemoryType == LoaderFirmwarePermanent) ||
-            (MdBlock->MemoryType == LoaderBBTMemory) ||
-            (MdBlock->MemoryType == LoaderHALCachedMemory) || // ???
-            (MdBlock->MemoryType == LoaderSpecialMemory))
-        {
-            continue;
-        }
+    /* Flush the TLB */
+    KeFlushCurrentTb();
 
-        /* Check if BURNMEM was used */
-        if (MdBlock->MemoryType != LoaderBad)
-        {
-            /* Count this in the total of pages */
-            MmNumberOfPhysicalPages += MdBlock->PageCount;
-        }
+    /* Set up a template PTE */
+    TmplPte.u.Long = 0;
+    TmplPte.u.Flush.Valid = 1;
+    TmplPte.u.Flush.Write = 1;
+    HyperTemplatePte = TmplPte;
 
-        BasePage = MdBlock->BasePage;
-        LastPage = MdBlock->BasePage + MdBlock->PageCount - 1;
+    /* Create PDPTs (72 KB) for shared system address space, 
+     * skip page tables and hyperspace */
 
-        /* Check if this is the new lowest page */
-        if (BasePage < MmLowestPhysicalPage)
+    /* Loop the PXEs */
+    for (Pte = MiAddressToPxe((PVOID)(HYPER_SPACE_END + 1));
+         Pte <= MiAddressToPxe(MI_HIGHEST_SYSTEM_ADDRESS);
+         Pte++)
+    {
+        /* Is the PXE already valid? */
+        if (!Pte->u.Hard.Valid)
         {
-            /* Update the lowest page */
-            MmLowestPhysicalPage = BasePage;
-        }
+            /* It's not Initialize it */
+            TmplPte.u.Flush.PageFrameNumber = MxAllocPage();
+            *Pte = TmplPte;
 
-        /* Check if this is the new highest page */
-        if (LastPage > MmHighestPhysicalPage)
-        {
-            /* Update the highest page */
-            MmHighestPhysicalPage = LastPage;
+            /* Zero the page. The PXE is the PTE for the PDPT. */
+            RtlZeroMemory(MiPteToAddress(Pte), PAGE_SIZE);
         }
-DPRINT1("BasePage = %ld, LastPage = %ld\n", BasePage, LastPage);
-__debugbreak();
-        /* Map pages for the PFN database */
-        PageCount = PAGE_ROUND_UP(MdBlock->PageCount * sizeof(MMPFN)) / PAGE_SIZE;
-        MxMapPageRange(&MmPfnDatabase[BasePage], PageCount);
-
-        /* Zero out the pages */
-        RtlZeroMemory(&MmPfnDatabase[BasePage], PageCount * PAGE_SIZE);
     }
 
-    /* Calculate the number of bytes, and then convert to pages */
-    MxPfnAllocation = (MmHighestPhysicalPage + 1) * sizeof(MMPFN);
-    MxPfnAllocation >>= PAGE_SHIFT;
-    MxPfnAllocation++;
+    /* Setup the mapping PTEs */
+    MmFirstReservedMappingPte = MxGetPte((PVOID)MI_MAPPING_RANGE_START);
+    MmFirstReservedMappingPte->u.Hard.PageFrameNumber = MI_HYPERSPACE_PTES;
+    MmLastReservedMappingPte = MiAddressToPte((PVOID)MI_MAPPING_RANGE_END);
 
+#ifndef KDBG
+    /* Setup debug mapping PTE */
+    MmDebugPte = MxGetPte(MI_DEBUG_MAPPING);
+#endif
 }
 
 VOID
 NTAPI
-MiArmPrepareNonPagedPool()
+MiBuildNonPagedPool(VOID)
 {
-    PFN_NUMBER PageCount;
+    PMMPTE Pte;
+    PFN_COUNT PageCount;
 
     /* Check if this is a machine with less than 256MB of RAM, and no overide */
     if ((MmNumberOfPhysicalPages <= MI_MIN_PAGES_FOR_NONPAGED_POOL_TUNING) &&
@@ -361,7 +468,7 @@ MiArmPrepareNonPagedPool()
     /* Check if the registy setting or our dynamic calculation was too high */
     if (MmSizeOfNonPagedPoolInBytes > MI_MAX_INIT_NONPAGED_POOL_SIZE)
     {
-        // Set it to the maximum */
+        /* Set it to the maximum */
         MmSizeOfNonPagedPoolInBytes = MI_MAX_INIT_NONPAGED_POOL_SIZE;
     }
 
@@ -391,22 +498,58 @@ MiArmPrepareNonPagedPool()
         MmMaximumNonPagedPoolInBytes = MI_MAX_NONPAGED_POOL_SIZE;
     }
 
+    /* Put non paged pool to the end of the region */
+    MmNonPagedPoolStart = (PCHAR)MmNonPagedPoolEnd - MmMaximumNonPagedPoolInBytes;
+
+    /* Make sure it doesn't collide with the PFN database */
+    if ((PCHAR)MmNonPagedPoolStart < (PCHAR)MmPfnDatabase + MxPfnSizeInBytes)
+    {
+        /* Put non paged pool after the PFN database */
+        MmNonPagedPoolStart = (PCHAR)MmPfnDatabase + MxPfnSizeInBytes;
+        MmMaximumNonPagedPoolInBytes = (ULONG64)MmNonPagedPoolEnd - 
+                                       (ULONG64)MmNonPagedPoolStart;
+    }
+
+    ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolStart));
+
     /* Calculate the nonpaged pool expansion start region */
-    MmNonPagedPoolExpansionStart = (PVOID)((ULONG_PTR)MmNonPagedPoolEnd -
-                                  MmMaximumNonPagedPoolInBytes +
-                                  MmSizeOfNonPagedPoolInBytes);
-    MmNonPagedPoolExpansionStart = (PVOID)PAGE_ALIGN(MmNonPagedPoolExpansionStart);
-
-    DPRINT("NP Pool has been tuned to: %d bytes and %d bytes\n",
-           MmSizeOfNonPagedPoolInBytes, MmMaximumNonPagedPoolInBytes);
-
-    /* Now calculate the nonpaged system VA region, which includes the
-     * nonpaged pool expansion (above) and the system PTEs. Note that it is
-     * then aligned to a PDE boundary (4MB). */
-    MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedPoolExpansionStart -
-                                    (MmNumberOfSystemPtes + 1) * PAGE_SIZE);
-    MmNonPagedSystemStart = (PVOID)((ULONG_PTR)MmNonPagedSystemStart &
-                                    ~((4 * 1024 * 1024) - 1));
+    MmNonPagedPoolExpansionStart = (PCHAR)MmNonPagedPoolStart +
+                                          MmSizeOfNonPagedPoolInBytes;
+    ASSERT(IS_PAGE_ALIGNED(MmNonPagedPoolExpansionStart));
+
+    /* Map the nonpaged pool */
+    PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
+    MxMapPageRange(MmNonPagedPoolStart, PageCount);
+
+    /* Loop the non paged pool extension PTEs */
+    for (Pte = MiAddressToPte(MmNonPagedPoolExpansionStart);
+         Pte <= MiAddressToPte(MmNonPagedPoolEnd);
+         Pte++)
+    {
+        /* Create PXE, PPE, PDE and zero the PTE */
+        MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
+    }
+
+    /* Initialize the ARM3 nonpaged pool */
+    MiInitializeArmPool();
+
+    /* Initialize the nonpaged pool */
+    InitializePool(NonPagedPool, 0);
+}
+
+VOID
+NTAPI
+MiBuildSystemPteSpace()
+{
+    PMMPTE Pte, StartPte, EndPte;
+
+    /* Use the default numer of system PTEs */
+    MmNumberOfSystemPtes = MI_NUMBER_SYSTEM_PTES;
+
+    /* System PTE pool is below the PFN database */
+    MiNonPagedSystemSize = (MmNumberOfSystemPtes + 1) * PAGE_SIZE;
+    MmNonPagedSystemStart = (PCHAR)MmPfnDatabase - MiNonPagedSystemSize;
+    MmNonPagedSystemStart = MM_ROUND_DOWN(MmNonPagedSystemStart, 512 * PAGE_SIZE);
 
     /* Don't let it go below the minimum */
     if (MmNonPagedSystemStart < (PVOID)MI_NON_PAGED_SYSTEM_START_MIN)
@@ -415,27 +558,244 @@ MiArmPrepareNonPagedPool()
         MmNonPagedSystemStart = (PVOID)MI_NON_PAGED_SYSTEM_START_MIN;
 
         /* Reduce the amount of system PTEs to reach this point */
-        MmNumberOfSystemPtes = ((ULONG_PTR)MmNonPagedPoolExpansionStart -
-                                (ULONG_PTR)MmNonPagedSystemStart) >>
+        MmNumberOfSystemPtes = ((ULONG64)MmPfnDatabase -
+                                (ULONG64)MmNonPagedSystemStart) >>
                                 PAGE_SHIFT;
         MmNumberOfSystemPtes--;
         ASSERT(MmNumberOfSystemPtes > 1000);
     }
 
-    /* Non paged pool comes after the PFN database */
-    MmNonPagedPoolStart = (PVOID)((ULONG_PTR)MmPfnDatabase +
-                                  (MxPfnAllocation << PAGE_SHIFT));
+    /* Set the range of system PTEs */
+    StartPte = MiAddressToPte(MI_SYSTEM_PTE_START);
+    EndPte = StartPte + MmNumberOfSystemPtes - 1;
 
-    /* Map the nonpaged pool */
-    PageCount = (MmSizeOfNonPagedPoolInBytes + PAGE_SIZE - 1) / PAGE_SIZE;
-    MxMapPageRange(MmNonPagedPoolStart, PageCount);
+    /* Loop the system PTEs */
+    for (Pte = StartPte; Pte <= EndPte; Pte++)
+    {
+        /* Create PXE, PPE, PDE and zero the PTE */
+        MxGetPte(MiPteToAddress(Pte))->u.Long = 0;
+    }
+
+    /* Create the system PTE space */
+    Pte = MiAddressToPte(MI_SYSTEM_PTE_START);
+    MiInitializeSystemPtes(Pte, MmNumberOfSystemPtes, SystemPteSpace);
 
-    /* Sanity check: make sure we have properly defined the system PTE space */
-    ASSERT(MiAddressToPte(MmNonPagedSystemStart) <
-           MiAddressToPte(MmNonPagedPoolExpansionStart));
+    /* Reserve system PTEs for zeroing PTEs and clear them */
+    MiFirstReservedZeroingPte = MiReserveSystemPtes(MI_ZERO_PTES, SystemPteSpace);
+    RtlZeroMemory(MiFirstReservedZeroingPte, MI_ZERO_PTES * sizeof(MMPTE));
 
+    /* Set the counter to maximum */
+    MiFirstReservedZeroingPte->u.Hard.PageFrameNumber = MI_ZERO_PTES - 1;
 }
 
+VOID
+NTAPI
+MiBuildPhysicalMemoryBlock(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
+{
+    PPHYSICAL_MEMORY_DESCRIPTOR Buffer, NewBuffer;
+    PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
+    PLIST_ENTRY ListEntry;
+    PFN_NUMBER NextPage = -1;
+    PULONG Bitmap;
+    ULONG Runs = 0;
+    ULONG Size, i;
+
+    /* Calculate size for the PFN bitmap */
+    Size = ROUND_UP(MmHighestPhysicalPage + 1, sizeof(ULONG));
+
+    /* Allocate the PFN bitmap */
+    Bitmap = ExAllocatePoolWithTag(NonPagedPool, Size, '  mM');
+
+    /* Allocate enough memory for the physical memory block */
+    Buffer = ExAllocatePoolWithTag(NonPagedPool,
+                                   sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
+                                   sizeof(PHYSICAL_MEMORY_RUN) *
+                                   (MiNumberDescriptors - 1),
+                                   'lMmM');
+    if (!Bitmap || !Buffer)
+    {
+        /* This is critical */
+        KeBugCheckEx(INSTALL_MORE_MEMORY,
+                     MmNumberOfPhysicalPages,
+                     MmLowestPhysicalPage,
+                     MmHighestPhysicalPage,
+                     0x101);
+    }
+
+    /* Initialize the bitmap and clear all bits */
+    RtlInitializeBitMap(&MiPfnBitMap, Bitmap, MmHighestPhysicalPage + 1);
+    RtlClearAllBits(&MiPfnBitMap);
+
+    /* Loop the memory descriptors */
+    for (ListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+         ListEntry != &LoaderBlock->MemoryDescriptorListHead;
+         ListEntry = ListEntry->Flink)
+    {
+        /* Get the memory descriptor */
+        MdBlock = CONTAINING_RECORD(ListEntry,
+                                    MEMORY_ALLOCATION_DESCRIPTOR,
+                                    ListEntry);
+
+        /* Skip pages that are not part of the PFN database */
+        if (!MiIncludeType[MdBlock->MemoryType])
+        {
+            continue;
+        }
+
+        /* Does the memory block begin where the last ended? */
+        if (MdBlock->BasePage == NextPage)
+        {
+            /* Add it to the current run */
+            Buffer->Run[Runs - 1].PageCount += MdBlock->PageCount;
+        }
+        else
+        {
+            /* Create a new run */
+            Runs++;
+            Buffer->Run[Runs - 1].BasePage = MdBlock->BasePage;
+            Buffer->Run[Runs - 1].PageCount = MdBlock->PageCount;
+        }
+
+        /* Set the bits in the PFN bitmap */
+        RtlSetBits(&MiPfnBitMap, MdBlock->BasePage, MdBlock->PageCount);
+
+        /* Set the next page */
+        NextPage = MdBlock->BasePage + MdBlock->PageCount;
+    }
+
+    // FIXME: allocate a buffer of better size
+
+    Buffer->NumberOfRuns = Runs;
+    Buffer->NumberOfPages = MmNumberOfPhysicalPages;
+    MmPhysicalMemoryBlock = Buffer;
+}
+
+VOID
+NTAPI
+MiBuildPagedPool(VOID)
+{
+    PMMPTE Pte;
+    MMPTE TmplPte;
+    PFN_NUMBER PageFrameIndex;
+    KIRQL OldIrql;
+    ULONG Size, BitMapSize;
+    
+    /* Default size for paged pool is 4 times non paged pool */
+    MmSizeOfPagedPoolInBytes = 4 * MmMaximumNonPagedPoolInBytes;
+
+    /* Make sure it doesn't overflow */
+    if (MmSizeOfPagedPoolInBytes > ((ULONG64)MmNonPagedSystemStart -
+                                    (ULONG64)MmPagedPoolStart))
+    {
+        MmSizeOfPagedPoolInBytes = (ULONG64)MmNonPagedSystemStart -
+                                   (ULONG64)MmPagedPoolStart;
+    }
+
+    /* Make sure paged pool is big enough */
+    if (MmSizeOfPagedPoolInBytes < MI_MIN_INIT_PAGED_POOLSIZE)
+    {
+        MmSizeOfPagedPoolInBytes = MI_MIN_INIT_PAGED_POOLSIZE;
+    }
+
+    /* Align down to a PDE boundary */
+    MmSizeOfPagedPoolInBytes = ROUND_DOWN(MmSizeOfPagedPoolInBytes,
+                                          512 * PAGE_SIZE);
+    MmSizeOfPagedPoolInPages = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
+
+    /* This is where paged pool ends */
+    MmPagedPoolEnd = (PCHAR)MmPagedPoolStart + MmSizeOfPagedPoolInBytes - 1;
+
+    /* Sanity check */
+    ASSERT(MmPagedPoolEnd < MmNonPagedSystemStart);
+
+    /* setup a template PTE */
+    TmplPte.u.Long = 0;
+    TmplPte.u.Flush.Valid = 1;
+    TmplPte.u.Flush.Write = 1;
+
+    /* Make sure the PXE is valid */
+    Pte = MiAddressToPxe(MmPagedPoolStart);
+    if (!Pte->u.Flush.Valid)
+    {
+        /* Map it! */
+        TmplPte.u.Flush.PageFrameNumber = MmAllocPage(MC_SYSTEM, 0);
+        *Pte = TmplPte;
+    }
+
+    /* Map all page directories (max 128) */
+    for (Pte = MiAddressToPpe(MmPagedPoolStart);
+         Pte <= MiAddressToPpe(MmPagedPoolEnd);
+         Pte++)
+    {
+        if (!Pte->u.Flush.Valid)
+        {
+            /* Map it! */
+            TmplPte.u.Flush.PageFrameNumber = MxAllocPage();
+            *Pte = TmplPte;
+        }
+    }
+
+    /* Create and map the first PTE for paged pool */
+    Pte = MxGetPte(MmPagedPoolStart);
+    TmplPte.u.Flush.PageFrameNumber = MxAllocPage();
+    *Pte = TmplPte;
+
+    /* Save the first and last paged pool PTE */
+    MmPagedPoolInfo.FirstPteForPagedPool = MiAddressToPte(MmPagedPoolStart);
+    MmPagedPoolInfo.LastPteForPagedPool = MiAddressToPte(MmPagedPoolEnd);
+
+    MmPagedPoolInfo.NextPdeForPagedPoolExpansion = 
+        MiAddressToPde(MmPagedPoolStart) + 1;
+
+    // We keep track of each page via a bit, so check how big the bitmap will
+    // have to be (make sure to align our page count such that it fits nicely
+    // into a 4-byte aligned bitmap.
+
+    /* The size of the bitmap in bits is the size in pages */
+    BitMapSize = MmSizeOfPagedPoolInPages;
+
+    /* Calculate buffer size in bytes, aligned to 32 bits */
+    Size = sizeof(RTL_BITMAP) + ROUND_UP(BitMapSize, 32) / 8;
+
+    // Allocate the allocation bitmap, which tells us which regions have not yet
+    // been mapped into memory
+
+    MmPagedPoolInfo.PagedPoolAllocationMap = 
+        ExAllocatePoolWithTag(NonPagedPool, Size, '  mM');
+    ASSERT(MmPagedPoolInfo.PagedPoolAllocationMap);
+
+    // Initialize it such that at first, only the first page's worth of PTEs is
+    // marked as allocated (incidentially, the first PDE we allocated earlier).
+    RtlInitializeBitMap(MmPagedPoolInfo.PagedPoolAllocationMap,
+                        (PULONG)(MmPagedPoolInfo.PagedPoolAllocationMap + 1),
+                        BitMapSize);
+    RtlSetAllBits(MmPagedPoolInfo.PagedPoolAllocationMap);
+    RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 0, 512);
+
+    // We have a second bitmap, which keeps track of where allocations end.
+    // Given the allocation bitmap and a base address, we can therefore figure
+    // out which page is the last page of that allocation, and thus how big the
+    // entire allocation is.
+    MmPagedPoolInfo.EndOfPagedPoolBitmap = 
+        ExAllocatePoolWithTag(NonPagedPool, Size, '  mM');
+    ASSERT(MmPagedPoolInfo.EndOfPagedPoolBitmap);
+
+    /* Initialize the bitmap */
+    RtlInitializeBitMap(MmPagedPoolInfo.EndOfPagedPoolBitmap,
+                        (PULONG)(MmPagedPoolInfo.EndOfPagedPoolBitmap + 1),
+                        BitMapSize);
+
+    /* No allocations, no allocation ends; clear all bits. */
+    RtlClearAllBits(MmPagedPoolInfo.EndOfPagedPoolBitmap);
+
+    /* Initialize the paged pool mutex */
+    KeInitializeGuardedMutex(&MmPagedPoolMutex);
+
+    /* Initialize the paged pool */
+    InitializePool(PagedPool, 0);
+}
+
+
 NTSTATUS
 NTAPI
 MmArmInitSystem(IN ULONG Phase,
@@ -443,22 +803,17 @@ MmArmInitSystem(IN ULONG Phase,
 {
     if (Phase == 0)
     {
-        /* Get a continuous range of physical pages */
-        MxSetupFreePageList(LoaderBlock);
-
-        /* Initialize the memory layout */
-        MiArmIninializeMemoryLayout(LoaderBlock);
-
-        /* Loop descriptors and prepare PFN database */
-        MiArmEvaluateMemoryDescriptors(LoaderBlock);
+        /* Parse memory descriptors */
+        MiEvaluateMemoryDescriptors(LoaderBlock);
 
-        MiArmInitializePageTable();
+        /* Prepare PFN database mappings */
+        MiPreparePfnDatabse(LoaderBlock);
 
-        /* Configure size of the non paged pool */
-        MiArmPrepareNonPagedPool();
+        /* Initialize the session space */
+        MiInitializeSessionSpace(LoaderBlock);
 
-        /* Initialize the ARM3 nonpaged pool */
-        MiInitializeArmPool();
+        /* Initialize some mappings */
+        MiInitializePageTable();
 
         /* Update the memory descriptor, to make sure the pages we used
            won't get inserted into the PFN database */
@@ -468,10 +823,27 @@ MmArmInitSystem(IN ULONG Phase,
     }
     else if (Phase == 1)
     {
+        PMMPTE Pte;
+        ULONG OldCount;
+        PPHYSICAL_MEMORY_RUN Run;
+
         /* The PFN database was created, restore the free descriptor */
         *MxFreeDescriptor = MxOldFreeDescriptor;
 
+        /* Switch to phase 1 */
+        MxPhase = 1;
+
+        /* Initialize the nonpaged pool */
+        MiBuildNonPagedPool();
+
+        /* Initialize system PTE handling */
+        MiBuildSystemPteSpace();
+
+        /* Build the physical memory block */
+        MiBuildPhysicalMemoryBlock(LoaderBlock);
 
+        /* Size up paged pool and build the shadow system page directory */
+        MiBuildPagedPool();
     }
 
     return STATUS_SUCCESS;