[NTOS/MM]
authorJérôme Gardou <jerome.gardou@reactos.org>
Fri, 25 Jul 2014 22:13:35 +0000 (22:13 +0000)
committerJérôme Gardou <jerome.gardou@reactos.org>
Fri, 25 Jul 2014 22:13:35 +0000 (22:13 +0000)
 - First implementation of NtProtectVirtualMemory with Transition PTE
 - Release PTE frame page after erasing the PTE to avoid useless page fault

svn path=/trunk/; revision=63736

reactos/ntoskrnl/mm/ARM3/pagfault.c
reactos/ntoskrnl/mm/ARM3/pfnlist.c
reactos/ntoskrnl/mm/ARM3/virtual.c

index 662d1ea..0236bbf 100644 (file)
@@ -1310,20 +1310,41 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
         }
     }
 
+    /* Is this a transition PTE */
+    if (TempPte.u.Soft.Transition)
+    {
+        PVOID InPageBlock = NULL;
+        /* Lock the PFN database */
+        LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+        /* Resolve */
+        Status = MiResolveTransitionFault(Address, PointerPte, Process, LockIrql, &InPageBlock);
+
+        NT_ASSERT(NT_SUCCESS(Status));
+
+        /* And now release the lock and leave*/
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, LockIrql);
+
+        ASSERT(OldIrql == KeGetCurrentIrql());
+        ASSERT(OldIrql <= APC_LEVEL);
+        ASSERT(KeAreAllApcsDisabled() == TRUE);
+        return Status;
+    }
+
     //
     // The PTE must be invalid but not completely empty. It must also not be a
-    // prototype PTE as that scenario should've been handled above. These are
-    // all Windows checks
+    // prototype or transition PTE as those scenarii should've been handled above.
+    // These are all Windows checks
     //
     ASSERT(TempPte.u.Hard.Valid == 0);
     ASSERT(TempPte.u.Soft.Prototype == 0);
+    ASSERT(TempPte.u.Soft.Transition == 0);
     ASSERT(TempPte.u.Long != 0);
 
     //
-    // No transition or page file software PTEs in ARM3 yet, so this must be a
-    // demand zero page. These are all ReactOS checks
+    // No page file software PTEs in ARM3 yet, so this must be a
+    // demand zero page. This is a ReactOS check.
     //
-    ASSERT(TempPte.u.Soft.Transition == 0);
     ASSERT(TempPte.u.Soft.PageFileHigh == 0);
 
     //
index af132b2..12b33ce 100644 (file)
@@ -292,7 +292,6 @@ MiUnlinkPageFromList(IN PMMPFN Pfn)
         ListHead = &MmModifiedPageListByColor[0];
 
         /* Decrease transition page counter */
-        ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
         MmTransitionSharedPages--;
     }
     else if (ListHead == &MmModifiedNoWritePageListHead)
@@ -984,7 +983,6 @@ MiInsertPageInList(IN PMMPFNLIST ListHead,
         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 */
index fc87629..97d7601 100644 (file)
@@ -404,13 +404,36 @@ MiDeletePte(IN PMMPTE PointerPte,
     /* Capture the PTE */
     TempPte = *PointerPte;
 
-    /* We only support valid PTEs for now */
-    ASSERT(TempPte.u.Hard.Valid == 1);
+    /* See if the PTE is valid */
     if (TempPte.u.Hard.Valid == 0)
     {
-        /* Invalid PTEs not supported yet */
+        /* Prototype PTEs not supported yet */
         ASSERT(TempPte.u.Soft.Prototype == 0);
-        ASSERT(TempPte.u.Soft.Transition == 0);
+        if (TempPte.u.Soft.Transition)
+        {
+            /* Get the PFN entry */
+            PageFrameIndex = PFN_FROM_PTE(&TempPte);
+            Pfn1 = MiGetPfnEntry(PageFrameIndex);
+
+            DPRINT1("Pte %p is transitional!\n", PointerPte);
+
+            /* Destroy the PTE */
+            MI_ERASE_PTE(PointerPte);
+
+            /* Drop the reference on the page table. */
+            MiDecrementShareCount(MiGetPfnEntry(Pfn1->u4.PteFrame), Pfn1->u4.PteFrame);
+
+            if (Pfn1->u2.ShareCount == 0)
+            {
+                NT_ASSERT(Pfn1->u3.e2.ReferenceCount == 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);
+            }
+            return;
+        }
     }
 
     /* Get the PFN entry */
@@ -457,6 +480,9 @@ MiDeletePte(IN PMMPTE PointerPte,
                              (ULONG_PTR)Pfn1->PteAddress);
             }
         }
