[ros-diffs] [sir_richard] 56233: [NTOS]: Add support for determining transition vs. demand zero faults (the former should not yet happen). [NTOS]: Add a function for removing transition pages from either the s...

sir_richard at svn.reactos.org sir_richard at svn.reactos.org
Mon Mar 26 07:41:47 UTC 2012


Author: sir_richard
Date: Mon Mar 26 07:41:47 2012
New Revision: 56233

URL: http://svn.reactos.org/svn/reactos?rev=56233&view=rev
Log:
[NTOS]: Add support for determining transition vs. demand zero faults (the former should not yet happen).
[NTOS]: Add a function for removing transition pages from either the standby or modified page lists (not yet used).

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

Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c?rev=56233&r1=56232&r2=56233&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Mon Mar 26 07:41:47 2012
@@ -446,6 +446,151 @@
 
 NTSTATUS
 NTAPI
+MiResolveTransitionFault(IN PVOID FaultingAddress,
+                         IN PMMPTE PointerPte,
+                         IN PEPROCESS CurrentProcess,
+                         IN KIRQL OldIrql,
+                         OUT PVOID *InPageBlock)
+{
+    PFN_NUMBER PageFrameIndex;
+    PMMPFN Pfn1;
+    MMPTE TempPte;
+    PMMPTE PointerToPteForProtoPage;
+    USHORT NewRefCount;
+    DPRINT1("Transition fault on 0x%p with PTE 0x%lx in process %s\n", FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
+
+    /* Windowss does this check */
+    ASSERT(*InPageBlock == NULL);
+
+    /* ARM3 doesn't support this path */
+    ASSERT(OldIrql != MM_NOIRQL);
+
+    /* Capture the PTE and make sure it's in transition format */
+    TempPte = *PointerPte;
+    ASSERT((TempPte.u.Soft.Valid == 0) &&
+           (TempPte.u.Soft.Prototype == 0) &&
+           (TempPte.u.Soft.Transition == 1));
+
+    /* Get the PFN and the PFN entry */
+    PageFrameIndex = TempPte.u.Trans.PageFrameNumber;
+    DPRINT1("Transition PFN: %lx\n", PageFrameIndex);
+    Pfn1 = MiGetPfnEntry(PageFrameIndex);
+
+    /* One more transition fault! */
+    InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
+
+    /* This is from ARM3 -- Windows normally handles this here */
+    ASSERT(Pfn1->u4.InPageError == 0);
+
+    /* Not supported in ARM3 */
+    ASSERT(Pfn1->u3.e1.ReadInProgress == 0);
+
+    /* Windows checks there's some free pages and this isn't an in-page error */
+    ASSERT(MmAvailablePages >= 0);
+    ASSERT(Pfn1->u4.InPageError == 0);
+
+    /* Was this a transition page in the valid list, or free/zero list? */
+    if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
+    {
+        /* All Windows does here is a bunch of sanity checks */
+        DPRINT1("Transition in active list\n");
+        ASSERT((Pfn1->PteAddress >= MiAddressToPte(MmPagedPoolStart)) &&
+               (Pfn1->PteAddress <= MiAddressToPte(MmPagedPoolEnd)));
+        ASSERT(Pfn1->u2.ShareCount != 0);
+        ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
+    }
+    else
+    {
+        /* Otherwise, the page is removed from its list */
+        DPRINT1("Transition page in free/zero list\n");
+        MiUnlinkPageFromList(Pfn1);
+
+        /* Windows does these checks -- perhaps a macro? */
+        ASSERT(Pfn1->u2.ShareCount == 0);
+        ASSERT(Pfn1->u2.ShareCount == 0);
+        ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
+
+        /* Check if this was a prototype PTE */
+        if ((Pfn1->u3.e1.PrototypePte == 1) &&
+            (Pfn1->OriginalPte.u.Soft.Prototype == 1))
+        {
+            DPRINT1("Prototype floating page not yet supported\n");
+            ASSERT(FALSE);
+        }
+
+        /* FIXME: Update counter */
+
+        /* We must be the first reference */
+        NewRefCount = InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
+        ASSERT(NewRefCount == 1);
+    }
+
+    /* At this point, there should no longer be any in-page errors */
+    ASSERT(Pfn1->u4.InPageError == 0);
+
+    /* Check if this was a PFN with no more share references */
+    if (Pfn1->u2.ShareCount == 0)
+    {
+        /* Windows checks for these... maybe a macro? */
+        ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
+        ASSERT(Pfn1->u2.ShareCount == 0);
+
+        /* Was this the last active reference to it */
+        DPRINT1("Page share count is zero\n");
+        if (Pfn1->u3.e2.ReferenceCount == 1)
+        {
+            /* The page should be leaking somewhere on the free/zero list */
+            DPRINT1("Page reference count is one\n");
+            ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
+            if ((Pfn1->u3.e1.PrototypePte == 1) &&
+                (Pfn1->OriginalPte.u.Soft.Prototype == 1))
+            {
+                /* Do extra processing if it was a prototype page */
+                DPRINT1("Prototype floating page not yet supported\n");
+                ASSERT(FALSE);
+            }
+
+            /* FIXME: Update counter */
+        }
+    }
+
+    /* Bump the share count and make the page valid */
+    Pfn1->u2.ShareCount++;
+    Pfn1->u3.e1.PageLocation = ActiveAndValid;
+
+    /* Prototype PTEs are in paged pool, which itself might be in transition */
+    if (FaultingAddress >= MmSystemRangeStart)
+    {
+        /* Check if this is a paged pool PTE in transition state */
+        PointerToPteForProtoPage = MiAddressToPte(PointerPte);
+        TempPte = *PointerToPteForProtoPage;
+        if ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Transition == 1))
+        {
+            /* This isn't yet supported */
+            DPRINT1("Double transition fault not yet supported\n");
+            ASSERT(FALSE);
+        }
+    }
+
+    /* Build the transition PTE -- maybe a macro? */
+    ASSERT(PointerPte->u.Hard.Valid == 0);
+    ASSERT(PointerPte->u.Trans.Prototype == 0);
+    ASSERT(PointerPte->u.Trans.Transition == 1);
+    TempPte.u.Long = (PointerPte->u.Long & ~0xFFF) |
+                     (MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
+                     MiDetermineUserGlobalPteMask(PointerPte);
+
+    /* FIXME: Set dirty bit */
+
+    /* Write the valid PTE */
+    MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+    /* Return success */
+    return STATUS_PAGE_FAULT_TRANSITION;
+}
+
+NTSTATUS
+NTAPI
 MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
                        IN PVOID Address,
                        IN PMMPTE PointerPte,
