[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_EXECUTE_READWRITE 6
#define MM_EXECUTE_WRITECOPY 7
#define MM_PROTECT_ACCESS 7
//
// 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_GUARDPAGE 0x10
#define MM_WRITECOMBINE 0x18
#define MM_PROTECT_SPECIAL 0x18
//
// These are special cases
@ -588,7 +590,6 @@ typedef struct _MM_SESSION_SPACE
LONG ImageLoadingCount;
} MM_SESSION_SPACE, *PMM_SESSION_SPACE;
static const MMPTE MmZeroPte = {{0}};
extern PMM_SESSION_SPACE MmSessionSpace;
extern MMPTE HyperTemplatePte;
extern MMPDE ValidKernelPde;
@ -1002,6 +1003,21 @@ MI_WRITE_VALID_PTE(IN PMMPTE PointerPte,
*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
//
@ -1012,9 +1028,22 @@ MI_WRITE_INVALID_PTE(IN PMMPTE PointerPte,
{
/* Write the invalid PTE */
ASSERT(InvalidPte.u.Hard.Valid == 0);
ASSERT(InvalidPte.u.Long != 0);
*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
//
@ -1039,6 +1068,7 @@ MI_WRITE_INVALID_PDE(IN PMMPDE PointerPde,
{
/* Write the invalid PDE */
ASSERT(InvalidPde.u.Hard.Valid == 0);
ASSERT(InvalidPde.u.Long != 0);
*PointerPde = InvalidPde;
}

View file

@ -122,7 +122,7 @@ MiIsAccessAllowed(
#define _BYTE_MASK(Bit0, Bit1, Bit2, Bit3, Bit4, Bit5, Bit6, Bit7) \
(Bit0) | ((Bit1) << 1) | ((Bit2) << 2) | ((Bit3) << 3) | \
((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
_BYTE_MASK(0, 1, 1, 1, 1, 1, 1, 1), // READ
@ -134,11 +134,11 @@ MiIsAccessAllowed(
}
};
/* We want only the low 3 bits */
ProtectionMask &= 7;
/* We want only the lower access bits */
ProtectionMask &= MM_PROTECT_ACCESS;
/* Look it up in the table */
return (MiAccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
return (AccessAllowedMask[Write != 0][Execute != 0] >> ProtectionMask) & 1;
}
NTSTATUS
@ -187,7 +187,7 @@ MiAccessCheck(IN PMMPTE PointerPte,
}
/* Check if this is a guard page */
if (ProtectionMask & MM_GUARDPAGE)
if ((ProtectionMask & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
{
NT_ASSERT(ProtectionMask != MM_DECOMMIT);
@ -765,8 +765,8 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction,
/* Release the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Remove caching bits */
Protection &= ~(MM_NOCACHE | MM_NOACCESS);
/* Remove special/caching bits */
Protection &= ~MM_PROTECT_SPECIAL;
/* Setup caching */
if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
@ -820,7 +820,8 @@ MiResolveTransitionFault(IN PVOID FaultingAddress,
PMMPFN Pfn1;
MMPTE TempPte;
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 */
ASSERT(*InPageBlock == NULL);
@ -1453,37 +1454,25 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
/* Bail out, if the fault came from user mode */
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_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address)) MiSynchronizeSystemPde((PMMPDE)PointerPte);
MiCheckPdeForPagedPool(Address);
#endif
/* Check if the PDE is invalid */
if (PointerPde->u.Hard.Valid == 0)
/* Check if the higher page table entries are invalid */
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,
(ULONG_PTR)Address,
StoreInstruction,
@ -1894,7 +1883,7 @@ UserFault:
}
/* Is this a guard page? */
if (ProtectionCode & MM_GUARDPAGE)
if ((ProtectionCode & MM_PROTECT_SPECIAL) == MM_GUARDPAGE)
{
/* The VAD protection cannot be 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! */
ProtectMask |= MM_GUARDPAGE;
ProtectMask |= MM_DECOMMIT;
}
/* Check for nocache option */
@ -1914,10 +1914,7 @@ MiFlushTbAndCapture(IN PMMVAD FoundVad,
//
// Write the new PTE, making sure we are only changing the bits
//
ASSERT(PointerPte->u.Hard.Valid == 1);
ASSERT(TempPte.u.Hard.Valid == 1);
ASSERT(PointerPte->u.Hard.PageFrameNumber == TempPte.u.Hard.PageFrameNumber);
*PointerPte = TempPte;
MI_UPDATE_VALID_PTE(PointerPte, TempPte);
//
// Flush the TLB

View file

@ -350,26 +350,26 @@ MiDeleteSystemPageableVm(IN PMMPTE PointerPte,
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
/* Destroy the PTE */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte);
MI_ERASE_PTE(PointerPte);
}
else
{
/*
* The only other ARM3 possibility is a demand zero page, which would
* mean freeing some of the paged pool pages that haven't even been
* touched yet, as part of a larger allocation.
*
* Right now, we shouldn't expect any page file information in the PTE
*/
ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
/* Destroy the PTE */
MI_ERASE_PTE(PointerPte);
}
/* Actual legitimate pages */
ActualPages++;
}
else
{
/*
* The only other ARM3 possibility is a demand zero page, which would
* mean freeing some of the paged pool pages that haven't even been
* touched yet, as part of a larger allocation.
*
* Right now, we shouldn't expect any page file information in the PTE
*/
ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
/* Destroy the PTE */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte);
}
/* Keep going */
PointerPte++;
@ -486,7 +486,7 @@ MiDeletePte(IN PMMPTE PointerPte,
}
/* Destroy the PTE and flush the TLB */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte);
MI_ERASE_PTE(PointerPte);
KeFlushCurrentTb();
}
@ -618,7 +618,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va,
(TempPte.u.Soft.Prototype == 1))
{
/* Just nuke it */
MI_WRITE_INVALID_PTE(PointerPte, MmZeroPte);
MI_ERASE_PTE(PointerPte);
}
else
{
@ -632,7 +632,7 @@ MiDeleteVirtualAddresses(IN ULONG_PTR Va,
else
{
/* 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 += (PAGE_SIZE * PTE_COUNT))
{
if (MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0)
if (MiQueryPageTableReferences((PVOID)Address) == 0)
{
pointerPde = MiAddressToPde(Address);
if (pointerPde->u.Hard.Valid)