+
+        /* Erase it */
+        MI_ERASE_PTE(PointerPte);
     }
     else
     {
@@ -471,6 +497,9 @@ MiDeletePte(IN PMMPTE PointerPte,
                          (ULONG_PTR)Pfn1->PteAddress);
         }
 
+        /* Erase the PTE */
+        MI_ERASE_PTE(PointerPte);
+
         /* There should only be 1 shared reference count */
         ASSERT(Pfn1->u2.ShareCount == 1);
 
@@ -485,8 +514,7 @@ MiDeletePte(IN PMMPTE PointerPte,
         //CurrentProcess->NumberOfPrivatePages--;
     }
 
-    /* Destroy the PTE and flush the TLB */
-    MI_ERASE_PTE(PointerPte);
+    /* Flush the TLB */
     KeFlushCurrentTb();
 }
 
@@ -2053,7 +2081,7 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
 
     /* Check for ROS specific memory area */
     MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, *BaseAddress);
-    if ((MemoryArea) && (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW))
+    if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
     {
         /* Evil hack */
         return MiRosProtectVirtualMemory(Process,
@@ -2231,27 +2259,41 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
                 if ((NewAccessProtection & PAGE_NOACCESS) ||
                     (NewAccessProtection & PAGE_GUARD))
                 {
-                    /* The page should be in the WS and we should make it transition now */
-                    DPRINT1("Making valid page invalid is not yet supported!\n");
-                    Status = STATUS_NOT_IMPLEMENTED;
-                    /* Unlock the working set */
-                    MiUnlockProcessWorkingSetUnsafe(Process, Thread);
-                    goto FailPath;
-                }
+                    KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+                    /* Mark the PTE as transition and change its protection */
+                    PteContents.u.Hard.Valid = 0;
+                    PteContents.u.Soft.Transition = 1;
+                    PteContents.u.Trans.Protection = ProtectionMask;
+                    /* Decrease PFN share count and write the PTE */
+                    MiDecrementShareCount(Pfn1, PFN_FROM_PTE(&PteContents));
+                    // FIXME: remove the page from the WS
+                    MI_WRITE_INVALID_PTE(PointerPte, PteContents);
+#ifdef CONFIG_SMP
+                    // FIXME: Should invalidate entry in every CPU TLB
+                    ASSERT(FALSE);
+#endif
+                    KeInvalidateTlbEntry(MiPteToAddress(PointerPte));
 
-                /* Write the protection mask and write it with a TLB flush */
-                Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
-                MiFlushTbAndCapture(Vad,
-                                    PointerPte,
-                                    ProtectionMask,
-                                    Pfn1,
-                                    TRUE);
+                    /* We are done for this PTE */
+                    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+                }
+                else
+                {
+                    /* Write the protection mask and write it with a TLB flush */
+                    Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
+                    MiFlushTbAndCapture(Vad,
+                                        PointerPte,
+                                        ProtectionMask,
+                                        Pfn1,
+                                        TRUE);
+                }
             }
             else
             {
                 /* We don't support these cases yet */
                 ASSERT(PteContents.u.Soft.Prototype == 0);
-                ASSERT(PteContents.u.Soft.Transition == 0);
+                //ASSERT(PteContents.u.Soft.Transition == 0);
 
                 /* The PTE is already demand-zero, just update the protection mask */
                 PteContents.u.Soft.Protection = ProtectionMask;