[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / mm / ARM3 / pfnlist.c
index a86611b..f8a4b3a 100644 (file)
 #define NDEBUG
 #include <debug.h>
 
-#line 15 "ARMĀ³::PFNLIST"
 #define MODULE_INVOLVED_IN_ARM3
 #include "../ARM3/miarm.h"
 
+#if DBG
 #define ASSERT_LIST_INVARIANT(x) \
 do { \
        ASSERT(((x)->Total == 0 && \
@@ -25,11 +25,15 @@ do { \
                        (x)->Flink != LIST_HEAD && \
                        (x)->Blink != LIST_HEAD)); \
 } while (0)
+#else
+#define ASSERT_LIST_INVARIANT(x)
+#endif
 
 /* GLOBALS ********************************************************************/
 
 BOOLEAN MmDynamicPfn;
 BOOLEAN MmMirroring;
+ULONG MmSystemPageColor;
 
 MMPFNLIST MmZeroedPageListHead = {0, ZeroedPageList, LIST_HEAD, LIST_HEAD};
 MMPFNLIST MmFreePageListHead = {0, FreePageList, LIST_HEAD, LIST_HEAD};
@@ -50,139 +54,25 @@ PMMPFNLIST MmPageLocationList[] =
     NULL,
     NULL
 };
-/* FUNCTIONS ******************************************************************/
 
-VOID
-NTAPI
-MiInsertInListTail(IN PMMPFNLIST ListHead,
-                   IN PMMPFN Entry)
-{
-    PFN_NUMBER OldBlink, EntryIndex = MiGetPfnEntryIndex(Entry);
-
-       ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-       ASSERT_LIST_INVARIANT(ListHead);
+ULONG MI_PFN_CURRENT_USAGE;
+CHAR MI_PFN_CURRENT_PROCESS_NAME[16] = "None yet";
 
-    /* Get the back link */
-    OldBlink = ListHead->Blink;
-    if (OldBlink != LIST_HEAD)
-    {
-        /* Set the back pointer to point to us now */
-        MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
-    }
-    else
-    {
-        /* Set the list to point to us */
-        ListHead->Flink = EntryIndex;
-    }
-    
-    /* Set the entry to point to the list head forwards, and the old page backwards */
-    Entry->u1.Flink = LIST_HEAD;
-    Entry->u2.Blink = OldBlink;
-    
-    /* And now the head points back to us, since we are last */
-    ListHead->Blink = EntryIndex;
-    ListHead->Total++;
-       ASSERT_LIST_INVARIANT(ListHead);
-}
+/* FUNCTIONS ******************************************************************/
 
 VOID
 NTAPI
-MiInsertZeroListAtBack(IN PFN_NUMBER EntryIndex)
+MiZeroPhysicalPage(IN PFN_NUMBER PageFrameIndex)
 {
-    PFN_NUMBER OldBlink;
-    PMMPFNLIST ListHead;
-    PMMPFN Pfn1;
-#if 0
-    PMMPFN Blink;
-    ULONG Color;
-    PMMCOLOR_TABLES ColorHead;
-#endif
-
-    /* Make sure the PFN lock is held */
-    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-    
-    /* Get the descriptor */
-    Pfn1 = MiGetPfnEntry(EntryIndex);
-    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
-    ASSERT(Pfn1->u4.MustBeCached == 0);
-    ASSERT(Pfn1->u3.e1.Rom == 0);
-    ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
-    ASSERT(Pfn1->u4.InPageError == 0);
-    
-    /* Use the zero list */
-    ListHead = &MmZeroedPageListHead;
-       ASSERT_LIST_INVARIANT(ListHead);
-    ListHead->Total++;
-
-    /* Get the back link */
-    OldBlink = ListHead->Blink;
-    if (OldBlink != LIST_HEAD)
-    {
-        /* Set the back pointer to point to us now */
-        MiGetPfnEntry(OldBlink)->u1.Flink = EntryIndex;
-    }
-    else
-    {
-        /* Set the list to point to us */
-        ListHead->Flink = EntryIndex;
-    }
-    
-    /* Set the entry to point to the list head forwards, and the old page backwards */
-    Pfn1->u1.Flink = LIST_HEAD;
-    Pfn1->u2.Blink = OldBlink;
-    
-    /* And now the head points back to us, since we are last */
-    ListHead->Blink = EntryIndex;
-    
-    /* Update the page location */
-    Pfn1->u3.e1.PageLocation = ZeroedPageList;
-
-    /* FIXME: NOT YET Due to caller semantics: Update the available page count */
-    //MmAvailablePages++;
-
-    /* Check if we've reached the configured low memory threshold */
-    if (MmAvailablePages == MmLowMemoryThreshold)
-    {
-        /* Clear the event, because now we're ABOVE the threshold */
-        KeClearEvent(MiLowMemoryEvent);
-    }
-    else if (MmAvailablePages == MmHighMemoryThreshold)
-    {
-        /* Otherwise check if we reached the high threshold and signal the event */
-        KeSetEvent(MiHighMemoryEvent, 0, FALSE);
-    }
-
-       ASSERT_LIST_INVARIANT(ListHead);
-
-#if 0
-    /* Get the page color */
-    Color = EntryIndex & MmSecondaryColorMask;
-
-    /* Get the first page on the color list */
-    ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
-    if (ColorHead->Flink == LIST_HEAD)
-    {
-        /* The list is empty, so we are the first page */
-        Pfn1->u4.PteFrame = -1;
-        ColorHead->Flink = EntryIndex;
-    }
-    else
-    {
-        /* Get the previous page */
-        Blink = (PMMPFN)ColorHead->Blink;
-        
-        /* Make it link to us */
-        Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
-        Blink->OriginalPte.u.Long = EntryIndex;
-    }
-    
-    /* Now initialize our own list pointers */
-    ColorHead->Blink = Pfn1;
-    Pfn1->OriginalPte.u.Long = LIST_HEAD;
-    
-    /* And increase the count in the colored list */
-    ColorHead->Count++;
-#endif
+    KIRQL OldIrql;
+    PVOID VirtualAddress;
+    PEPROCESS Process = PsGetCurrentProcess();
+
+    /* Map in hyperspace, then wipe it using XMMI or MEMSET */
+    VirtualAddress = MiMapPageInHyperSpace(Process, PageFrameIndex, &OldIrql);
+    ASSERT(VirtualAddress);
+    KeZeroPages(VirtualAddress, PAGE_SIZE);
+    MiUnmapPageInHyperSpace(Process, VirtualAddress, OldIrql);
 }
 
 VOID
@@ -192,59 +82,114 @@ MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
     PFN_NUMBER OldFlink, OldBlink;
     PMMPFNLIST ListHead;
     MMLISTS ListName;
-    
+    ULONG Color;
+    PMMCOLOR_TABLES ColorTable;
+    PMMPFN Pfn1;
+
     /* Make sure the PFN lock is held */
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
 
     /* Make sure the PFN entry isn't in-use */
     ASSERT(Entry->u3.e1.WriteInProgress == 0);
     ASSERT(Entry->u3.e1.ReadInProgress == 0);
-    
+
     /* Find the list for this entry, make sure it's the free or zero list */
     ListHead = MmPageLocationList[Entry->u3.e1.PageLocation];
     ListName = ListHead->ListName;
     ASSERT(ListHead != NULL);
     ASSERT(ListName <= FreePageList);
-       ASSERT_LIST_INVARIANT(ListHead);
-    
+    ASSERT_LIST_INVARIANT(ListHead);
+
     /* Remove one count */
     ASSERT(ListHead->Total != 0);
     ListHead->Total--;
-    
+
     /* Get the forward and back pointers */
     OldFlink = Entry->u1.Flink;
     OldBlink = Entry->u2.Blink;
-    
+
     /* Check if the next entry is the list head */
     if (OldFlink != LIST_HEAD)
     {
         /* It is not, so set the backlink of the actual entry, to our backlink */
-        MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
+        MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
     }
     else
     {
         /* Set the list head's backlink instead */
         ListHead->Blink = OldBlink;
     }
-    
+
     /* Check if the back entry is the list head */
     if (OldBlink != LIST_HEAD)
     {
         /* It is not, so set the backlink of the actual entry, to our backlink */
-        MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
+        MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
     }
     else
     {
         /* Set the list head's backlink instead */
         ListHead->Flink = OldFlink;
     }
-    
+
+    /* Get the page color */
+    OldBlink = MiGetPfnEntryIndex(Entry);
+    Color = OldBlink & MmSecondaryColorMask;
+
+    /* Get the first page on the color list */
+    ColorTable = &MmFreePagesByColor[ListName][Color];
+
+    /* Check if this was was actually the head */
+    OldFlink = ColorTable->Flink;
+    if (OldFlink == OldBlink)
+    {
+        /* Make the table point to the next page this page was linking to */
+        ColorTable->Flink = Entry->OriginalPte.u.Long;
+        if (ColorTable->Flink != LIST_HEAD)
+        {
+            /* And make the previous link point to the head now */
+            MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
+        }
+        else
+        {
+            /* And if that page was the head, loop the list back around */
+            ColorTable->Blink = (PVOID)LIST_HEAD;
+        }
+    }
+    else
+    {
+        /* This page shouldn't be pointing back to the head */
+        ASSERT(Entry->u4.PteFrame != COLORED_LIST_HEAD);
+
+        /* Make the back link point to whoever the next page is */
+        Pfn1 = MI_PFN_ELEMENT(Entry->u4.PteFrame);
+        Pfn1->OriginalPte.u.Long = Entry->OriginalPte.u.Long;
+
+        /* Check if this page was pointing to the head */
+        if (Entry->OriginalPte.u.Long != LIST_HEAD)
+        {
+            /* Make the back link point to the head */
+            Pfn1 = MI_PFN_ELEMENT(Entry->OriginalPte.u.Long);
+            Pfn1->u4.PteFrame = Entry->u4.PteFrame;
+        }
+        else
+        {
+            /* Then the table is directly back pointing to this page now */
+            ColorTable->Blink = Pfn1;
+        }
+    }
+
+    /* One less colored page */
+    ASSERT(ColorTable->Count >= 1);
+    ColorTable->Count--;
+
+    /* ReactOS Hack */
+    Entry->OriginalPte.u.Long = 0;
+
     /* We are not on a list anymore */
     Entry->u1.Flink = Entry->u2.Blink = 0;
-       ASSERT_LIST_INVARIANT(ListHead);
-    
-    /* FIXME: Deal with color list */
-    
+    ASSERT_LIST_INVARIANT(ListHead);
+
     /* See if we hit any thresholds */
     if (MmAvailablePages == MmHighMemoryThreshold)
     {
@@ -256,12 +201,20 @@ MiUnlinkFreeOrZeroedPage(IN PMMPFN Entry)
         /* Signal the low memory event */
         KeSetEvent(MiLowMemoryEvent, 0, FALSE);
     }
-    
+
     /* One less page */
     if (--MmAvailablePages < MmMinimumFreePages)
     {
         /* FIXME: Should wake up the MPW and working set manager, if we had one */
     }
+
+#if MI_TRACE_PFNS
+    ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
+    Entry->PfnUsage = MI_PFN_CURRENT_USAGE;
+    memcpy(Entry->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
+//    MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
+//    memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
+#endif
 }
 
 PFN_NUMBER
@@ -273,91 +226,94 @@ MiRemovePageByColor(IN PFN_NUMBER PageIndex,
     PMMPFNLIST ListHead;
     MMLISTS ListName;
     PFN_NUMBER OldFlink, OldBlink;
-    ULONG OldColor, OldCache;
-#if 0
+    USHORT OldColor, OldCache;
     PMMCOLOR_TABLES ColorTable;
-#endif   
+
     /* Make sure PFN lock is held */
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
     ASSERT(Color < MmSecondaryColors);
 
     /* Get the PFN entry */
-    Pfn1 = MiGetPfnEntry(PageIndex);
+    Pfn1 = MI_PFN_ELEMENT(PageIndex);
     ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
     ASSERT(Pfn1->u3.e1.Rom == 0);
-    
+
     /* Capture data for later */
     OldColor = Pfn1->u3.e1.PageColor;
     OldCache = Pfn1->u3.e1.CacheAttribute;
 
     /* Could be either on free or zero list */
     ListHead = MmPageLocationList[Pfn1->u3.e1.PageLocation];
-       ASSERT_LIST_INVARIANT(ListHead);
+    ASSERT_LIST_INVARIANT(ListHead);
     ListName = ListHead->ListName;
     ASSERT(ListName <= FreePageList);
-    
+
     /* Remove a page */
     ListHead->Total--;
 
     /* Get the forward and back pointers */
     OldFlink = Pfn1->u1.Flink;
     OldBlink = Pfn1->u2.Blink;
-    
+
     /* Check if the next entry is the list head */
     if (OldFlink != LIST_HEAD)
     {
         /* It is not, so set the backlink of the actual entry, to our backlink */
-        MiGetPfnEntry(OldFlink)->u2.Blink = OldBlink;
+        MI_PFN_ELEMENT(OldFlink)->u2.Blink = OldBlink;
     }
     else
     {
         /* Set the list head's backlink instead */
-        ListHead->Blink = OldFlink;
+        ListHead->Blink = OldBlink;
     }
-    
+
     /* Check if the back entry is the list head */
     if (OldBlink != LIST_HEAD)
     {
         /* It is not, so set the backlink of the actual entry, to our backlink */
-        MiGetPfnEntry(OldBlink)->u1.Flink = OldFlink;
+        MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
     }
     else
     {
         /* Set the list head's backlink instead */
         ListHead->Flink = OldFlink;
     }
-    
+
     /* We are not on a list anymore */
+       ASSERT_LIST_INVARIANT(ListHead);
     Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
-    
+
     /* Zero flags but restore color and cache */
     Pfn1->u3.e2.ShortFlags = 0;
     Pfn1->u3.e1.PageColor = OldColor;
     Pfn1->u3.e1.CacheAttribute = OldCache;
 
-       ASSERT_LIST_INVARIANT(ListHead);
-
-#if 0 // When switching to ARM3
     /* Get the first page on the color list */
+    ASSERT(Color < MmSecondaryColors);
     ColorTable = &MmFreePagesByColor[ListName][Color];
     ASSERT(ColorTable->Count >= 1);
-    
+
     /* Set the forward link to whoever we were pointing to */
     ColorTable->Flink = Pfn1->OriginalPte.u.Long;
+
+    /* Get the first page on the color list */
     if (ColorTable->Flink == LIST_HEAD)
     {
         /* This is the beginning of the list, so set the sentinel value */
-        ColorTable->Blink = LIST_HEAD;    
+        ColorTable->Blink = (PVOID)LIST_HEAD;
     }
     else
     {
         /* The list is empty, so we are the first page */
-        MiGetPfnEntry(ColorTable->Flink)->u4.PteFrame = -1;
+        MI_PFN_ELEMENT(ColorTable->Flink)->u4.PteFrame = COLORED_LIST_HEAD;
     }
-    
-    /* One more page */
-    ColorTable->Total++;
-#endif
+
+    /* One less page */
+    ColorTable->Count--;
+
+    /* ReactOS Hack */
+    Pfn1->OriginalPte.u.Long = 0;
+
     /* See if we hit any thresholds */
     if (MmAvailablePages == MmHighMemoryThreshold)
     {
@@ -369,13 +325,21 @@ MiRemovePageByColor(IN PFN_NUMBER PageIndex,
         /* Signal the low memory event */
         KeSetEvent(MiLowMemoryEvent, 0, FALSE);
     }
-    
+
     /* One less page */
     if (--MmAvailablePages < MmMinimumFreePages)
     {
         /* FIXME: Should wake up the MPW and working set manager, if we had one */
     }
 
+#if MI_TRACE_PFNS
+    //ASSERT(MI_PFN_CURRENT_USAGE != MI_USAGE_NOT_SET);
+    Pfn1->PfnUsage = MI_PFN_CURRENT_USAGE;
+    memcpy(Pfn1->ProcessName, MI_PFN_CURRENT_PROCESS_NAME, 16);
+    //MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
+    //memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
+#endif
+
     /* Return the page */
     return PageIndex;
 }
@@ -391,9 +355,8 @@ MiRemoveAnyPage(IN ULONG Color)
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
     ASSERT(MmAvailablePages != 0);
     ASSERT(Color < MmSecondaryColors);
-    
+
     /* Check the colored free list */
-#if 0 // Enable when using ARM3 database */
     PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
     if (PageIndex == LIST_HEAD)
     {
@@ -401,15 +364,14 @@ MiRemoveAnyPage(IN ULONG Color)
         PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
         if (PageIndex == LIST_HEAD)
         {
-#endif
             /* Check the free list */
-                       ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+            ASSERT_LIST_INVARIANT(&MmFreePageListHead);
             PageIndex = MmFreePageListHead.Flink;
             Color = PageIndex & MmSecondaryColorMask;
             if (PageIndex == LIST_HEAD)
             {
                 /* Check the zero list */
-                               ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+                ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
                 PageIndex = MmZeroedPageListHead.Flink;
                 Color = PageIndex & MmSecondaryColorMask;
                 ASSERT(PageIndex != LIST_HEAD);
@@ -419,66 +381,93 @@ MiRemoveAnyPage(IN ULONG Color)
                     ASSERT(MmZeroedPageListHead.Total == 0);
                 }
             }
-#if 0 // Enable when using ARM3 database */
         }
     }
-#endif
 
     /* Remove the page from its list */
     PageIndex = MiRemovePageByColor(PageIndex, Color);
 
     /* Sanity checks */
-    Pfn1 = MiGetPfnEntry(PageIndex);
+    Pfn1 = MI_PFN_ELEMENT(PageIndex);
     ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
            (Pfn1->u3.e1.PageLocation == ZeroedPageList));
     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
     ASSERT(Pfn1->u2.ShareCount == 0);
