mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 04:35:07 +00:00
[NTOS/MM]
- 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
This commit is contained in:
parent
f3b4339291
commit
0e90ca943e
|
@ -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);
|
||||
|
||||
//
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* Write the protection mask and write it with a TLB flush */
|
||||
Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
|
||||
MiFlushTbAndCapture(Vad,
|
||||
PointerPte,
|
||||
ProtectionMask,
|
||||
Pfn1,
|
||||
TRUE);
|
||||
/* 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);
|
||||
}
|
||||
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;
|
||||
|
|
Loading…
Reference in a new issue