[NTOSKRNL]

- Get rid of MmZeroPte and instead implement MI_ERASE_PTE. Use this and only this to make a PTE zero. The other functions will not allow to do this.
- Add MI_UPDATE_VALID_PTE to update a valid PTE with another valid PTE
- Add 2 additional protection mask constants: MM_PROTECT_ACCESS for the lower 3 bits and MM_PROTECT_SPECIAL for the higher 2 bits. Make use of the latter when dealing with guard pages and caching.
- Deduplicate some code in MmArmAccessFault
- Move code in MiDeleteSystemPageableVm to where it belongs (it was in the wrong else case!)
- Wse MiQueryPageTableReferences instead of manipulating MmWorkingSetList->UsedPageTableEntries

svn path=/trunk/; revision=61110
This commit is contained in:
Timo Kreuzer 2013-11-27 00:04:26 +00:00
parent 5ab8592b44
commit 4019985115
5 changed files with 75 additions and 59 deletions

View file

@ -107,6 +107,7 @@ C_ASSERT(SYSTEM_PD_SIZE == PAGE_SIZE);
#define MM_WRITECOPY 5 #define MM_WRITECOPY 5
#define MM_EXECUTE_READWRITE 6 #define MM_EXECUTE_READWRITE 6
#define MM_EXECUTE_WRITECOPY 7 #define MM_EXECUTE_WRITECOPY 7
#define MM_PROTECT_ACCESS 7
// //
// These are flags on top of the actual protection mask // These are flags on top of the actual protection mask
@ -114,6 +115,7 @@ C_ASSERT(SYSTEM_PD_SIZE == PAGE_SIZE);
#define MM_NOCACHE 0x08 #define MM_NOCACHE 0x08
#define MM_GUARDPAGE 0x10 #define MM_GUARDPAGE 0x10
#define MM_WRITECOMBINE 0x18 #define MM_WRITECOMBINE 0x18
#define MM_PROTECT_SPECIAL 0x18
// //
// These are special cases // These are special cases
@ -588,7 +590,6 @@ typedef struct _MM_SESSION_SPACE
LONG ImageLoadingCount; LONG ImageLoadingCount;
} MM_SESSION_SPACE, *PMM_SESSION_SPACE; } MM_SESSION_SPACE, *PMM_SESSION_SPACE;
static const MMPTE MmZeroPte = {{0}};
extern PMM_SESSION_SPACE MmSessionSpace; extern PMM_SESSION_SPACE MmSessionSpace;
extern MMPTE HyperTemplatePte; extern MMPTE HyperTemplatePte;
extern MMPDE ValidKernelPde; extern MMPDE ValidKernelPde;
@ -1002,6 +1003,21 @@ MI_WRITE_VALID_PTE(IN PMMPTE PointerPte,
*PointerPte = TempPte; *PointerPte = TempPte;
} }
//
// Updates a valid PTE
//
VOID
FORCEINLINE
MI_UPDATE_VALID_PTE(IN PMMPTE PointerPte,
IN MMPTE TempPte)
{
/* Write the valid PTE */
ASSERT(PointerPte->u.Hard.Valid == 1);
ASSERT(TempPte.u.Hard.Valid == 1);
ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
*PointerPte = TempPte;
}
// //
// Writes an invalid PTE // Writes an invalid PTE
// //
@ -1012,9 +1028,22 @@ MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte,
{ {
/* Write the invalid PTE */ /* Write the invalid PTE */
ASSERT(InvalidPte.u.Hard.Valid == 0); ASSERT(InvalidPte.u.Hard.Valid == 0);
ASSERT(InvalidPte.u.Long != 0);
*PointerPte = InvalidPte; *PointerPte = InvalidPte;
} }
//
// Erase the PTE completely
//
VOID
FORCEINLINE
MI_ERASE_PTE(IN PMMPTE PointerPte)
{
/* Zero out the PTE */
ASSERT(PointerPte->u.Long != 0);
PointerPte->u.Long = 0;
}
// //
// Writes a valid PDE // Writes a valid PDE
// //
@ -1039,6 +1068,7 @@ MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde,
{ {
/* Write the invalid PDE */ /* Write the invalid PDE */
ASSERT(InvalidPde.u.Hard.Valid == 0); ASSERT(InvalidPde.u.Hard.Valid == 0);
ASSERT(InvalidPde.u.Long != 0);
*PointerPde = InvalidPde; *PointerPde = InvalidPde;
} }

