Testers: Please pay attention to this build and test it fully:
authorSir Richard <sir_richard@svn.reactos.org>
Sat, 29 May 2010 18:33:50 +0000 (18:33 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Sat, 29 May 2010 18:33:50 +0000 (18:33 +0000)
[NTOS]: Implement MiDecrementShareCount (to start replacing MmReleasePageMemoryConsumer calls for pages that were grabbed through ARM3, not Mm).
[NTOS]: Implement MiInitializePfn (to initialize pages grabbed through ARM3/MiRemoveAnyPage instead of Mm/MmAllocPage).
[NTOS]: For stack pages, use new ARM3 PFN alloc/free routines, as a first test/beginning of the new ARM3 ABI.
[NTOS]: Implement and start using the Pending-Deletion PFN flag.
[NTOS]: As a result, for stack pages, the Transition page state will now be seen, and the new routine for re-inserting pages into the free list will now be used. Tracking of page table references is also done now for these pages (but we don't free the PT since this doesn't seem safe yet).

svn path=/trunk/; revision=47424

reactos/ntoskrnl/mm/ARM3/contmem.c
reactos/ntoskrnl/mm/ARM3/miarm.h
reactos/ntoskrnl/mm/ARM3/pagfault.c
reactos/ntoskrnl/mm/ARM3/pfnlist.c
reactos/ntoskrnl/mm/ARM3/procsup.c

index 0d7628b..2f3eda9 100644 (file)
@@ -502,6 +502,9 @@ MiFreeContiguousMemory(IN PVOID BaseAddress)
         ASSERT(Pfn1->u4.VerifierAllocation == 0);
         ASSERT(Pfn1->u3.e1.PrototypePte == 0);
         
+        /* Set the special pending delete marker */
+        MI_SET_PFN_DELETED(Pfn1);
+        
         /* Keep going for assertions */
         PointerPte++;
     } while (Pfn1++->u3.e1.EndOfAllocation == 0);
@@ -531,12 +534,11 @@ MiFreeContiguousMemory(IN PVOID BaseAddress)
     // Loop all the pages
     //
     LastPage = PageFrameIndex + PageCount;
+    Pfn1 = MiGetPfnEntry(PageFrameIndex);
     do
     {
-        //
-        // Free each one, and move on
-        //
-        MmReleasePageMemoryConsumer(MC_NPPOOL, PageFrameIndex++);
+        /* Decrement the share count and move on */
+        MiDecrementShareCount(Pfn1++, PageFrameIndex++);
     } while (PageFrameIndex < LastPage);
     
     //
index 193eb04..4c5e3bc 100644 (file)
 //
 #define MI_MAKE_SOFTWARE_PTE(p, x)          ((p)->u.Long = (x << MM_PTE_SOFTWARE_PROTECTION_BITS))
 
+//
+// Marks a PTE as deleted
+//
+#define MI_SET_PFN_DELETED(x)               ((x)->PteAddress = (PMMPTE)((ULONG_PTR)(x)->PteAddress | 1))
+#define MI_IS_PFN_DELETED(x)                ((ULONG_PTR)((x)->PteAddress) & 1)
+
 //
 // Special values for LoadedImports
 //
@@ -585,6 +591,21 @@ MiAllocatePfn(
     IN ULONG Protection
 );
 
+VOID
+NTAPI
+MiInitializePfn(
+    IN PFN_NUMBER PageFrameIndex,
+    IN PMMPTE PointerPte,
+    IN BOOLEAN Modified
+);
+
+VOID
+NTAPI
+MiDecrementShareCount(
+    IN PMMPFN Pfn1,
+    IN PFN_NUMBER PageFrameIndex
+);
+
 PFN_NUMBER
 NTAPI
 MiRemoveAnyPage(
index 7455a10..ceff13b 100644 (file)
@@ -91,7 +91,7 @@ MiResolveDemandZeroFault(IN PVOID Address,
 {
     PFN_NUMBER PageFrameNumber;
     MMPTE TempPte;
-    DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
+    DPRINT1("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
             Address,
             Process);
     
index ff17eb0..b70e191 100644 (file)
@@ -561,4 +561,126 @@ MiInsertPageInFreeList(IN PFN_NUMBER PageFrameIndex)
     }
 }
 
+VOID
+NTAPI
+MiInitializePfn(IN PFN_NUMBER PageFrameIndex,
+                IN PMMPTE PointerPte,
+                IN BOOLEAN Modified)
+{
+    PMMPFN Pfn1;
+    NTSTATUS Status;
+    PMMPTE PointerPtePte;
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+
+    /* Setup the PTE */
+    Pfn1 = MiGetPfnEntry(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);
+    }
+
+    /* Otherwise this is a fresh page -- set it up */
+    ASSERT(Pfn1->u3.e2.ReferenceCount == 0);
+    Pfn1->u3.e2.ReferenceCount = 1;
+    Pfn1->u2.ShareCount = 1;
+    Pfn1->u3.e1.PageLocation = ActiveAndValid;
+    ASSERT(Pfn1->u3.e1.Rom == 0);
+    Pfn1->u3.e1.Modified = Modified;
+
+    /* 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 = MiGetPfnEntry(PageFrameIndex);
+    Pfn1->u2.ShareCount++;
+}
+
+VOID
+NTAPI
+MiDecrementShareCount(IN PMMPFN Pfn1,
+                      IN PFN_NUMBER PageFrameIndex)
+{
+    ASSERT(PageFrameIndex > 0);
+    ASSERT(MiGetPfnEntry(PageFrameIndex) != NULL);
+    ASSERT(Pfn1 == MiGetPfnEntry(PageFrameIndex));
+
+    /* Page must be in-use */
+    if ((Pfn1->u3.e1.PageLocation != ActiveAndValid) &&
+        (Pfn1->u3.e1.PageLocation != StandbyPageList))
+    {
+        /* Otherwise we have PFN corruption */
+        KeBugCheckEx(PFN_LIST_CORRUPT,
+                     0x99,
+                     PageFrameIndex,
+                     Pfn1->u3.e1.PageLocation,
+                     0);
+    }
+
+    /* Check if the share count is now 0 */
+    ASSERT(Pfn1->u2.ShareCount < 0xF000000);
+    if (!--Pfn1->u2.ShareCount)
+    {
+        /* ReactOS does not handle these */
+        ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+
+        /* 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)
+        {
+            /* In ReactOS, this path should always be hit with a deleted PFN */
+            ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE);
+
+            /* 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;
+
+            /* Bring it back into the free list */
+            MiInsertPageInFreeList(PageFrameIndex);
+        }
+        else
+        {
+            /* Otherwise, just drop the reference count */
+            InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
+        }
+    }
+}
+
 /* EOF */
