mirror of
https://github.com/reactos/reactos.git
synced 2024-07-31 16:48:14 +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
|
// 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
|
// prototype or transition PTE as those scenarii should've been handled above.
|
||||||
// all Windows checks
|
// These are all Windows checks
|
||||||
//
|
//
|
||||||
ASSERT(TempPte.u.Hard.Valid == 0);
|
ASSERT(TempPte.u.Hard.Valid == 0);
|
||||||
ASSERT(TempPte.u.Soft.Prototype == 0);
|
ASSERT(TempPte.u.Soft.Prototype == 0);
|
||||||
|
ASSERT(TempPte.u.Soft.Transition == 0);
|
||||||
ASSERT(TempPte.u.Long != 0);
|
ASSERT(TempPte.u.Long != 0);
|
||||||
|
|
||||||
//
|
//
|
||||||
// No transition or page file software PTEs in ARM3 yet, so this must be a
|
// No page file software PTEs in ARM3 yet, so this must be a
|
||||||
// demand zero page. These are all ReactOS checks
|
// demand zero page. This is a ReactOS check.
|
||||||
//
|
//
|
||||||
ASSERT(TempPte.u.Soft.Transition == 0);
|
|
||||||
ASSERT(TempPte.u.Soft.PageFileHigh == 0);
|
ASSERT(TempPte.u.Soft.PageFileHigh == 0);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -292,7 +292,6 @@ MiUnlinkPageFromList(IN PMMPFN Pfn)
|
||||||
ListHead = &MmModifiedPageListByColor[0];
|
ListHead = &MmModifiedPageListByColor[0];
|
||||||
|
|
||||||
/* Decrease transition page counter */
|
/* Decrease transition page counter */
|
||||||
ASSERT(Pfn->u3.e1.PrototypePte == 1); /* Only supported ARM3 case */
|
|
||||||
MmTransitionSharedPages--;
|
MmTransitionSharedPages--;
|
||||||
}
|
}
|
||||||
else if (ListHead == &MmModifiedNoWritePageListHead)
|
else if (ListHead == &MmModifiedNoWritePageListHead)
|
||||||
|
@ -984,7 +983,6 @@ MiInsertPageInList(IN PMMPFNLIST ListHead,
|
||||||
ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
|
ASSERT(Pfn1->OriginalPte.u.Soft.PageFileHigh == 0);
|
||||||
|
|
||||||
/* One more transition page */
|
/* One more transition page */
|
||||||
ASSERT(Pfn1->u3.e1.PrototypePte == 1);
|
|
||||||
MmTransitionSharedPages++;
|
MmTransitionSharedPages++;
|
||||||
|
|
||||||
/* Increment the number of per-process modified pages */
|
/* Increment the number of per-process modified pages */
|
||||||
|
|
|
@ -404,13 +404,36 @@ MiDeletePte(IN PMMPTE PointerPte,
|
||||||
/* Capture the PTE */
|
/* Capture the PTE */
|
||||||
TempPte = *PointerPte;
|
TempPte = *PointerPte;
|
||||||
|
|
||||||
/* We only support valid PTEs for now */
|
/* See if the PTE is valid */
|
||||||
ASSERT(TempPte.u.Hard.Valid == 1);
|
|
||||||
if (TempPte.u.Hard.Valid == 0)
|
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.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 */
|
/* Get the PFN entry */
|
||||||
|
@ -457,6 +480,9 @@ MiDeletePte(IN PMMPTE PointerPte,
|
||||||
(ULONG_PTR)Pfn1->PteAddress);
|
(ULONG_PTR)Pfn1->PteAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Erase it */
|
||||||
|
MI_ERASE_PTE(PointerPte);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -471,6 +497,9 @@ MiDeletePte(IN PMMPTE PointerPte,
|
||||||
(ULONG_PTR)Pfn1->PteAddress);
|
(ULONG_PTR)Pfn1->PteAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Erase the PTE */
|
||||||
|
MI_ERASE_PTE(PointerPte);
|
||||||
|
|
||||||
/* There should only be 1 shared reference count */
|
/* There should only be 1 shared reference count */
|
||||||
ASSERT(Pfn1->u2.ShareCount == 1);
|
ASSERT(Pfn1->u2.ShareCount == 1);
|
||||||
|
|
||||||
|
@ -485,8 +514,7 @@ MiDeletePte(IN PMMPTE PointerPte,
|
||||||
//CurrentProcess->NumberOfPrivatePages--;
|
//CurrentProcess->NumberOfPrivatePages--;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Destroy the PTE and flush the TLB */
|
/* Flush the TLB */
|
||||||
MI_ERASE_PTE(PointerPte);
|
|
||||||
KeFlushCurrentTb();
|
KeFlushCurrentTb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2053,7 +2081,7 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
|
||||||
|
|
||||||
/* Check for ROS specific memory area */
|
/* Check for ROS specific memory area */
|
||||||
MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, *BaseAddress);
|
MemoryArea = MmLocateMemoryAreaByAddress(&Process->Vm, *BaseAddress);
|
||||||
if ((MemoryArea) && (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW))
|
if ((MemoryArea) && (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3))
|
||||||
{
|
{
|
||||||
/* Evil hack */
|
/* Evil hack */
|
||||||
return MiRosProtectVirtualMemory(Process,
|
return MiRosProtectVirtualMemory(Process,
|
||||||
|
@ -2231,14 +2259,27 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
|
||||||
if ((NewAccessProtection & PAGE_NOACCESS) ||
|
if ((NewAccessProtection & PAGE_NOACCESS) ||
|
||||||
(NewAccessProtection & PAGE_GUARD))
|
(NewAccessProtection & PAGE_GUARD))
|
||||||
{
|
{
|
||||||
/* The page should be in the WS and we should make it transition now */
|
KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
||||||
DPRINT1("Making valid page invalid is not yet supported!\n");
|
|
||||||
Status = STATUS_NOT_IMPLEMENTED;
|
|
||||||
/* Unlock the working set */
|
|
||||||
MiUnlockProcessWorkingSetUnsafe(Process, Thread);
|
|
||||||
goto FailPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* 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 */
|
/* Write the protection mask and write it with a TLB flush */
|
||||||
Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
|
Pfn1->OriginalPte.u.Soft.Protection = ProtectionMask;
|
||||||
MiFlushTbAndCapture(Vad,
|
MiFlushTbAndCapture(Vad,
|
||||||
|
@ -2247,11 +2288,12 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
|
||||||
Pfn1,
|
Pfn1,
|
||||||
TRUE);
|
TRUE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We don't support these cases yet */
|
/* We don't support these cases yet */
|
||||||
ASSERT(PteContents.u.Soft.Prototype == 0);
|
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 */
|
/* The PTE is already demand-zero, just update the protection mask */
|
||||||
PteContents.u.Soft.Protection = ProtectionMask;
|
PteContents.u.Soft.Protection = ProtectionMask;
|
||||||
|
|
Loading…
Reference in a new issue