View file

@ -122,7 +122,7 @@ MiIsAccessAllowed(
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \ #define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \
(Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \ (Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7) ((Bit4) << 4) | ((Bit5) << 5) | ((Bit6) << 6) | ((Bit7) << 7)
static const UCHAR MiAccessAllowedMask[2][2] = static const UCHAR AccessAllowedMask[2][2] =
{ {
{ // Protect 0 1 2 3 4 5 6 7 { // Protect 0 1 2 3 4 5 6 7
_BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ _BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ
@ -134,11 +134,11 @@ MiIsAccessAllowed(
} }
}; };
/* We want only the low 3 bits */ /* We want only the lower access bits */
ProtectionMask &= 7; ProtectionMask &= MM_PROTECT_ACCESS;
/* Look it up in the table */ /* Look it up in the table */
return (MiAccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1; return (AccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
} }
NTSTATUS NTSTATUS
@ -187,7 +187,7 @@ MiAccessCheck(IN PMMPTE PointerPte,
} }
/* Check if this is a guard page */ /* Check if this is a guard page */
if (ProtectionMask & MM_GUARDPAGE) if ((ProtectionMask & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
{ {
NT_ASSERT(ProtectionMask != MM_DECOMMIT); NT_ASSERT(ProtectionMask != MM_DECOMMIT);
@ -765,8 +765,8 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction,
/* Release the PFN lock */ /* Release the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Remove caching bits */ /* Remove special/caching bits */
Protection &= ~(MM_NOCACHE | MM_NOACCESS); Protection &= ~MM_PROTECT_SPECIAL;
/* Setup caching */ /* Setup caching */
if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined) if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
@ -820,7 +820,8 @@ MiResolveTransitionFault(IN PVOID FaultingAddress,
PMMPFN Pfn1; PMMPFN Pfn1;
MMPTE TempPte; MMPTE TempPte;
PMMPTE PointerToPteForProtoPage; PMMPTE PointerToPteForProtoPage;
DPRINT1("Transition fault on 0x%p with PTE 0x%p in process %s\n", FaultingAddress, PointerPte, CurrentProcess->ImageFileName); DPRINT1("Transition fault on 0x%p with PTE 0x%p in process %s\n",
FaultingAddress, PointerPte, CurrentProcess->ImageFileName);
/* Windowss does this check */ /* Windowss does this check */
ASSERT(*InPageBlock == NULL); ASSERT(*InPageBlock == NULL);
@ -1453,37 +1454,25 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
/* Bail out, if the fault came from user mode */ /* Bail out, if the fault came from user mode */
if (Mode == UserMode) return STATUS_ACCESS_VIOLATION; if (Mode == UserMode) return STATUS_ACCESS_VIOLATION;
#if (_MI_PAGING_LEVELS == 4)
/* AMD64 system, check if PXE is invalid */
if (PointerPxe->u.Hard.Valid == 0)
{
KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
(ULONG_PTR)Address,
StoreInstruction,
(ULONG_PTR)TrapInformation,
7);
}
#endif
#if (_MI_PAGING_LEVELS == 4)
/* PAE/AMD64 system, check if PPE is invalid */
if (PointerPpe->u.Hard.Valid == 0)
{
KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
(ULONG_PTR)Address,
StoreInstruction,
(ULONG_PTR)TrapInformation,
5);
}
#endif
#if (_MI_PAGING_LEVELS == 2) #if (_MI_PAGING_LEVELS == 2)
if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte); if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
MiCheckPdeForPagedPool(Address); MiCheckPdeForPagedPool(Address);
#endif #endif
/* Check if the PDE is invalid */ /* Check if the higher page table entries are invalid */
if (PointerPde->u.Hard.Valid == 0) if (
#if (_MI_PAGING_LEVELS == 4)
/* AMD64 system, check if PXE is invalid */
(PointerPxe->u.Hard.Valid == 0) ||
#endif
#if (_MI_PAGING_LEVELS >= 3)
/* PAE/AMD64 system, check if PPE is invalid */
(PointerPpe->u.Hard.Valid == 0) ||
#endif
/* Always check if the PDE is valid */
(PointerPde->u.Hard.Valid == 0))
{ {
/* PDE (still) not valid, kill the system */ /* PXE/PPE/PDE (still) not valid, kill the system */
KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA, KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
(ULONG_PTR)Address, (ULONG_PTR)Address,
StoreInstruction, StoreInstruction,
@ -1894,7 +1883,7 @@ UserFault:
} }
/* Is this a guard page? */ /* Is this a guard page? */
if (ProtectionCode & MM_GUARDPAGE) if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
{ {
/* The VAD protection cannot be MM_DECOMMIT! */ /* The VAD protection cannot be MM_DECOMMIT! */
NT_ASSERT(ProtectionCode != MM_DECOMMIT); NT_ASSERT(ProtectionCode != MM_DECOMMIT);

View file

@ -198,7 +198,7 @@ MiMakeProtectionMask(IN ULONG Protect)
} }
/* This actually turns on guard page in this scenario! */ /* This actually turns on guard page in this scenario! */
ProtectMask |= MM_GUARDPAGE; ProtectMask |= MM_DECOMMIT;
} }
/* Check for nocache option */ /* Check for nocache option */
@ -1914,10 +1914,7 @@ MiFlushTbAndCapture(IN PMMVAD FoundVad,
// //
// Write the new PTE, making sure we are only changing the bits // Write the new PTE, making sure we are only changing the bits
// //
ASSERT(PointerPte->u.Hard.Valid == 1); MI_UPDATE_VALID_PTE(PointerPte, TempPte);
ASSERT(TempPte.u.Hard.Valid == 1);
ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
*PointerPte = TempPte;
// //
// Flush the TLB // Flush the TLB

View file

@ -350,11 +350,7 @@ MiDeleteSystemPageableVm(IN PMMPTE PointerPte,
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Destroy the PTE */ /* Destroy the PTE */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); MI_ERASE_PTE(PointerPte);
}
/* Actual legitimate pages */
ActualPages++;
} }
else else
{ {
@ -368,7 +364,11 @@ MiDeleteSystemPageableVm(IN PMMPTE PointerPte,
ASSERT(PointerPte->u.Soft.PageFileHigh == 0); ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
/* Destroy the PTE */ /* Destroy the PTE */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); MI_ERASE_PTE(PointerPte);
}
/* Actual legitimate pages */
ActualPages++;
} }
/* Keep going */ /* Keep going */
@ -486,7 +486,7 @@ MiDeletePte(IN PMMPTE PointerPte,
} }
/* Destroy the PTE and flush the TLB */ /* Destroy the PTE and flush the TLB */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); MI_ERASE_PTE(PointerPte);
KeFlushCurrentTb(); KeFlushCurrentTb();
} }
@ -618,7 +618,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va,
(TempPte.u.Soft.Prototype == 1)) (TempPte.u.Soft.Prototype == 1))
{ {
/* Just nuke it */ /* Just nuke it */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); MI_ERASE_PTE(PointerPte);
} }
else else
{ {
@ -632,7 +632,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va,
else else
{ {
/* The PTE was never mapped, just nuke it here */ /* The PTE was never mapped, just nuke it here */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte); MI_ERASE_PTE(PointerPte);
} }
} }

View file

@ -394,7 +394,7 @@ MiBalancerThread(PVOID Unused)
Address < (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS; Address < (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS;
Address += (PAGE_SIZE * PTE_COUNT)) Address += (PAGE_SIZE * PTE_COUNT))
{ {
if (MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0) if (MiQueryPageTableReferences((PVOID)Address) == 0)
{ {
pointerPde = MiAddressToPde(Address); pointerPde = MiAddressToPde(Address);
if (pointerPde->u.Hard.Valid) if (pointerPde->u.Hard.Valid)