@@ -457,10 +602,11 @@
                        IN KIRQL OldIrql,
                        IN PVOID TrapInformation)
 {
-    MMPTE TempPte;
+    MMPTE TempPte, PteContents;
     PMMPFN Pfn1;
     PFN_NUMBER PageFrameIndex;
     NTSTATUS Status;
+    PVOID InPageBlock = NULL;
 
     /* Must be called with an invalid, prototype PTE, with the PFN lock held */
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
@@ -497,19 +643,50 @@
         return STATUS_ACCESS_VIOLATION;
     }
 
-    /* This is the only thing we support right now */
-    ASSERT(TempPte.u.Soft.PageFileHigh == 0);
-    ASSERT(TempPte.u.Proto.ReadOnly == 0);
-    ASSERT(PointerPte > MiHighestUserPte);
+    /* Check for access rights on the PTE proper */
+    PteContents = *PointerPte;
+    if (PteContents.u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)
+    {
+        if (!PteContents.u.Proto.ReadOnly)
+        {
+            /* FIXME: CHECK FOR ACCESS AND COW */
+        }
+    }
+    else
+    {
+        /* FIXME: Should check for COW */
+    }
+
+    /* Check for clone PTEs */
+    if (PointerPte <= MiHighestUserPte) ASSERT(Process->CloneRoot == NULL);
+
+    /* We don't support mapped files yet */
     ASSERT(TempPte.u.Soft.Prototype == 0);
-    ASSERT(TempPte.u.Soft.Transition == 0);
-
-    /* Resolve the demand zero fault */
-    Status = MiResolveDemandZeroFault(Address,
-                                      PointerProtoPte,
-                                      Process,
-                                      OldIrql);
-    ASSERT(NT_SUCCESS(Status));
+
+    /* We might however have transition PTEs */
+    if (TempPte.u.Soft.Transition == 1)
+    {
+        /* Resolve the transition fault */
+        ASSERT(OldIrql != MM_NOIRQL);
+        Status = MiResolveTransitionFault(Address,
+                                          PointerProtoPte,
+                                          Process,
+                                          OldIrql,
+                                          &InPageBlock);
+        ASSERT(NT_SUCCESS(Status));
+    }
+    else
+    {
+        /* We also don't support paged out pages */
+        ASSERT(TempPte.u.Soft.PageFileHigh == 0);
+
+        /* Resolve the demand zero fault */
+        Status = MiResolveDemandZeroFault(Address,
+                                          PointerProtoPte,
+                                          Process,
+                                          OldIrql);
+        ASSERT(NT_SUCCESS(Status));
+    }
 
     /* Complete the prototype PTE fault -- this will release the PFN lock */
     ASSERT(PointerPte->u.Hard.Valid == 0);