index 8f1e6b7..e82a567 100644 (file)
@@ -31,8 +31,10 @@ MmDeleteKernelStack(IN PVOID StackBase,
                     IN BOOLEAN GuiStack)
 {
     PMMPTE PointerPte;
-    PFN_NUMBER StackPages;
+    PFN_NUMBER StackPages, PageFrameNumber;//, PageTableFrameNumber;
+    PMMPFN Pfn1;//, Pfn2;
     ULONG i;
+    KIRQL OldIrql;
     
     //
     // This should be the guard page, so decrement by one
@@ -46,6 +48,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
     StackPages = BYTES_TO_PAGES(GuiStack ?
                                 KERNEL_LARGE_STACK_SIZE : KERNEL_STACK_SIZE);
     
+    /* Acquire the PFN lock */
+    OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+                            
     //
     // Loop them
     //
@@ -56,10 +61,22 @@ MmDeleteKernelStack(IN PVOID StackBase,
         //
         if (PointerPte->u.Hard.Valid == 1)
         {
-            //
-            // Nuke it
-            //
-            MmReleasePageMemoryConsumer(MC_NPPOOL, PFN_FROM_PTE(PointerPte));
+            /* Get the PTE's page */
+            PageFrameNumber = PFN_FROM_PTE(PointerPte);
+            Pfn1 = MiGetPfnEntry(PageFrameNumber);
+#if 0 // ARM3 might not own the page table, so don't take this risk. Leak it instead!
+            /* Now get the page of the page table mapping it */
+            PageTableFrameNumber = Pfn1->u4.PteFrame;
+            Pfn2 = MiGetPfnEntry(PageTableFrameNumber);
+            
+            /* Remove a shared reference, since the page is going away */
+            MiDecrementShareCount(Pfn2, PageTableFrameNumber);
+#endif
+            /* Set the special pending delete marker */
+            Pfn1->PteAddress = (PMMPTE)((ULONG_PTR)Pfn1->PteAddress | 1);
+            
+            /* And now delete the actual stack page */
+            MiDecrementShareCount(Pfn1, PageFrameNumber);
         }
         
         //
@@ -73,6 +90,9 @@ MmDeleteKernelStack(IN PVOID StackBase,
     //
     ASSERT(PointerPte->u.Hard.Valid == 0);
     
+    /* Release the PFN lock */
+    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
     //
     // Release the PTEs
     //
@@ -154,15 +174,14 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
         //
         PointerPte++;
         
-        //
-        // Get a page
-        //
-        PageFrameIndex = MmAllocPage(MC_NPPOOL);
-        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        /* Get a page */
+        PageFrameIndex = MiRemoveAnyPage(0);
         
-        //
-        // Write it
-        //
+        /* Initialize the PFN entry for this page */
+        MiInitializePfn(PageFrameIndex, PointerPte, 1);
+        
+        /* Write the valid PTE */
+        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
         ASSERT(PointerPte->u.Hard.Valid == 0);
         ASSERT(TempPte.u.Hard.Valid == 1);
         *PointerPte = TempPte;
@@ -250,13 +269,14 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
     //
     while (LimitPte >= NewLimitPte)
     {
-        //
-        // Get a page
-        //
-        PageFrameIndex = MmAllocPage(MC_NPPOOL);
-        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
+        /* Get a page */
+        PageFrameIndex = MiRemoveAnyPage(0);
+        
+        /* Initialize the PFN entry for this page */
+        MiInitializePfn(PageFrameIndex, LimitPte, 1);
         
         /* Write the valid PTE */
+        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
         ASSERT(LimitPte->u.Hard.Valid == 0);
         ASSERT(TempPte.u.Hard.Valid == 1);
         *LimitPte-- = TempPte;