[ros-diffs] [sir_richard] 56291: [NTOS]: Add initial support for standby page list and modified page list in the current page list routines. Add support for prototype PTEs in a few more cases, including handli...

sir_richard at svn.reactos.org sir_richard at svn.reactos.org
Sat Mar 31 20:08:34 UTC 2012


Author: sir_richard
Date: Sat Mar 31 20:08:34 2012
New Revision: 56291

URL: http://svn.reactos.org/svn/reactos?rev=56291&view=rev
Log:
[NTOS]: Add initial support for standby page list and modified page list in the current page list routines. Add support for prototype PTEs in a few more cases, including handling of transition pages. Should not affect any of the current code as those lists/transition pages aren't yet used.

Modified:
    trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c

Modified: trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c?rev=56291&r1=56290&r2=56291&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] Sat Mar 31 20:08:34 2012
@@ -723,13 +723,84 @@
 #endif
 }
 
-/* Note: This function is hardcoded only for the zeroed page list, for now */
+VOID
+FASTCALL
+MiInsertStandbyListAtFront(IN PFN_NUMBER PageFrameIndex)
+{
+    PMMPFNLIST ListHead;
+    PFN_NUMBER Flink;
+    PMMPFN Pfn1, Pfn2;
+
+    /* Make sure the lock is held */
+    DPRINT1("Inserting page: %lx into standby list !\n", PageFrameIndex);
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* Make sure the PFN is valid */
+    ASSERT((PageFrameIndex != 0) &&
+           (PageFrameIndex <= MmHighestPhysicalPage) &&
+           (PageFrameIndex >= MmLowestPhysicalPage));
+
+    /* Grab the PFN and validate it is the right kind of PFN being inserted */
+    Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
+    ASSERT(Pfn1->u4.MustBeCached == 0);
+    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+    ASSERT(Pfn1->u3.e1.PrototypePte == 1);
+    ASSERT(Pfn1->u3.e1.Rom != 1);
+
+    /* One more transition page on a list */
+    MmTransitionSharedPages++;
+
+    /* Get the standby page list and increment its count */
+    ListHead = &MmStandbyPageListByPriority [Pfn1->u4.Priority];
+    ASSERT_LIST_INVARIANT(ListHead);
+    ListHead->Total++;
+
+    /* 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 = StandbyPageList;
+
+    /* 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);
+    }
+}
+
 VOID
 NTAPI
 MiInsertPageInList(IN PMMPFNLIST ListHead,
                    IN PFN_NUMBER PageFrameIndex)
 {
-    PFN_NUMBER Flink;
+    PFN_NUMBER Flink, LastPage;
     PMMPFN Pfn1, Pfn2;
     MMLISTS ListName;
     PMMCOLOR_TABLES ColorHead;
@@ -751,95 +822,181 @@
     ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
     ASSERT(Pfn1->u3.e1.Rom != 1);
 
-    /* Only used for zero pages in ReactOS */
+    /* Is a standby or modified page being inserted? */
     ListName = ListHead->ListName;
-    ASSERT(ListName == ZeroedPageList);
+    if ((ListName == StandbyPageList) || (ListName == ModifiedPageList))
+    {
+        /* If the page is in transition, it must also be a prototype page */
+        if ((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
+            (Pfn1->OriginalPte.u.Soft.Transition == 1))
+        {
+            /* Crash the system on inconsistency */
+            KeBugCheckEx(MEMORY_MANAGEMENT, 0x8888, 0, 0, 0);
+        }
+    }
+
+    /* Standby pages are prioritized, so we need to get the real head */
+    if (ListHead == &MmStandbyPageListHead)
+    {
+        /* Obviously the prioritized list should still have the same name */
+        ListHead = &MmStandbyPageListByPriority[Pfn1->u4.Priority];
+        ASSERT(ListHead->ListName == ListName);
+    }
+
+    /* Increment the list count */
     ListHead->Total++;
+
+    /* Is a modified page being inserted? */
+    if (ListHead == &MmModifiedPageListHead)
+    {
+        /* For now, only single-prototype pages should end up in this path */
+        DPRINT1("Modified page being added: %lx\n", PageFrameIndex);
+        ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
+
+        /* Modified pages are colored when they are selected for page file */
+        ListHead = &MmModifiedPageListByColor[0];
+        ASSERT (ListHead->ListName == ListName);
+        ListHead->Total++;
+
+        /* Increment the number of paging file modified pages */
+        MmTotalPagesForPagingFile++;
+    }
 
     /* 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;
+    /* Zero pages go to the head, all other pages go to the end */
+    if (ListName == ZeroedPageList)
+    {
+        /* 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;
+        }
     }
     else
     {
-        /* It was empty, so have it loop back around to this new page */
+        /* Get the last page on the list */
+        LastPage = ListHead->Blink;
+        if (LastPage != LIST_HEAD)
+        {
+            /* Link us with the previous page, so we're at the end now */
+            MI_PFN_ELEMENT(LastPage)->u1.Flink = PageFrameIndex;
+        }
+        else
+        {
+            /* The list is empty, so we are the first page */
+            ListHead->Flink = 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;
     }
 
     /* 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++;
+    /* For zero/free pages, we also have to handle the colored lists */
+    if (ListName <= StandbyPageList)
+    {
+        /* 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);
+            //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
+    }
+    else if (ListName == ModifiedPageList)
+    {
+        /* In ARM3, page must be destined for page file, and not yet written out */
+        ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
+        ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
+
+        /* One more transition page */
+        ASSERT(Pfn1->u3.e1.PrototypePte == 1);
+        MmTransitionSharedPages++;
+
+        /* Increment the number of per-process modified pages */
+        PsGetCurrentProcess()->ModifiedPageCount++;
+
+        /* FIXME: Wake up modified page writer if there are not enough free pages */
+    }
+    else if (ListName == ModifiedNoWritePageList)
+    {
+        /* This list is not yet implemented */
+        ASSERT(FALSE);
+    }
 }
 
 VOID
@@ -1020,6 +1177,9 @@
 MiDecrementShareCount(IN PMMPFN Pfn1,
                       IN PFN_NUMBER PageFrameIndex)
 {
+    PMMPTE PointerPte;
+    MMPTE TempPte;
+
     ASSERT(PageFrameIndex > 0);
     ASSERT(MI_PFN_ELEMENT(PageFrameIndex) != NULL);
     ASSERT(Pfn1 == MI_PFN_ELEMENT(PageFrameIndex));
@@ -1041,8 +1201,27 @@
     ASSERT(Pfn1->u2.ShareCount < 0xF000000);
     if (!--Pfn1->u2.ShareCount)
     {
-        /* ReactOS does not handle these */
-        ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+        /* Was this a prototype PTE? */
+        if (Pfn1->u3.e1.PrototypePte)
+        {
+            /* Grab the PTE address and make sure it's in prototype pool */
+            PointerPte = Pfn1->PteAddress;
+            ASSERT((PointerPte >= (PMMPTE)MmPagedPoolStart) && (PointerPte <= (PMMPTE)MmPagedPoolEnd));
+
+            /* The PTE that backs it should also be valdi */
+            PointerPte = MiAddressToPte(PointerPte);
+            ASSERT(PointerPte->u.Hard.Valid == 1);
+
+            /* Get the original prototype PTE and turn it into a transition PTE */
+            PointerPte = Pfn1->PteAddress;
+            TempPte = *PointerPte;
+            TempPte.u.Soft.Transition = 1;
+            TempPte.u.Soft.Valid = 0;
+            TempPte.u.Soft.Prototype = 0;
+            TempPte.u.Soft.Protection = Pfn1->OriginalPte.u.Soft.Protection;
+            MI_WRITE_INVALID_PTE(PointerPte, TempPte);
+            DPRINT1("Marking PTE: %p as transition (%p - %lx)\n", PointerPte, Pfn1, MiGetPfnEntryIndex(Pfn1));
+        }
 
         /* Put the page in transition */
         Pfn1->u3.e1.PageLocation = TransitionPage;
@@ -1054,8 +1233,24 @@
         ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
         if (Pfn1->u3.e2.ReferenceCount == 1)
         {
-            /* In ReactOS, this path should always be hit with a deleted PFN */
-            ASSERT((MI_IS_PFN_DELETED(Pfn1) == TRUE) || (Pfn1->u3.e1.PrototypePte == 1));
+            /* Is there still a PFN for this page? */
+            if (MI_IS_PFN_DELETED(Pfn1) == TRUE)
+            {
+                /* Clear the last reference */
+                Pfn1->u3.e2.ReferenceCount = 0;
+                ASSERT(Pfn1->OriginalPte.u.Soft.Prototype == 0);
+
+                /* Mark the page temporarily as valid, we're going to make it free soon */
+                Pfn1->u3.e1.PageLocation = ActiveAndValid;
+
+                /* Bring it back into the free list */
+                MiInsertPageInFreeList(PageFrameIndex);
+            }
+            else
+            {
+                /* PFN not yet deleted, drop a ref count */
+                MiDecrementReferenceCount(Pfn1, PageFrameIndex);
+            }
 
             /* Clear the last reference */
             Pfn1->u3.e2.ReferenceCount = 0;
@@ -1110,12 +1305,18 @@
         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);
+    /* Check to see which list this page should go into */
+    if (Pfn1->u3.e1.Modified == 1)
+    {
+        /* Push it into the modified page list */
+        MiInsertPageInList(&MmModifiedPageListHead, PageFrameIndex);
+    }
+    else
+    {
+        /* Otherwise, insert this page into the standby list */
+        ASSERT(Pfn1->u3.e1.RemovalRequested == 0);
+        MiInsertStandbyListAtFront(PageFrameIndex);
+    }
 }
 
 VOID




More information about the Ros-diffs mailing list