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.…
==============================================================================
--- 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;