Author: jgardou Date: Fri Jul 25 22:13:35 2014 New Revision: 63736
URL: http://svn.reactos.org/svn/reactos?rev=63736&view=rev Log: [NTOS/MM] - First implementation of NtProtectVirtualMemory with Transition PTE - Release PTE frame page after erasing the PTE to avoid useless page fault
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c trunk/reactos/ntoskrnl/mm/ARM3/virtual.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Fri Jul 25 22:13:35 2014 @@ -1310,20 +1310,41 @@ } }
+ /* 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);
//
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c?... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] Fri Jul 25 22:13:35 2014 @@ -292,7 +292,6 @@ 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 @@ 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 */
Modified: trunk/reactos/ntoskrnl/mm/ARM3/virtual.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/virtual.c?... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/virtual.c [iso-8859-1] Fri Jul 25 22:13:35 2014 @@ -404,13 +404,36 @@ /* 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 @@ (ULONG_PTR)Pfn1->PteAddress); } } + + /* Erase it */ + MI_ERASE_PTE(PointerPte); } else { @@ -471,6 +497,9 @@ (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 @@ //CurrentProcess->NumberOfPrivatePages--; }
- /* Destroy the PTE and flush the TLB */ - MI_ERASE_PTE(PointerPte); + /* Flush the TLB */ KeFlushCurrentTb(); }
@@ -2053,7 +2081,7 @@
/* 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 @@ 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)); + + /* We are done for this PTE */ + KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); } - - /* Write the protection mask and write it with a TLB flush */ - Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask; - MiFlushTbAndCapture(Vad, - PointerPte, - ProtectionMask, - Pfn1, - TRUE); + 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;