From 4019985115fbcb19247b22d024e411cd9f5f2cbe Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Wed, 27 Nov 2013 00:04:26 +0000 Subject: [PATCH] [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 --- reactos/ntoskrnl/mm/ARM3/miarm.h | 32 +++++++++++++++- reactos/ntoskrnl/mm/ARM3/pagfault.c | 57 ++++++++++++----------------- reactos/ntoskrnl/mm/ARM3/section.c | 7 +--- reactos/ntoskrnl/mm/ARM3/virtual.c | 36 +++++++++--------- reactos/ntoskrnl/mm/balance.c | 2 +- 5 files changed, 75 insertions(+), 59 deletions(-) diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index 428e0e31834..0ec38ed1b97 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -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; } diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index 5c69317ffd2..d8516bff64c 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -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); diff --git a/reactos/ntoskrnl/mm/ARM3/section.c b/reactos/ntoskrnl/mm/ARM3/section.c index 403376d3d51..ef79a3c7f6e 100644 --- a/reactos/ntoskrnl/mm/ARM3/section.c +++ b/reactos/ntoskrnl/mm/ARM3/section.c @@ -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 diff --git a/reactos/ntoskrnl/mm/ARM3/virtual.c b/reactos/ntoskrnl/mm/ARM3/virtual.c index d8d3eadcb4f..6afcfc82e98 100644 --- a/reactos/ntoskrnl/mm/ARM3/virtual.c +++ b/reactos/ntoskrnl/mm/ARM3/virtual.c @@ -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); } } diff --git a/reactos/ntoskrnl/mm/balance.c b/reactos/ntoskrnl/mm/balance.c index 85fec719d8c..804c674763e 100644 --- a/reactos/ntoskrnl/mm/balance.c +++ b/reactos/ntoskrnl/mm/balance.c @@ -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) -- 2.17.1