Modified: trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c?rev=56233&r1=56232&r2=56233&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] Mon Mar 26 07:41:47 2012
@@ -225,6 +225,124 @@
 //    MI_PFN_CURRENT_USAGE = MI_USAGE_NOT_SET;
 //    memcpy(MI_PFN_CURRENT_PROCESS_NAME, "Not Set", 16);
 #endif
+}
+
+VOID
+NTAPI
+MiUnlinkPageFromList(IN PMMPFN Pfn)
+{
+    PMMPFNLIST ListHead;
+    PFN_NUMBER OldFlink, OldBlink;
+
+    /* Make sure the PFN lock is held */
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* ARM3 should only call this for dead pages */
+    ASSERT(Pfn->u3.e2.ReferenceCount == 0);
+
+    /* Transition pages are supposed to be standby/modified/nowrite */
+    ListHead = MmPageLocationList[Pfn->u3.e1.PageLocation];
+    ASSERT(ListHead->ListName >= StandbyPageList);
+
+    /* Check if this was standby, or modified */
+    if (ListHead == &MmStandbyPageListHead)
+    {
+        /* Should not be a ROM page */
+        ASSERT(Pfn->u3.e1.Rom == 0);
+
+        /* Get the exact list */
+        ListHead = &MmStandbyPageListByPriority[Pfn->u4.Priority];
+
+        /* See if we hit any thresholds */
+        if (MmAvailablePages == MmHighMemoryThreshold)
+        {
+            /* Clear the high memory event */
+            KeClearEvent(MiHighMemoryEvent);
+        }
+        else if (MmAvailablePages == MmLowMemoryThreshold)
+        {
+            /* Signal the low memory event */
+            KeSetEvent(MiLowMemoryEvent, 0, FALSE);
+        }
+
+        /* Decrease transition page counter */
+        ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
+        MmTransitionSharedPages--;
+
+        /* One less page */
+        if (--MmAvailablePages < MmMinimumFreePages)
+        {
+            /* FIXME: Should wake up the MPW and working set manager, if we had one */
+            DPRINT1("Running low on pages: %d remaining\n", MmAvailablePages);
+
+            /* Call RosMm and see if it can release any pages for us */
+            MmRebalanceMemoryConsumers();
+        }
+    }
+    else if (ListHead == &MmModifiedPageListHead)
+    {
+        /* Only shared memory (page-file backed) modified pages are supported */
+        ASSERT(Pfn->OriginalPte.u.Soft.Prototype == 0);
+
+        /* Decrement the counters */
+        ListHead->Total--;
+        MmTotalPagesForPagingFile--;
+
+        /* Pick the correct colored list */
+        ListHead = &MmModifiedPageListByColor[0];
+
+        /* Decrease transition page counter */
+        ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
+        MmTransitionSharedPages--;
+    }
+    else if (ListHead == &MmModifiedNoWritePageListHead)
+    {
+        /* List not yet supported */
+        ASSERT(FALSE);
+    }
+
+    /* Nothing should be in progress and the list should not be empty */
+    ASSERT(Pfn->u3.e1.WriteInProgress == 0);
+    ASSERT(Pfn->u3.e1.ReadInProgress == 0);
+    ASSERT(ListHead->Total != 0);
+
+    /* Get the forward and back pointers */
+    OldFlink = Pfn->u1.Flink;
+    OldBlink = Pfn->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 */
+        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 */
+        MI_PFN_ELEMENT(OldBlink)->u1.Flink = OldFlink;
+    }
+    else
+    {
+        /* Set the list head's backlink instead */
+        ListHead->Flink = OldFlink;
+    }
+
+    /* ReactOS Hack */
+    Pfn->OriginalPte.u.Long = 0;
+
+    /* We are not on a list anymore */
+    Pfn->u1.Flink = Pfn->u2.Blink = 0;
+    ASSERT_LIST_INVARIANT(ListHead);
+
+    /* Remove one entry from the list */
+    ListHead->Total--;
 }
 
 PFN_NUMBER




More information about the Ros-diffs mailing list