Author: tkreuzer
Date: Mon Feb 6 15:08:32 2012
New Revision: 55462
URL: http://svn.reactos.org/svn/reactos?rev=55462&view=rev
Log:
[NTOSKRNL]
Handle 3 and 4 level page tables in MmArmAccessFault
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.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] Mon Feb 6 15:08:32 2012
@@ -180,6 +180,13 @@
// Return status
//
return Status;
+}
+#else
+NTSTATUS
+FASTCALL
+MiCheckPdeForPagedPool(IN PVOID Address)
+{
+ return STATUS_ACCESS_VIOLATION;
}
#endif
@@ -784,7 +791,6 @@
CurrentProcess = NULL;
}
-
/* Acquire the working set lock */
KeRaiseIrql(APC_LEVEL, &LockIrql);
MiLockWorkingSet(CurrentThread, WorkingSet);
@@ -902,16 +908,42 @@
}
#if (_MI_PAGING_LEVELS == 4)
- /* On these systems we have PXEs and PPEs ready for everything we need */
- if (PointerPxe->u.Hard.Valid == 0) return STATUS_ACCESS_VIOLATION;
+ /* Check if the PXE is valid */
+ if (PointerPxe->u.Hard.Valid == 0)
+ {
+ /* Right now, we only handle scenarios where the PXE is totally empty */
+ ASSERT(PointerPxe->u.Long == 0);
+
+ /* Resolve a demand zero fault */
+ Status = MiResolveDemandZeroFault(PointerPpe,
+ MM_READWRITE,
+ CurrentProcess,
+ MM_NOIRQL);
+
+ /* We should come back with a valid PXE */
+ ASSERT(PointerPxe->u.Hard.Valid == 1);
+ }
#endif
#if (_MI_PAGING_LEVELS >= 3)
- if (PointerPpe->u.Hard.Valid == 0) return STATUS_ACCESS_VIOLATION;
-#endif
-
-
- /* First things first, is the PDE valid? */
+ /* Check if the PPE is valid */
+ if (PointerPpe->u.Hard.Valid == 0)
+ {
+ /* Right now, we only handle scenarios where the PPE is totally empty */
+ ASSERT(PointerPpe->u.Long == 0);
+
+ /* Resolve a demand zero fault */
+ Status = MiResolveDemandZeroFault(PointerPde,
+ MM_READWRITE,
+ CurrentProcess,
+ MM_NOIRQL);
+
+ /* We should come back with a valid PPE */
+ ASSERT(PointerPpe->u.Hard.Valid == 1);
+ }
+#endif
+
+ /* Check if the PDE is valid */
if (PointerPde->u.Hard.Valid == 0)
{
/* Right now, we only handle scenarios where the PDE is totally empty */
@@ -983,12 +1015,11 @@
return Status;
}
-
- {
- /* Add an additional page table reference */
- MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
- ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
- }
+#if (_MI_PAGING_LEVELS == 2)
+ /* Add an additional page table reference */
+ MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
+ ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
+#endif
/* Did we get a prototype PTE back? */
if (!ProtoPte)
Author: tkreuzer
Date: Mon Feb 6 14:35:09 2012
New Revision: 55460
URL: http://svn.reactos.org/svn/reactos?rev=55460&view=rev
Log:
[NTOSKRNL]
Add a modification that I missed to apply.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.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] Mon Feb 6 14:35:09 2012
@@ -764,6 +764,9 @@
return STATUS_SUCCESS;
}
+ /* Get the current thread */
+ CurrentThread = PsGetCurrentThread();
+
// Check for a fault on the page table or hyperspace
if (MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address))
{
@@ -781,8 +784,6 @@
CurrentProcess = NULL;
}
- /* Get the current thread */
- CurrentThread = PsGetCurrentThread();
/* Acquire the working set lock */
KeRaiseIrql(APC_LEVEL, &LockIrql);
Author: tkreuzer
Date: Mon Feb 6 14:32:07 2012
New Revision: 55459
URL: http://svn.reactos.org/svn/reactos?rev=55459&view=rev
Log:
[NTOSKRNL]
- Modify the logic in MmArmAccessFault, so that faults on kernel mode addresses including page table addresses are handled in the first part and user mode addresses (VADs) in the second part. This works, because for the special case of page table addresses, the user mode and kernel mode part of the code end up doing the same thing and this simplifies the code.
- In the user mode part call MiCheckVirtualAddress early and bail out if no VAD is found, since we do not care about any other cases any more.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.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] Mon Feb 6 14:32:07 2012
@@ -697,7 +697,7 @@
}
/* Check for kernel fault address */
- while (Address >= MmSystemRangeStart)
+ if (Address >= MmSystemRangeStart)
{
/* Bail out, if the fault came from user mode */
if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
@@ -716,6 +716,17 @@
StoreInstruction,
(ULONG_PTR)TrapInformation,
2);
+ }
+#endif
+
+#if (_MI_PAGING_LEVELS == 2)
+ /* Check if we have a situation that might need synchronization
+ of the PDE with the system page directory */
+ if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address))
+ {
+ /* This could be a paged pool commit with an unsychronized PDE.
+ NOTE: This way it works on x86, verify for other architectures! */
+ if (MiSynchronizeSystemPde((PMMPDE)PointerPte)) return STATUS_SUCCESS;
}
#endif
@@ -756,23 +767,24 @@
// Check for a fault on the page table or hyperspace
if (MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address))
{
-#if (_MI_PAGING_LEVELS == 2)
- /* Could be paged pool access from a new process -- synchronize the page directories */
- if (MiCheckPdeForPagedPool(Address) == STATUS_WAIT_1)
- {
- DPRINT1("PAGE TABLES FAULTED IN!\n");
- return STATUS_SUCCESS;
- }
-#endif
- /* Otherwise this could be a commit of a virtual address */
- break;
- }
-
- /* In this path, we are using the system working set */
+ ASSERT(TempPte.u.Long != (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS));
+ ASSERT(TempPte.u.Soft.Prototype == 0);
+
+ /* Use the process working set */
+ CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
+ WorkingSet = &CurrentProcess->Vm;
+ }
+ else
+ {
+ /* Otherwise use the system working set */
+ WorkingSet = &MmSystemCacheWs;
+ CurrentProcess = NULL;
+ }
+
+ /* Get the current thread */
CurrentThread = PsGetCurrentThread();
- WorkingSet = &MmSystemCacheWs;
-
- /* Acquire it */
+
+ /* Acquire the working set lock */
KeRaiseIrql(APC_LEVEL, &LockIrql);
MiLockWorkingSet(CurrentThread, WorkingSet);
@@ -854,7 +866,7 @@
PointerPte,
ProtoPte,
FALSE,
- NULL,
+ CurrentProcess,
TrapInformation,
NULL);
@@ -868,30 +880,41 @@
return Status;
}
+ /* This is a user fault */
+ CurrentThread = PsGetCurrentThread();
+ CurrentProcess = (PEPROCESS)CurrentThread->Tcb.ApcState.Process;
+
+ /* Lock the working set */
+ MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
+
+#if (_MI_PAGING_LEVELS == 2)
+ ASSERT(PointerPde->u.Hard.LargePage == 0);
+#endif
+
+ /* Check if this address range belongs to a valid allocation (VAD) */
+ ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
+ if (ProtectionCode == MM_NOACCESS)
+ {
+ /* This is a bogus VA */
+ MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
#if (_MI_PAGING_LEVELS == 4)
/* On these systems we have PXEs and PPEs ready for everything we need */
if (PointerPxe->u.Hard.Valid == 0) return STATUS_ACCESS_VIOLATION;
#endif
+
#if (_MI_PAGING_LEVELS >= 3)
if (PointerPpe->u.Hard.Valid == 0) return STATUS_ACCESS_VIOLATION;
#endif
- /* This is a user fault (<- And this is a lie!) */
- CurrentThread = PsGetCurrentThread();
- CurrentProcess = PsGetCurrentProcess();
-
- /* Lock the working set */
- MiLockProcessWorkingSet(CurrentProcess, CurrentThread);
/* First things first, is the PDE valid? */
- 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);
@@ -921,6 +944,7 @@
if (TempPte.u.Long == (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS))
{
/* Resolve the fault */
+ MI_WRITE_INVALID_PDE(PointerPde, DemandZeroPde);
MiResolveDemandZeroFault(Address,
(ULONG)PointerPte->u.Soft.Protection,
CurrentProcess,
@@ -937,8 +961,7 @@
/* Check for non-demand zero PTE */
if (TempPte.u.Long != 0)
{
- /* This is a page fault, check for valid protection */
- ASSERT(TempPte.u.Soft.Protection != 0x100);
+ /* This is a page fault */
/* FIXME: Run MiAccessCheck */
@@ -959,28 +982,7 @@
return Status;
}
- /* Check if this address range belongs to a valid allocation (VAD) */
- ASSERT(TempPte.u.Long == 0);
- ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
- if (ProtectionCode == MM_NOACCESS)
- {
- /* This is a bogus VA */
- Status = STATUS_ACCESS_VIOLATION;
-
- /* Could be a not-yet-mapped paged pool page table */
-#if (_MI_PAGING_LEVELS == 2)
- MiCheckPdeForPagedPool(Address);
-#endif
- /* See if that fixed it */
- if (PointerPte->u.Hard.Valid == 1) Status = STATUS_SUCCESS;
-
- /* Return the status */
- MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
- return Status;
- }
-
- /* Is this a user address? */
- if (Address <= MM_HIGHEST_USER_ADDRESS)
+
{
/* Add an additional page table reference */
MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
@@ -1026,24 +1028,11 @@
/* And we're done with the lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
- /* 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);
- }
+ /* User fault, build a user PTE */
+ MI_MAKE_HARDWARE_PTE_USER(&TempPte,
+ PointerPte,
+ PointerPte->u.Soft.Protection,
+ PageFrameIndex);
/* Write the dirty bit for writeable pages */
if (MI_IS_PAGE_WRITEABLE(&TempPte)) MI_MAKE_DIRTY_PAGE(&TempPte);
Author: tkreuzer
Date: Mon Feb 6 10:46:52 2012
New Revision: 55456
URL: http://svn.reactos.org/svn/reactos?rev=55456&view=rev
Log:
[NTOSKRNL]
- Implement MiSynchronizeSystemPde, which does what its name suggests, synchronize a system PDE and is an improved replacement (with a more proper name) for MiCheckPdeForPagedPool
- Move some code to avoid an additional check
- Call MiResolveDemandZeroFault directy instead of creating a demand zero PDE and then calling MiDispatchFault, which after a lot of checks will finally do the same
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.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] Mon Feb 6 10:46:52 2012
@@ -100,6 +100,28 @@
}
}
+#if (_MI_PAGING_LEVELS == 2)
+BOOLEAN
+FORCEINLINE
+MiSynchronizeSystemPde(PMMPDE PointerPde)
+{
+ MMPDE SystemPde;
+ ULONG Index;
+
+ /* Get the Index from the PDE */
+ Index = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE);
+
+ /* Copy the PDE from the double-mapped system page directory */
+ SystemPde = MmSystemPagePtes[Index];
+ *PointerPde = SystemPde;
+
+ /* Make sure we re-read the PDE and PTE */
+ KeMemoryBarrierWithoutFence();
+
+ /* Return, if we had success */
+ return (BOOLEAN)SystemPde.u.Hard.Valid;
+}
+
NTSTATUS
FASTCALL
MiCheckPdeForPagedPool(IN PVOID Address)
@@ -159,6 +181,7 @@
//
return Status;
}
+#endif
VOID
NTAPI
@@ -699,28 +722,12 @@
/* Check if the PDE is invalid */
if (PointerPde->u.Hard.Valid == 0)
{
- //
- // Debug spew (eww!)
- //
- DPRINT("Invalid PDE\n");
#if (_MI_PAGING_LEVELS == 2)
- //
- // Handle mapping in "Special" PDE directoreis
- //
- MiCheckPdeForPagedPool(Address);
-#endif
- //
- // Now we SHOULD be good
- //
- if (PointerPde->u.Hard.Valid == 0)
+ /* Sync this PDE and check, if that made it valid */
+ if (!MiSynchronizeSystemPde(PointerPde))
+#endif
{
- //
- // FIXFIX: Do the S-LIST hack
- //
-
- //
- // Kill the system
- //
+ /* PDE (still) not valid, kill the system */
KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
(ULONG_PTR)Address,
StoreInstruction,
@@ -824,20 +831,20 @@
(ULONG_PTR)TrapInformation,
1);
}
- }
-
- /* Check for demand page */
- if ((StoreInstruction) && !(ProtoPte) && !(TempPte.u.Hard.Valid))
- {
- /* Get the protection code */
- if (!(TempPte.u.Soft.Protection & MM_READWRITE))
+
+ /* Check for demand page */
+ if ((StoreInstruction) && !(TempPte.u.Hard.Valid))
{
- /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
- KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
- (ULONG_PTR)Address,
- TempPte.u.Long,
- (ULONG_PTR)TrapInformation,
- 14);
+ /* Get the protection code */
+ if (!(TempPte.u.Soft.Protection & MM_READWRITE))
+ {
+ /* Bugcheck the system! */
+ KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
+ (ULONG_PTR)Address,
+ TempPte.u.Long,
+ (ULONG_PTR)TrapInformation,
+ 14);
+ }
}
}
@@ -889,21 +896,15 @@
/* Right now, we expect a valid protection mask on the VAD */
ASSERT(ProtectionCode != MM_NOACCESS);
- /* Make the PDE demand-zero */
- MI_WRITE_INVALID_PDE(PointerPde, DemandZeroPde);
-
/* And go dispatch the fault on the PDE. This should handle the demand-zero */
#if MI_TRACE_PFNS
UserPdeFault = TRUE;
#endif
- Status = MiDispatchFault(TRUE,
- PointerPte,
- (PMMPTE)PointerPde,
- NULL,
- FALSE,
- PsGetCurrentProcess(),
- TrapInformation,
- NULL);
+ /* Resolve a demand zero fault */
+ Status = MiResolveDemandZeroFault(PointerPte,
+ MM_READWRITE,
+ CurrentProcess,
+ MM_NOIRQL);
#if MI_TRACE_PFNS
UserPdeFault = FALSE;
#endif
@@ -930,15 +931,14 @@
return STATUS_PAGE_FAULT_DEMAND_ZERO;
}
- /* Get protection and check if it's a prototype PTE */
- ProtectionCode = (ULONG)TempPte.u.Soft.Protection;
+ /* Make sure it's not a prototype PTE */
ASSERT(TempPte.u.Soft.Prototype == 0);
/* Check for non-demand zero PTE */
if (TempPte.u.Long != 0)
{
/* This is a page fault, check for valid protection */
- ASSERT(ProtectionCode != 0x100);
+ ASSERT(TempPte.u.Soft.Protection != 0x100);
/* FIXME: Run MiAccessCheck */