[ÇNTOSKRNL]

- modify MiResolveDemandZeroFault to take the page protection as a parameter instead of the PTE. This will be used soon.
- Move increment of counters into the region where the pfn lock is held to avoid race conditions and make heavy locked operations unneccessary
- Add some ASSERTs

svn path=/trunk/; revision=55454
This commit is contained in:
Timo Kreuzer 2012-02-06 09:26:23 +00:00
parent 12f8a6d6a6
commit b207b33d11

View file

@ -209,11 +209,12 @@ MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
NTSTATUS NTSTATUS
NTAPI NTAPI
MiResolveDemandZeroFault(IN PVOID Address, MiResolveDemandZeroFault(IN PVOID Address,
IN PMMPTE PointerPte, IN ULONG Protection,
IN PEPROCESS Process, IN PEPROCESS Process,
IN KIRQL OldIrql) IN KIRQL OldIrql)
{ {
PFN_NUMBER PageFrameNumber = 0; PFN_NUMBER PageFrameNumber = 0;
PMMPTE PointerPte = MiAddressToPte(Address);
MMPTE TempPte; MMPTE TempPte;
BOOLEAN NeedZero = FALSE, HaveLock = FALSE; BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
ULONG Color; ULONG Color;
@ -294,14 +295,12 @@ MiResolveDemandZeroFault(IN PVOID Address,
/* Initialize it */ /* Initialize it */
MiInitializePfn(PageFrameNumber, PointerPte, TRUE); MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
/* Increment demand zero faults */
KeGetCurrentPrcb()->MmDemandZeroCount++;
/* Release PFN lock if needed */ /* Release PFN lock if needed */
if (HaveLock) KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); if (HaveLock) KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
//
// Increment demand zero faults
//
InterlockedIncrement(&KeGetCurrentPrcb()->MmDemandZeroCount);
/* Zero the page if need be */ /* Zero the page if need be */
if (NeedZero) MiZeroPfn(PageFrameNumber); if (NeedZero) MiZeroPfn(PageFrameNumber);
@ -311,7 +310,7 @@ MiResolveDemandZeroFault(IN PVOID Address,
/* For user mode */ /* For user mode */
MI_MAKE_HARDWARE_PTE_USER(&TempPte, MI_MAKE_HARDWARE_PTE_USER(&TempPte,
PointerPte, PointerPte,
PointerPte->u.Soft.Protection, Protection,
PageFrameNumber); PageFrameNumber);
} }
else else
@ -319,7 +318,7 @@ MiResolveDemandZeroFault(IN PVOID Address,
/* For kernel mode */ /* For kernel mode */
MI_MAKE_HARDWARE_PTE(&TempPte, MI_MAKE_HARDWARE_PTE(&TempPte,
PointerPte, PointerPte,
PointerPte->u.Soft.Protection, Protection,
PageFrameNumber); PageFrameNumber);
} }
@ -462,7 +461,10 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
ASSERT(TempPte.u.Soft.Transition == 0); ASSERT(TempPte.u.Soft.Transition == 0);
/* Resolve the demand zero fault */ /* Resolve the demand zero fault */
Status = MiResolveDemandZeroFault(Address, PointerProtoPte, Process, OldIrql); Status = MiResolveDemandZeroFault(Address,
(ULONG)PointerProtoPte->u.Soft.Protection,
Process,
OldIrql);
ASSERT(NT_SUCCESS(Status)); ASSERT(NT_SUCCESS(Status));
/* Complete the prototype PTE fault -- this will release the PFN lock */ /* Complete the prototype PTE fault -- this will release the PFN lock */
@ -494,6 +496,9 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
Address, Address,
Process); Process);
/* Make sure the addresses are ok */
ASSERT(PointerPte == MiAddressToPte(Address));
// //
// Make sure APCs are off and we're not at dispatch // Make sure APCs are off and we're not at dispatch
// //
@ -609,7 +614,7 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
// we want. Go handle it! // we want. Go handle it!
// //
Status = MiResolveDemandZeroFault(Address, Status = MiResolveDemandZeroFault(Address,
PointerPte, (ULONG)PointerPte->u.Soft.Protection,
Process, Process,
MM_NOIRQL); MM_NOIRQL);
ASSERT(KeAreAllApcsDisabled() == TRUE); ASSERT(KeAreAllApcsDisabled() == TRUE);
@ -658,30 +663,23 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
DPRINT("ARM3 FAULT AT: %p\n", Address); DPRINT("ARM3 FAULT AT: %p\n", Address);
// /* Check for page fault on high IRQL */
// Check for dispatch-level snafu
//
if (OldIrql > APC_LEVEL) if (OldIrql > APC_LEVEL)
{ {
//
// There are some special cases where this is okay, but not in ARM3 yet // There are some special cases where this is okay, but not in ARM3 yet
//
DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n", DbgPrint("MM:***PAGE FAULT AT IRQL > 1 Va %p, IRQL %lx\n",
Address, Address,
OldIrql); OldIrql);
ASSERT(OldIrql <= APC_LEVEL); ASSERT(OldIrql <= APC_LEVEL);
} }
// /* Check for kernel fault address */
// Check for kernel fault address
//
while (Address >= MmSystemRangeStart) while (Address >= MmSystemRangeStart)
{ {
// /* Bail out, if the fault came from user mode */
// What are you even DOING here?
//
if (Mode == UserMode) return STATUS_ACCESS_VIOLATION; if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
/* PXEs and PPEs for kernel mode are mapped for everything we need */
#if (_MI_PAGING_LEVELS >= 3) #if (_MI_PAGING_LEVELS >= 3)
if ( if (
#if (_MI_PAGING_LEVELS == 4) #if (_MI_PAGING_LEVELS == 4)
@ -689,6 +687,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
#endif #endif
(PointerPpe->u.Hard.Valid == 0)) (PointerPpe->u.Hard.Valid == 0))
{ {
/* The address is not from any pageable area! */
KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA, KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
(ULONG_PTR)Address, (ULONG_PTR)Address,
StoreInstruction, StoreInstruction,
@ -697,9 +696,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
} }
#endif #endif
// /* Check if the PDE is invalid */
// Is the PDE valid?
//
if (PointerPde->u.Hard.Valid == 0) if (PointerPde->u.Hard.Valid == 0)
{ {
// //
@ -732,9 +729,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
} }
} }
// /* The PDE is valid, so read the PTE */
// The PDE is valid, so read the PTE
//
TempPte = *PointerPte; TempPte = *PointerPte;
if (TempPte.u.Hard.Valid == 1) if (TempPte.u.Hard.Valid == 1)
{ {
@ -751,9 +746,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
// // Check for a fault on the page table or hyperspace
// Check for a fault on the page table or hyperspace itself
//
if (MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address)) if (MI_IS_PAGE_TABLE_OR_HYPER_ADDRESS(Address))
{ {
#if (_MI_PAGING_LEVELS == 2) #if (_MI_PAGING_LEVELS == 2)
@ -776,26 +769,21 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
KeRaiseIrql(APC_LEVEL, &LockIrql); KeRaiseIrql(APC_LEVEL, &LockIrql);
MiLockWorkingSet(CurrentThread, WorkingSet); MiLockWorkingSet(CurrentThread, WorkingSet);
// /* Re-read PTE now that we own the lock */
// Re-read PTE now that the IRQL has been raised
//
TempPte = *PointerPte; TempPte = *PointerPte;
if (TempPte.u.Hard.Valid == 1) if (TempPte.u.Hard.Valid == 1)
{ {
//
// Only two things can go wrong here: // Only two things can go wrong here:
// Executing NX page (we couldn't care less) // Executing NX page (we couldn't care less)
// Writing to a read-only page (the stuff ARM3 works with is write, // Writing to a read-only page (the stuff ARM3 works with is write,
// so again, moot point. // so again, moot point).
// ASSERT(TempPte.u.Hard.Write == 1);
/* Release the working set */ /* Release the working set */
MiUnlockWorkingSet(CurrentThread, WorkingSet); MiUnlockWorkingSet(CurrentThread, WorkingSet);
KeLowerIrql(LockIrql); KeLowerIrql(LockIrql);
//
// Otherwise, the PDE was probably invalid, and all is good now // Otherwise, the PDE was probably invalid, and all is good now
//
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -823,15 +811,13 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
} }
else else
{ {
// /* We don't implement transition PTEs */
// We don't implement transition PTEs
//
ASSERT(TempPte.u.Soft.Transition == 0); ASSERT(TempPte.u.Soft.Transition == 0);
/* Check for no-access PTE */ /* Check for no-access PTE */
if (TempPte.u.Soft.Protection == MM_NOACCESS) if (TempPte.u.Soft.Protection == MM_NOACCESS)
{ {
/* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */ /* Bugcheck the system! */
KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA, KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
(ULONG_PTR)Address, (ULONG_PTR)Address,
StoreInstruction, StoreInstruction,
@ -855,9 +841,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
} }
} }
// /* Now do the real fault handling */
// Now do the real fault handling
//
Status = MiDispatchFault(StoreInstruction, Status = MiDispatchFault(StoreInstruction,
Address, Address,
PointerPte, PointerPte,
@ -872,9 +856,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
MiUnlockWorkingSet(CurrentThread, WorkingSet); MiUnlockWorkingSet(CurrentThread, WorkingSet);
KeLowerIrql(LockIrql); KeLowerIrql(LockIrql);
// /* We are done! */
// We are done!
//
DPRINT("Fault resolved with status: %lx\n", Status); DPRINT("Fault resolved with status: %lx\n", Status);
return Status; return Status;
} }
@ -939,7 +921,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
{ {
/* Resolve the fault */ /* Resolve the fault */
MiResolveDemandZeroFault(Address, MiResolveDemandZeroFault(Address,
PointerPte, (ULONG)PointerPte->u.Soft.Protection,
CurrentProcess, CurrentProcess,
MM_NOIRQL); MM_NOIRQL);
@ -1038,11 +1020,12 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
/* Initialize the PFN entry now */ /* Initialize the PFN entry now */
MiInitializePfn(PageFrameIndex, PointerPte, 1); MiInitializePfn(PageFrameIndex, PointerPte, 1);
/* One more demand-zero fault */
KeGetCurrentPrcb()->MmDemandZeroCount++;
/* And we're done with the lock */ /* And we're done with the lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 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? */ /* Was the fault on an actual user page, or a kernel page for the user? */
if (PointerPte <= MiHighestUserPte) if (PointerPte <= MiHighestUserPte)