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?re... ============================================================================== --- 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.c... ============================================================================== --- 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 */