diff --git a/ntoskrnl/mm/i386/page.c b/ntoskrnl/mm/i386/page.c index 3e5f579..35b0921 100644 --- a/ntoskrnl/mm/i386/page.c +++ b/ntoskrnl/mm/i386/page.c @@ -15,13 +15,38 @@ #include -#ifndef _MI_PAGING_LEVELS -#error "Dude, fix your stuff before using this file" -#endif +#define ADDR_TO_PDE_OFFSET MiAddressToPdeOffset +#define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE)) /* GLOBALS *****************************************************************/ + +#define PA_BIT_PRESENT (0) +#define PA_BIT_READWRITE (1) +#define PA_BIT_USER (2) +#define PA_BIT_WT (3) +#define PA_BIT_CD (4) +#define PA_BIT_ACCESSED (5) +#define PA_BIT_DIRTY (6) +#define PA_BIT_GLOBAL (8) + +#define PA_PRESENT (1 << PA_BIT_PRESENT) +#define PA_READWRITE (1 << PA_BIT_READWRITE) +#define PA_USER (1 << PA_BIT_USER) +#define PA_DIRTY (1 << PA_BIT_DIRTY) +#define PA_WT (1 << PA_BIT_WT) +#define PA_CD (1 << PA_BIT_CD) +#define PA_ACCESSED (1 << PA_BIT_ACCESSED) +#define PA_GLOBAL (1 << PA_BIT_GLOBAL) + +#define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPER_SPACE && (ULONG)(v) <= HYPER_SPACE_END)) + +#define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT) +#define PFN_TO_PTE(X) ((X) << PAGE_SHIFT) + +#define PAGE_MASK(x) ((x)&(~0xfff)) + const -ULONG_PTR +ULONG MmProtectToPteMask[32] = { // @@ -109,6 +134,47 @@ ULONG MmProtectToValue[32] = /* FUNCTIONS ***************************************************************/ +static ULONG +ProtectToPTE(ULONG flProtect) +{ + ULONG Attributes = 0; + + if (flProtect & (PAGE_NOACCESS|PAGE_GUARD)) + { + Attributes = 0; + } + else if (flProtect & PAGE_IS_WRITABLE) + { + Attributes = PA_PRESENT | PA_READWRITE; + } + else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE)) + { + Attributes = PA_PRESENT; + } + else + { + DPRINT1("Unknown main protection type.\n"); + KeBugCheck(MEMORY_MANAGEMENT); + } + + if (flProtect & PAGE_SYSTEM) + { + } + else + { + Attributes = Attributes | PA_USER; + } + if (flProtect & PAGE_NOCACHE) + { + Attributes = Attributes | PA_CD; + } + if (flProtect & PAGE_WRITETHROUGH) + { + Attributes = Attributes | PA_WT; + } + return(Attributes); +} + NTSTATUS NTAPI MiFillSystemPageDirectory(IN PVOID Base, @@ -157,7 +223,7 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, */ { PMMPTE PointerPte; - MMPTE OldPte; + ULONG Pte; DPRINT("MmDeleteVirtualMapping(%p, %p, %p, %p)\n", Process, Address, WasDirty, Page); @@ -174,11 +240,8 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, DPRINT1("NULL process given for user-mode mapping at %p\n", Address); KeBugCheck(MEMORY_MANAGEMENT); } -#if (_MI_PAGING_LEVELS == 2) + if (!MiSynchronizeSystemPde(MiAddressToPde(Address))) -#else - if (!MiIsPdeForAddressValid(Address)) -#endif { /* There can't be a page if there is no PDE */ if (WasDirty) @@ -215,9 +278,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, } PointerPte = MiAddressToPte(Address); - OldPte.u.Long = InterlockedExchangePte(PointerPte, 0); + Pte = InterlockedExchangePte(PointerPte, 0); - if (OldPte.u.Long == 0) + if (Pte == 0) { /* There was nothing here */ if (Address < MmSystemRangeStart) @@ -230,9 +293,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, } /* It must have been present, or not a swap entry */ - ASSERT(OldPte.u.Hard.Valid || !FlagOn(OldPte.u.Long, 0x800)); + ASSERT(FlagOn(Pte, PA_PRESENT) || !FlagOn(Pte, 0x800)); - if (OldPte.u.Hard.Valid) + if (FlagOn(Pte, PA_PRESENT)) KeInvalidateTlbEntry(Address); if (Address < MmSystemRangeStart) @@ -250,9 +313,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, } if (WasDirty) - *WasDirty = !!OldPte.u.Hard.Dirty; + *WasDirty = FlagOn(Pte, PA_DIRTY); if (Page) - *Page = OldPte.u.Hard.PageFrameNumber; + *Page = PTE_TO_PFN(Pte); } @@ -264,7 +327,7 @@ MmDeletePageFileMapping( SWAPENTRY* SwapEntry) { PMMPTE PointerPte; - MMPTE OldPte; + ULONG Pte; /* This should not be called for kernel space anymore */ ASSERT(Process != NULL); @@ -285,11 +348,10 @@ MmDeletePageFileMapping( MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); PointerPte = MiAddressToPte(Address); - OldPte.u.Long = InterlockedExchangePte(PointerPte, 0); - /* This must be a swap entry ! */ - if (!FlagOn(OldPte.u.Long, 0x800) || OldPte.u.Hard.Valid) + Pte = InterlockedExchangePte(PointerPte, 0); + if (!FlagOn(Pte, 0x800) || FlagOn(Pte, PA_PRESENT)) { - KeBugCheckEx(MEMORY_MANAGEMENT, OldPte.u.Long, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); + KeBugCheckEx(MEMORY_MANAGEMENT, Pte, (ULONG_PTR)Process, (ULONG_PTR)Address, 0); } /* This used to be a non-zero PTE, now we can let the PDE go. */ @@ -304,7 +366,22 @@ MmDeletePageFileMapping( MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread()); - *SwapEntry = OldPte.u.Long >> 1; + *SwapEntry = Pte >> 1; +} + +BOOLEAN +Mmi386MakeKernelPageTableGlobal(PVOID Address) +{ + PMMPDE PointerPde = MiAddressToPde(Address); + PMMPTE PointerPte = MiAddressToPte(Address); + + if (PointerPde->u.Hard.Valid == 0) + { + if(!MiSynchronizeSystemPde(PointerPde)) + return FALSE; + return PointerPte->u.Hard.Valid != 0; + } + return FALSE; } BOOLEAN @@ -316,11 +393,7 @@ MmIsPagePresent(PEPROCESS Process, PVOID Address) if (Address >= MmSystemRangeStart) { ASSERT(Process == NULL); -#if _MI_PAGING_LEVELS == 2 if (!MiSynchronizeSystemPde(MiAddressToPde(Address))) -#else - if (!MiIsPdeForAddressValid(Address)) -#endif { /* It can't be present if there is no PDE */ return FALSE; @@ -355,20 +428,18 @@ NTAPI MmIsDisabledPage(PEPROCESS Process, PVOID Address) { BOOLEAN Ret; - PMMPTE PointerPte; + ULONG Pte; if (Address >= MmSystemRangeStart) { ASSERT(Process == NULL); -#if _MI_PAGING_LEVELS == 2 if (!MiSynchronizeSystemPde(MiAddressToPde(Address))) -#else - if (!MiIsPdeForAddressValid(Address)) -#endif { /* It's not disabled if it's not present */ return FALSE; } + + Pte = MiAddressToPte(Address)->u.Long; } else { @@ -385,12 +456,11 @@ MmIsDisabledPage(PEPROCESS Process, PVOID Address) } MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); + + Pte = MiAddressToPte(Address)->u.Long; } - PointerPte = MiAddressToPte(Address); - Ret = !PointerPte->u.Hard.Valid - && !FlagOn(PointerPte->u.Long, 0x800) - && (PointerPte->u.Hard.PageFrameNumber != 0); + Ret = !FlagOn(Pte, PA_PRESENT) && !FlagOn(Pte, 0x800) && (PAGE_MASK(Pte) != 0); if (Address < MmSystemRangeStart) MiUnlockProcessWorkingSetShared(Process, PsGetCurrentThread()); @@ -403,7 +473,7 @@ NTAPI MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) { BOOLEAN Ret; - PMMPTE PointerPte; + ULONG Pte; /* We never set swap entries for kernel addresses */ if (Address >= MmSystemRangeStart) @@ -426,8 +496,8 @@ MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); - PointerPte = MiAddressToPte(Address); - Ret = !PointerPte->u.Hard.Valid && FlagOn(PointerPte->u.Long, 0x800); + Pte = MiAddressToPte(Address)->u.Long; + Ret = !FlagOn(Pte, PA_PRESENT) && FlagOn(Pte, 0x800); MiUnlockProcessWorkingSetShared(Process, PsGetCurrentThread()); @@ -438,7 +508,7 @@ VOID NTAPI MmGetPageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY* SwapEntry) { - PMMPTE PointerPte; + ULONG Pte; /* We never set swap entries for kernel addresses */ if (Address >= MmSystemRangeStart) @@ -463,9 +533,9 @@ MmGetPageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY* SwapEntry) MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); - PointerPte = MiAddressToPte(Address); - if (!PointerPte->u.Hard.Valid && FlagOn(PointerPte->u.Long, 0x800)) - *SwapEntry = PointerPte->u.Long >> 1; + Pte = MiAddressToPte(Address)->u.Long; + if (!FlagOn(Pte, PA_PRESENT) && FlagOn(Pte, 0x800)) + *SwapEntry = Pte >> 1; else *SwapEntry = 0; @@ -479,7 +549,7 @@ MmCreatePageFileMapping(PEPROCESS Process, SWAPENTRY SwapEntry) { PMMPTE PointerPte; - ULONG_PTR Pte; + ULONG Pte; /* This should not be called for kernel space anymore */ ASSERT(Process != NULL); @@ -521,22 +591,15 @@ MmCreateVirtualMappingUnsafe(PEPROCESS Process, ULONG flProtect, PFN_NUMBER Page) { - ULONG ProtectionMask; + ULONG Attributes; PMMPTE PointerPte; - MMPTE TempPte; - ULONG_PTR Pte; + ULONG Pte; DPRINT("MmCreateVirtualMappingUnsafe(%p, %p, %lu, %x)\n", Process, Address, flProtect, Page); ASSERT(((ULONG_PTR)Address % PAGE_SIZE) == 0); - ProtectionMask = MiMakeProtectionMask(flProtect); - /* Caller must have checked ! */ - ASSERT(ProtectionMask != MM_INVALID_PROTECTION); - ASSERT(ProtectionMask != MM_NOACCESS); - ASSERT(ProtectionMask != MM_ZERO_ACCESS); - /* Make sure our PDE is valid, and that everything is going fine */ if (Process == NULL) { @@ -545,10 +608,8 @@ MmCreateVirtualMappingUnsafe(PEPROCESS Process, DPRINT1("NULL process given for user-mode mapping at %p\n", Address); KeBugCheck(MEMORY_MANAGEMENT); } -#if _MI_PAGING_LEVELS == 2 if (!MiSynchronizeSystemPde(MiAddressToPde(Address))) MiFillSystemPageDirectory(Address, PAGE_SIZE); -#endif } else { @@ -565,18 +626,22 @@ MmCreateVirtualMappingUnsafe(PEPROCESS Process, MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); } - PointerPte = MiAddressToPte(Address); - + Attributes = ProtectToPTE(flProtect); + Attributes &= 0xfff; if (Address >= MmSystemRangeStart) { - MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte, ProtectionMask, Page); + Attributes &= ~PA_USER; } else { - MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, ProtectionMask, Page); + Attributes |= PA_USER; } - Pte = InterlockedExchangePte(PointerPte, TempPte.u.Long); + /* This must be for a valid address */ + ASSERT(FlagOn(Attributes, PA_PRESENT)); + + PointerPte = MiAddressToPte(Address); + Pte = InterlockedExchangePte(PointerPte, PFN_TO_PTE(Page) | Attributes); /* There should not have been anything valid here */ if (Pte != 0) { @@ -607,7 +672,7 @@ MmCreateVirtualMapping(PEPROCESS Process, ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0); if (!MmIsPageInUse(Page)) { - DPRINT1("Page %lx is not in use\n", Page); + DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Page)); KeBugCheck(MEMORY_MANAGEMENT); } @@ -618,21 +683,15 @@ ULONG NTAPI MmGetPageProtect(PEPROCESS Process, PVOID Address) { - PMMPTE PointerPte; + ULONG_PTR Pte; ULONG Protect; if (Address >= MmSystemRangeStart) { ASSERT(Process == NULL); -#if _MI_PAGING_LEVELS == 2 if (!MiSynchronizeSystemPde(MiAddressToPde(Address))) -#else - if (!MiIsPdeForAddressValid(Address)) -#endif - { return PAGE_NOACCESS; - } } else { @@ -653,29 +712,34 @@ MmGetPageProtect(PEPROCESS Process, PVOID Address) MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); } - PointerPte = MiAddressToPte(Address); + Pte = MiAddressToPte(Address)->u.Long; - if (!PointerPte->u.Flush.Valid) + if (!(Pte & PA_PRESENT)) { Protect = PAGE_NOACCESS; } else { - if (PointerPte->u.Flush.CopyOnWrite) - Protect = PAGE_WRITECOPY; - else if (PointerPte->u.Flush.Write) + if (Pte & PA_READWRITE) + { Protect = PAGE_READWRITE; + } else - Protect = PAGE_READONLY; -#if _MI_PAGING_LEVELS >= 3 - /* PAE & AMD64 long mode support NoExecute bit */ - if (!PointerPte->u.Flush.NoExecute) - Protect <<= 4; -#endif - if (PointerPte->u.Flush.CacheDisable) + { + Protect = PAGE_EXECUTE_READ; + } + if (Pte & PA_CD) + { Protect |= PAGE_NOCACHE; - if (PointerPte->u.Flush.WriteThrough) + } + if (Pte & PA_WT) + { Protect |= PAGE_WRITETHROUGH; + } + if (!(Pte & PA_USER)) + { + Protect |= PAGE_SYSTEM; + } } if (Address < MmSystemRangeStart) @@ -688,9 +752,9 @@ VOID NTAPI MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) { - ULONG ProtectionMask; + ULONG Attributes = 0; PMMPTE PointerPte; - MMPTE TempPte, OldPte; + ULONG Pte; DPRINT("MmSetPageProtect(Process %p Address %p flProtect %x)\n", Process, Address, flProtect); @@ -700,31 +764,26 @@ MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) ASSERT(Process == PsGetCurrentProcess()); - ProtectionMask = MiMakeProtectionMask(flProtect); - /* Caller must have checked ! */ - ASSERT(ProtectionMask != MM_INVALID_PROTECTION); - MiLockProcessWorkingSetUnsafe(Process, PsGetCurrentThread()); MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); - PointerPte = MiAddressToPte(Address); + Attributes = ProtectToPTE(flProtect); - MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, ProtectionMask, PFN_FROM_PTE(PointerPte)); - /* Keep dirty & accessed bits */ - TempPte.u.Hard.Accessed = PointerPte->u.Hard.Accessed; - TempPte.u.Hard.Dirty = PointerPte->u.Hard.Dirty; + Attributes &= 0xfff; + Attributes |= PA_USER; - OldPte.u.Long = InterlockedExchangePte(PointerPte, TempPte.u.Long); + PointerPte = MiAddressToPte(Address); + Pte = InterlockedExchangePte(PointerPte, PAGE_MASK(PointerPte->u.Long) | Attributes | (PointerPte->u.Long & (PA_ACCESSED|PA_DIRTY))); // We should be able to bring a page back from PAGE_NOACCESS - if (!OldPte.u.Hard.Valid && (FlagOn(OldPte.u.Long, 0x800) || (OldPte.u.Hard.PageFrameNumber == 0))) + if ((Pte & 0x800) || !(Pte >> PAGE_SHIFT)) { - DPRINT1("Invalid Pte %lx\n", OldPte.u.Long); + DPRINT1("Invalid Pte %lx\n", Pte); KeBugCheck(MEMORY_MANAGEMENT); } - if (OldPte.u.Long != TempPte.u.Long) + if ((Pte & 0xFFF) != Attributes) KeInvalidateTlbEntry(Address); MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread()); @@ -735,6 +794,7 @@ NTAPI MmSetDirtyBit(PEPROCESS Process, PVOID Address, BOOLEAN Bit) { PMMPTE PointerPte; + ULONG Pte; DPRINT("MmSetDirtyBit(Process %p Address %p Bit %x)\n", Process, Address, Bit); @@ -749,15 +809,20 @@ MmSetDirtyBit(PEPROCESS Process, PVOID Address, BOOLEAN Bit) MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL); PointerPte = MiAddressToPte(Address); + Pte = PointerPte->u.Long; + if (Bit) + Pte |= PA_DIRTY; + else + Pte &= ~PA_DIRTY; + Pte = InterlockedExchangePte(PointerPte, Pte); + // We shouldnl't set dirty bit on non-mapped adresses - if (!PointerPte->u.Hard.Valid && (FlagOn(PointerPte->u.Long, 0x800) || (PointerPte->u.Hard.PageFrameNumber == 0))) + if ((Pte & 0x800) || !(Pte >> PAGE_SHIFT)) { - DPRINT1("Invalid Pte %lx\n", PointerPte->u.Long); + DPRINT1("Invalid Pte %lx\n", Pte); KeBugCheck(MEMORY_MANAGEMENT); } - PointerPte->u.Hard.Dirty = !!Bit; - if (!Bit) KeInvalidateTlbEntry(Address); @@ -772,21 +837,4 @@ MmInitGlobalKernelPageDirectory(VOID) /* Nothing to do here */ } -#ifdef _M_IX86 -BOOLEAN -Mmi386MakeKernelPageTableGlobal(PVOID Address) -{ - PMMPDE PointerPde = MiAddressToPde(Address); - PMMPTE PointerPte = MiAddressToPte(Address); - - if (PointerPde->u.Hard.Valid == 0) - { - if (!MiSynchronizeSystemPde(PointerPde)) - return FALSE; - return PointerPte->u.Hard.Valid != 0; - } - return FALSE; -} -#endif - /* EOF */