-        
-    /* Return the page */
-       ASSERT_LIST_INVARIANT(&MmFreePageListHead);
-       ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+    ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+    ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
 
+    /* Return the page */
     return PageIndex;
 }
 
-PMMPFN
+PFN_NUMBER
 NTAPI
-MiRemoveHeadList(IN PMMPFNLIST ListHead)
+MiRemoveZeroPage(IN ULONG Color)
 {
-    PFN_NUMBER Entry, Flink;
+    PFN_NUMBER PageIndex;
     PMMPFN Pfn1;
-    
-       ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-       ASSERT_LIST_INVARIANT(ListHead);
+    BOOLEAN Zero = FALSE;
 
-    /* Get the entry that's currently first on the list */
-    Entry = ListHead->Flink;
-    Pfn1 = MiGetPfnEntry(Entry);
-    
-    /* Make the list point to the entry following the first one */
-    Flink = Pfn1->u1.Flink;
-    ListHead->Flink = Flink;
+    /* Make sure PFN lock is held and we have pages */
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    ASSERT(MmAvailablePages != 0);
+    ASSERT(Color < MmSecondaryColors);
 
-    /* Check if the next entry is actually the list head */
-    if (ListHead->Flink != LIST_HEAD)
-    {
-        /* It isn't, so therefore whoever is coming next points back to the head */
-        MiGetPfnEntry(Flink)->u2.Blink = LIST_HEAD;
-    }
-    else
+    /* Check the colored zero list */
+    PageIndex = MmFreePagesByColor[ZeroedPageList][Color].Flink;
+    if (PageIndex == LIST_HEAD)
     {
-        /* Then the list is empty, so the backlink should point back to us */
-        ListHead->Blink = LIST_HEAD;
+        /* Check the zero list */
+        ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+        PageIndex = MmZeroedPageListHead.Flink;
+        if (PageIndex == LIST_HEAD)
+        {
+            /* This means there's no zero pages, we have to look for free ones */
+            ASSERT(MmZeroedPageListHead.Total == 0);
+            Zero = TRUE;
+
+            /* Check the colored free list */
+            PageIndex = MmFreePagesByColor[FreePageList][Color].Flink;
+            if (PageIndex == LIST_HEAD)
+            {
+                /* Check the free list */
+                ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+                PageIndex = MmFreePageListHead.Flink;
+                Color = PageIndex & MmSecondaryColorMask;
+                ASSERT(PageIndex != LIST_HEAD);
+                if (PageIndex == LIST_HEAD)
+                {
+                    /* FIXME: Should check the standby list */
+                    ASSERT(MmZeroedPageListHead.Total == 0);
+                }
+            }
+        }
+        else
+        {
+            Color = PageIndex & MmSecondaryColorMask;
+        }
     }
-  
-    /* We are not on a list anymore */
-    Pfn1->u1.Flink = Pfn1->u2.Blink = 0;
-    ListHead->Total--;
-    
-       ASSERT_LIST_INVARIANT(ListHead);
 
-    /* Return the head element */
-    return Pfn1;
+    /* Sanity checks */
+    Pfn1 = MI_PFN_ELEMENT(PageIndex);
+    ASSERT((Pfn1->u3.e1.PageLocation == FreePageList) ||
+           (Pfn1->u3.e1.PageLocation == ZeroedPageList));
+
+    /* Remove the page from its list */
+    PageIndex = MiRemovePageByColor(PageIndex, Color);
+    ASSERT(Pfn1 == MI_PFN_ELEMENT(PageIndex));
+
+    /* Zero it, if needed */
+    if (Zero) MiZeroPhysicalPage(PageIndex);
+
+    /* Sanity checks */
+    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+    ASSERT(Pfn1->u2.ShareCount == 0);
+    ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+    ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+
+    /* Return the page */
+    return PageIndex;
 }
 
 VOID
@@ -488,19 +477,18 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
     PMMPFNLIST ListHead;
     PFN_NUMBER LastPage;
     PMMPFN Pfn1;
-#if 0
     ULONG Color;
     PMMPFN Blink;
     PMMCOLOR_TABLES ColorTable;
-#endif
+
     /* Make sure the page index is valid */
-       ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
+    ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
     ASSERT((PageFrameIndex != 0) &&
            (PageFrameIndex <= MmHighestPhysicalPage) &&
            (PageFrameIndex >= MmLowestPhysicalPage));
 
     /* Get the PFN entry */
-    Pfn1 = MiGetPfnEntry(PageFrameIndex);
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
 
     /* Sanity checks that a right kind of page is being inserted here */
     ASSERT(Pfn1->u4.MustBeCached == 0);
@@ -511,7 +499,7 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
 
     /* Get the free page list and increment its count */
     ListHead = &MmFreePageListHead;
-       ASSERT_LIST_INVARIANT(ListHead);
+    ASSERT_LIST_INVARIANT(ListHead);
     ListHead->Total++;
 
     /* Get the last page on the list */
@@ -519,7 +507,7 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
     if (LastPage != LIST_HEAD)
     {
         /* Link us with the previous page, so we're at the end now */
-        MiGetPfnEntry(LastPage)->u1.Flink = PageFrameIndex;
+        MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
     }
     else
     {
@@ -529,7 +517,8 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
 
     /* Now make the list head point back to us (since we go at the end) */
     ListHead->Blink = PageFrameIndex;
-    
+    ASSERT_LIST_INVARIANT(ListHead);
+
     /* And initialize our own list pointers */
     Pfn1->u1.Flink = LIST_HEAD;
     Pfn1->u2.Blink = LastPage;
@@ -537,7 +526,7 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
     /* Set the list name and default priority */
     Pfn1->u3.e1.PageLocation = FreePageList;
     Pfn1->u4.Priority = 3;
-    
+
     /* Clear some status fields */
     Pfn1->u4.InPageError = 0;
     Pfn1->u4.AweAllocation = 0;
@@ -557,9 +546,6 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
         KeSetEvent(MiHighMemoryEvent, 0, FALSE);
     }
 
-       ASSERT_LIST_INVARIANT(ListHead);
-
-#if 0 // When using ARM3 PFN
     /* Get the page color */
     Color = PageFrameIndex & MmSecondaryColorMask;
 
@@ -568,34 +554,159 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
     if (ColorTable->Flink == LIST_HEAD)
     {
         /* The list is empty, so we are the first page */
-        Pfn1->u4.PteFrame = -1;
+        Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
         ColorTable->Flink = PageFrameIndex;
     }
     else
     {
         /* Get the previous page */
         Blink = (PMMPFN)ColorTable->Blink;
-        
-        /* Make it link to us */
-        Pfn1->u4.PteFrame = MI_PFNENTRY_TO_PFN(Blink);
+
+        /* Make it link to us, and link back to it */
         Blink->OriginalPte.u.Long = PageFrameIndex;
+        Pfn1->u4.PteFrame = MiGetPfnEntryIndex(Blink);
     }
-    
+
     /* Now initialize our own list pointers */
     ColorTable->Blink = Pfn1;
+
+    /* This page is now the last */
     Pfn1->OriginalPte.u.Long = LIST_HEAD;
-    
+
     /* And increase the count in the colored list */
     ColorTable->Count++;
-#endif
-    
+
     /* Notify zero page thread if enough pages are on the free list now */
-    extern KEVENT ZeroPageThreadEvent;
-    if ((MmFreePageListHead.Total > 8) && !(KeReadStateEvent(&ZeroPageThreadEvent)))
+    if ((ListHead->Total >= 8) && !(MmZeroingPageThreadActive))
     {
-        /* This is ReactOS-specific */
-        KeSetEvent(&ZeroPageThreadEvent, IO_NO_INCREMENT, FALSE);
+        /* Set the event */
+        MmZeroingPageThreadActive = TRUE;
+        KeSetEvent(&MmZeroingPageEvent, IO_NO_INCREMENT, FALSE);
     }
+
+#if MI_TRACE_PFNS
+    Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
+    RtlZeroMemory(Pfn1->ProcessName, 16);
+#endif
+}
+
+/* Note: This function is hardcoded only for the zeroed page list, for now */
+VOID
+NTAPI
+MiInsertPageInList(IN PMMPFNLIST ListHead,
+                   IN PFN_NUMBER PageFrameIndex)
+{
+    PFN_NUMBER Flink;
+    PMMPFN Pfn1, Pfn2;
+    MMLISTS ListName;
+    PMMCOLOR_TABLES ColorHead;
+    ULONG Color;
+
+    /* For free pages, use MiInsertPageInFreeList */
+    ASSERT(ListHead != &MmFreePageListHead);
+
+    /* Make sure the lock is held */
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* Make sure the PFN is valid */
+    ASSERT((PageFrameIndex) &&
+           (PageFrameIndex <= MmHighestPhysicalPage) &&
+           (PageFrameIndex >= MmLowestPhysicalPage));
+
+    /* Page should be unused */
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+    ASSERT(Pfn1->u3.e1.Rom != 1);
+
+    /* Only used for zero pages in ReactOS */
+    ListName = ListHead->ListName;
+    ASSERT(ListName == ZeroedPageList);
+    ListHead->Total++;
+
+    /* Don't handle bad pages yet yet */
+    ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
+
+    /* Make the head of the list point to this page now */
+    Flink = ListHead->Flink;
+    ListHead->Flink = PageFrameIndex;
+
+    /* Make the page point to the previous head, and back to the list */
+    Pfn1->u1.Flink = Flink;
+    Pfn1->u2.Blink = LIST_HEAD;
+
+    /* Was the list empty? */
+    if (Flink != LIST_HEAD)
+    {
+        /* It wasn't, so update the backlink of the previous head page */
+        Pfn2 = MI_PFN_ELEMENT(Flink);
+        Pfn2->u2.Blink = PageFrameIndex;
+    }
+    else
+    {
+        /* It was empty, so have it loop back around to this new page */
+        ListHead->Blink = PageFrameIndex;
+    }
+
+    /* Move the page onto its new location */
+    Pfn1->u3.e1.PageLocation = ListName;
+
+    /* One more page on the system */
+    MmAvailablePages++;
+
+    /* Check if we've reached the configured low memory threshold */
+    if (MmAvailablePages == MmLowMemoryThreshold)
+    {
+        /* Clear the event, because now we're ABOVE the threshold */
+        KeClearEvent(MiLowMemoryEvent);
+    }
+    else if (MmAvailablePages == MmHighMemoryThreshold)
+    {
+        /* Otherwise check if we reached the high threshold and signal the event */
+        KeSetEvent(MiHighMemoryEvent, 0, FALSE);
+    }
+
+    /* Sanity checks */
+    ASSERT(ListName == ZeroedPageList);
+    ASSERT(Pfn1->u4.InPageError == 0);
+
+    /* Get the page color */
+    Color = PageFrameIndex & MmSecondaryColorMask;
+
+    /* Get the list for this color */
+    ColorHead = &MmFreePagesByColor[ZeroedPageList][Color];
+
+    /* Get the old head */
+    Flink = ColorHead->Flink;
+
+    /* Make this page point back to the list, and point forwards to the old head */
+    Pfn1->OriginalPte.u.Long = Flink;
+    Pfn1->u4.PteFrame = COLORED_LIST_HEAD;
+
+    /* Set the new head */
+    ColorHead->Flink = PageFrameIndex;
+
+    /* Was the head empty? */
+    if (Flink != LIST_HEAD)
+    {
+        /* No, so make the old head point to this page */
+        Pfn2 = MI_PFN_ELEMENT(Flink);
+        Pfn2->u4.PteFrame = PageFrameIndex;
+    }
+    else
+    {
+        /* Yes, make it loop back to this page */
+        ColorHead->Blink = (PVOID)Pfn1;
+    }
+
+    /* One more paged on the colored list */
+    ColorHead->Count++;
+
+#if MI_TRACE_PFNS
+    //ASSERT(MI_PFN_CURRENT_USAGE == MI_USAGE_NOT_SET);
+    Pfn1->PfnUsage = MI_USAGE_FREE_PAGE;
+    MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
+    RtlZeroMemory(Pfn1->ProcessName, 16);
+#endif
 }
 
 VOID
@@ -610,14 +721,24 @@ MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
 
     /* Setup the PTE */
-    Pfn1 = MiGetPfnEntry(PageFrameIndex);
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
     Pfn1->PteAddress = PointerPte;
 
     /* Check if this PFN is part of a valid address space */
     if (PointerPte->u.Hard.Valid == 1)
     {
-        /* FIXME: TODO */
-        ASSERT(FALSE);
+        /* Only valid from MmCreateProcessAddressSpace path */
+        ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
+
+        /* Make this a demand zero PTE */
+        MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
+    }
+    else
+    {
+        /* Copy the PTE data */
+        Pfn1->OriginalPte = *PointerPte;
+        ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
+                 (Pfn1->OriginalPte.u.Soft.Transition == 1)));
     }
 
     /* Otherwise this is a fresh page -- set it up */
@@ -651,10 +772,68 @@ MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
     Pfn1->u4.PteFrame = PageFrameIndex;
 
     /* Increase its share count so we don't get rid of it */
-    Pfn1 = MiGetPfnEntry(PageFrameIndex);
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
     Pfn1->u2.ShareCount++;
 }
 
+VOID
+NTAPI
+MiInitializePfnAndMakePteValid(IN PFN_NUMBER PageFrameIndex,
+                               IN PMMPTE PointerPte,
+                               IN MMPTE TempPte)
+{
+    PMMPFN Pfn1;
+    NTSTATUS Status;
+    PMMPTE PointerPtePte;
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* PTE must be invalid */
+    ASSERT(PointerPte->u.Hard.Valid == 0);
+
+    /* Setup the PTE */
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+    Pfn1->PteAddress = PointerPte;
+    Pfn1->OriginalPte = DemandZeroPte;
+
+    /* Otherwise this is a fresh page -- set it up */
+    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+    Pfn1->u3.e2.ReferenceCount++;
+    Pfn1->u2.ShareCount++;
+    Pfn1->u3.e1.PageLocation = ActiveAndValid;
+    ASSERT(Pfn1->u3.e1.Rom == 0);
+    Pfn1->u3.e1.Modified = 1;
+
+    /* Get the page table for the PTE */
+    PointerPtePte = MiAddressToPte(PointerPte);
+    if (PointerPtePte->u.Hard.Valid == 0)
+    {
+        /* Make sure the PDE gets paged in properly */
+        Status = MiCheckPdeForPagedPool(PointerPte);
+        if (!NT_SUCCESS(Status))
+        {
+            /* Crash */
+            KeBugCheckEx(MEMORY_MANAGEMENT,
+                         0x61940,
+                         (ULONG_PTR)PointerPte,
+                         (ULONG_PTR)PointerPtePte->u.Long,
+                         (ULONG_PTR)MiPteToAddress(PointerPte));
+        }
+    }
+
+    /* Get the PFN for the page table */
+    PageFrameIndex = PFN_FROM_PTE(PointerPtePte);
+    ASSERT(PageFrameIndex != 0);
+    Pfn1->u4.PteFrame = PageFrameIndex;
+
+    /* Increase its share count so we don't get rid of it */
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+    Pfn1->u2.ShareCount++;
+
+    /* Write valid PTE */
+    MI_WRITE_VALID_PTE(PointerPte, TempPte);
+}
+
+
 PFN_NUMBER
 NTAPI
 MiAllocatePfn(IN PMMPTE PointerPte,
@@ -663,36 +842,44 @@ MiAllocatePfn(IN PMMPTE PointerPte,
     KIRQL OldIrql;
     PFN_NUMBER PageFrameIndex;
     MMPTE TempPte;
-    
+
+    /* Sanity check that we aren't passed a valid PTE */
+    ASSERT(PointerPte->u.Hard.Valid == 0);
+
     /* Make an empty software PTE */
     MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
     
-    /* Lock the PFN database */
-    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-    
     /* Check if we're running low on pages */
     if (MmAvailablePages < 128)
     {
         DPRINT1("Warning, running low on memory: %d pages left\n", MmAvailablePages);
+
         //MiEnsureAvailablePageOrWait(NULL, OldIrql);
+
+        /* Call RosMm and see if it can release any pages for us */
+        MmRebalanceMemoryConsumers();
+
+        DPRINT1("Rebalance complete: %d pages left\n", MmAvailablePages);
     }
-    
+
+    /* Lock the PFN database */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
     /* Grab a page */
-       ASSERT_LIST_INVARIANT(&MmFreePageListHead);
-       ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
-    PageFrameIndex = MiRemoveAnyPage(0);
-    
+    ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+    ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+    PageFrameIndex = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
+
     /* Write the software PTE */
-    ASSERT(PointerPte->u.Hard.Valid == 0);
-    *PointerPte = TempPte;
+    MI_WRITE_INVALID_PTE(PointerPte, TempPte);
     PointerPte->u.Soft.Protection |= Protection;
-    
+
     /* Initialize its PFN entry */
     MiInitializePfn(PageFrameIndex, PointerPte, TRUE);
-    
+
     /* Release the PFN lock and return the page */
-       ASSERT_LIST_INVARIANT(&MmFreePageListHead);
-       ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
+    ASSERT_LIST_INVARIANT(&MmFreePageListHead);
+    ASSERT_LIST_INVARIANT(&MmZeroedPageListHead);
     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
     return PageFrameIndex;
 }
@@ -703,8 +890,9 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
                       IN PFN_NUMBER PageFrameIndex)
 {
     ASSERT(PageFrameIndex > 0);
-    ASSERT(MiGetPfnEntry(PageFrameIndex) != NULL);
-    ASSERT(Pfn1 == MiGetPfnEntry(PageFrameIndex));
+    ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
+    ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
+    ASSERT(MI_IS_ROS_PFN(Pfn1) == FALSE);
 
     /* Page must be in-use */
     if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
@@ -727,10 +915,10 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
 
         /* Put the page in transition */
         Pfn1->u3.e1.PageLocation = TransitionPage;
-    
+
         /* PFN lock must be held */
         ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-        
+
         /* Page should at least have one reference */
         ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
         if (Pfn1->u3.e2.ReferenceCount == 1)
@@ -740,13 +928,7 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
 
             /* Clear the last reference */
             Pfn1->u3.e2.ReferenceCount = 0;
-
-            /*
-             * OriginalPte is used by AweReferenceCount in ReactOS, but either 
-             * ways we shouldn't be seeing RMAP entries at this point
-             */
             ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
-            ASSERT(Pfn1->OriginalPte.u.Long == 0);
 
             /* Mark the page temporarily as valid, we're going to make it free soon */
             Pfn1->u3.e1.PageLocation = ActiveAndValid;
@@ -762,4 +944,82 @@ MiDecrementShareCount(IN PMMPFN Pfn1,
     }
 }
 
+VOID
+NTAPI
+MiDecrementReferenceCount(IN PMMPFN Pfn1,
+                          IN PFN_NUMBER PageFrameIndex)
+{
+    /* PFN lock must be held */
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* Sanity checks on the page */
+    ASSERT(PageFrameIndex < MmHighestPhysicalPage);
+    ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
+    ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
+
+    /* Dereference the page, bail out if it's still alive */
+    InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
+    if (Pfn1->u3.e2.ReferenceCount) return;
+
+    /* Nobody should still have reference to this page */
+    if (Pfn1->u2.ShareCount != 0)
+    {
+        /* Otherwise something's really wrong */
+        KeBugCheckEx(PFN_LIST_CORRUPT, 7, PageFrameIndex, Pfn1->u2.ShareCount, 0);
+    }
+
+    /* And it should be lying on some page list */
+    ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
+
+    /* Did someone set the delete flag? */
+    if (MI_IS_PFN_DELETED(Pfn1))
+    {
+        /* Insert it into the free list, there's nothing left to do */
+        MiInsertPageInFreeList(PageFrameIndex);
+        return;
+    }
+
+    /* We don't have a modified list yet */
+    ASSERT(Pfn1->u3.e1.Modified == 0);
+    ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
+
+    /* FIXME: Normally it would go on the standby list, but we're pushing it on the free list */
+    MiInsertPageInFreeList(PageFrameIndex);
+}
+
+VOID
+NTAPI
+MiInitializePfnForOtherProcess(IN PFN_NUMBER PageFrameIndex,
+                               IN PMMPTE PointerPte,
+                               IN PFN_NUMBER PteFrame)
+{
+    PMMPFN Pfn1;
+
+    /* Setup the PTE */
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+    Pfn1->PteAddress = PointerPte;
+
+    /* Make this a software PTE */
+    MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
+
+    /* Setup the page */
+    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+    Pfn1->u3.e2.ReferenceCount = 1;
+    Pfn1->u2.ShareCount = 1;
+    Pfn1->u3.e1.PageLocation = ActiveAndValid;
+    Pfn1->u3.e1.Modified = TRUE;
+    Pfn1->u4.InPageError = FALSE;
+
+    /* Did we get a PFN for the page table */
+    if (PteFrame)
+    {
+        /* Store it */
+        Pfn1->u4.PteFrame = PteFrame;
+
+        /* Increase its share count so we don't get rid of it */
+        Pfn1 = MI_PFN_ELEMENT(PteFrame);
+        Pfn1->u2.ShareCount++;
+    }
+}
+
 /* EOF */