Author: sir_richard
Date: Thu Jul 22 18:37:27 2010
New Revision: 48190
URL:
http://svn.reactos.org/svn/reactos?rev=48190&view=rev
Log:
[NTOS]: Add support for handling a very specific type of user-fault on ARM3 memory: memory
belonging to a VAD allocation made for a PEB/TEB (read-write) that hasn't yet been
allocated.
[NTOS]: Define the demand-zero PDE template.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/i386/init…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c [iso-8859-1] Thu Jul 22 18:37:27 2010
@@ -21,6 +21,9 @@
/* Template PTE and PDE for a kernel page */
MMPTE ValidKernelPde = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1,
.u.Hard.Accessed = 1};
MMPTE ValidKernelPte = {.u.Hard.Valid = 1, .u.Hard.Write = 1, .u.Hard.Dirty = 1,
.u.Hard.Accessed = 1};
+
+/* Template PDE for a demand-zero page */
+MMPDE DemandZeroPde = {.u.Long = (MM_READWRITE <<
MM_PTE_SOFTWARE_PROTECTION_BITS)};
/* PRIVATE FUNCTIONS **********************************************************/
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Thu Jul 22 18:37:27 2010
@@ -377,6 +377,7 @@
extern MMPTE HyperTemplatePte;
extern MMPDE ValidKernelPde;
extern MMPTE ValidKernelPte;
+extern MMPDE DemandZeroPde;
extern BOOLEAN MmLargeSystemCache;
extern BOOLEAN MmZeroPageFile;
extern BOOLEAN MmProtectFreedNonPagedPool;
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] Thu Jul 22 18:37:27 2010
@@ -20,6 +20,34 @@
/* PRIVATE FUNCTIONS **********************************************************/
+PMMPTE
+NTAPI
+MiCheckVirtualAddress(IN PVOID VirtualAddress,
+ OUT PULONG ProtectCode,
+ OUT PMMVAD *ProtoVad)
+{
+ PMMVAD Vad;
+
+ /* No prototype/section support for now */
+ *ProtoVad = NULL;
+
+ /* Only valid for user VADs for now */
+ ASSERT(VirtualAddress <= MM_HIGHEST_USER_ADDRESS);
+
+ /* Find the VAD, it must exist, since we only handle PEB/TEB */
+ Vad = MiLocateAddress(VirtualAddress);
+ ASSERT(Vad);
+
+ /* This must be a TEB/PEB VAD */
+ ASSERT(Vad->u.VadFlags.PrivateMemory == TRUE);
+ ASSERT(Vad->u.VadFlags.MemCommit == TRUE);
+ ASSERT(Vad->u.VadFlags.VadType == VadNone);
+
+ /* Return the protection on it */
+ *ProtectCode = Vad->u.VadFlags.Protection;
+ return NULL;
+}
+
NTSTATUS
FASTCALL
MiCheckPdeForPagedPool(IN PVOID Address)
@@ -300,6 +328,9 @@
PEPROCESS CurrentProcess;
NTSTATUS Status;
PMMSUPPORT WorkingSet;
+ ULONG ProtectionCode;
+ PMMVAD Vad;
+ PFN_NUMBER PageFrameIndex;
DPRINT("ARM3 FAULT AT: %p\n", Address);
//
@@ -494,12 +525,101 @@
/* Lock the working set */
MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
- /* Do something */
+ /* First things first, is the PDE valid? */
+ ASSERT(PointerPde != MiAddressToPde(PTE_BASE));
+ ASSERT(PointerPde->u.Hard.LargePage == 0);
+ if (PointerPde->u.Hard.Valid == 0)
+ {
+ /* Right now, we only handle scenarios where the PDE is totally empty */
+ ASSERT(PointerPde->u.Long == 0);
+
+ /* Check if this address range belongs to a valid allocation (VAD) */
+ MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
+
+ /* Right now, we expect a valid protection mask on the VAD */
+ ASSERT(ProtectionCode != MM_NOACCESS);
+
+ /* Make the PDE demand-zero */
+ MI_WRITE_INVALID_PTE(PointerPde, DemandZeroPde);
+
+ /* And go dispatch the fault on the PDE. This should handle the demand-zero */
+ Status = MiDispatchFault(TRUE,
+ PointerPte,
+ PointerPde,
+ NULL,
+ FALSE,
+ PsGetCurrentProcess(),
+ TrapInformation,
+ NULL);
+
+ /* We should come back with APCs enabled, and with a valid PDE */
+ ASSERT(KeAreAllApcsDisabled() == TRUE);
+ ASSERT(PointerPde->u.Hard.Valid == 1);
+ }
+
+ /* Now capture the PTE. We only handle cases where it's totally empty */
+ TempPte = *PointerPte;
+ ASSERT(TempPte.u.Long == 0);
+
+ /* Check if this address range belongs to a valid allocation (VAD) */
+ MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
+
+ /* Right now, we expect a valid protection mask on the VAD */
+ ASSERT(ProtectionCode != MM_NOACCESS);
+ PointerPte->u.Soft.Protection = ProtectionCode;
+
+ /* Lock the PFN database since we're going to grab a page */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Grab a page out of there. Later we should grab a colored zero page */
+ PageFrameIndex = MiRemoveAnyPage(0);
+ ASSERT(PageFrameIndex);
+
+ /* Release the lock since we need to do some zeroing */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Zero out the page, since it's for user-mode */
+ MiZeroPfn(PageFrameIndex);
+
+ /* Grab the lock again so we can initialize the PFN entry */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Initialize the PFN entry now */
+ MiInitializePfn(PageFrameIndex, PointerPte, 1);
+
+ /* And we're done with the lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* One more demand-zero fault */
+ InterlockedIncrement(&KeGetCurrentPrcb()->MmDemandZeroCount);
+
+ /* Was the fault on an actual user page, or a kernel page for the user? */
+ if (PointerPte <= MiHighestUserPte)
+ {
+ /* User fault, build a user PTE */
+ MI_MAKE_HARDWARE_PTE_USER(&TempPte,
+ PointerPte,
+ PointerPte->u.Soft.Protection,
+ PageFrameIndex);
+ }
+ else
+ {
+ /* Session, kernel, or user PTE, figure it out and build it */
+ MI_MAKE_HARDWARE_PTE(&TempPte,
+ PointerPte,
+ PointerPte->u.Soft.Protection,
+ PageFrameIndex);
+ }
+
+ /* Write the dirty bit for writeable pages */
+ if (TempPte.u.Hard.Write) TempPte.u.Hard.Dirty = TRUE;
+
+ /* And now write down the PTE, making the address valid */
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
/* Release the working set */
MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
- DPRINT1("WARNING: USER MODE FAULT IN ARM3???\n");
- return STATUS_ACCESS_VIOLATION;
+ return STATUS_PAGE_FAULT_DEMAND_ZERO;
}
/* EOF */