mirror of
https://github.com/reactos/reactos.git
synced 2025-05-19 00:54:18 +00:00
[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:
parent
5ab8592b44
commit
4019985115
5 changed files with 75 additions and 59 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue