[NTOS:MM] Make i386/page.c usable for all x86 variants

This includes PAE & amd64
This commit is contained in:
Jérôme Gardou 2021-04-07 08:49:26 +02:00 committed by Jérôme Gardou
parent 6d957d6958
commit 370982aa1d

View file

@ -15,35 +15,13 @@
#include <mm/ARM3/miarm.h>
#ifndef _MI_PAGING_LEVELS
#error "Dude, fix your stuff before using this file"
#endif
/* 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
ULONG_PTR
MmProtectToPteMask[32] =
{
//
@ -179,7 +157,7 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
*/
{
PMMPTE PointerPte;
ULONG Pte;
MMPTE OldPte;
DPRINT("MmDeleteVirtualMapping(%p, %p, %p, %p)\n", Process, Address, WasDirty, Page);
@ -196,8 +174,11 @@ 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)
@ -234,9 +215,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
}
PointerPte = MiAddressToPte(Address);
Pte = InterlockedExchangePte(PointerPte, 0);
OldPte.u.Long = InterlockedExchangePte(PointerPte, 0);
if (Pte == 0)
if (OldPte.u.Long == 0)
{
/* There was nothing here */
if (Address < MmSystemRangeStart)
@ -249,9 +230,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
}
/* It must have been present, or not a swap entry */
ASSERT(FlagOn(Pte, PA_PRESENT) || !FlagOn(Pte, 0x800));
ASSERT(OldPte.u.Hard.Valid || !FlagOn(OldPte.u.Long, 0x800));
if (FlagOn(Pte, PA_PRESENT))
if (OldPte.u.Hard.Valid)
KeInvalidateTlbEntry(Address);
if (Address < MmSystemRangeStart)
@ -269,9 +250,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
}
if (WasDirty)
*WasDirty = FlagOn(Pte, PA_DIRTY);
*WasDirty = !!OldPte.u.Hard.Dirty;
if (Page)
*Page = PTE_TO_PFN(Pte);
*Page = OldPte.u.Hard.PageFrameNumber;
}
@ -283,7 +264,7 @@ MmDeletePageFileMapping(
SWAPENTRY* SwapEntry)
{
PMMPTE PointerPte;
ULONG Pte;
MMPTE OldPte;
/* This should not be called for kernel space anymore */
ASSERT(Process != NULL);
@ -304,10 +285,11 @@ MmDeletePageFileMapping(
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
PointerPte = MiAddressToPte(Address);
Pte = InterlockedExchangePte(PointerPte, 0);
if (!FlagOn(Pte, 0x800) || FlagOn(Pte, PA_PRESENT))
OldPte.u.Long = InterlockedExchangePte(PointerPte, 0);
/* This must be a swap entry ! */
if (!FlagOn(OldPte.u.Long, 0x800) || OldPte.u.Hard.Valid)
{
KeBugCheckEx(MEMORY_MANAGEMENT, Pte, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
KeBugCheckEx(MEMORY_MANAGEMENT, OldPte.u.Long, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
}
/* This used to be a non-zero PTE, now we can let the PDE go. */
@ -322,22 +304,7 @@ MmDeletePageFileMapping(
MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
*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;
*SwapEntry = OldPte.u.Long >> 1;
}
BOOLEAN
@ -349,7 +316,11 @@ 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;
@ -384,18 +355,20 @@ NTAPI
MmIsDisabledPage(PEPROCESS Process, PVOID Address)
{
BOOLEAN Ret;
ULONG Pte;
PMMPTE PointerPte;
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
{
@ -412,11 +385,12 @@ MmIsDisabledPage(PEPROCESS Process, PVOID Address)
}
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
Pte = MiAddressToPte(Address)->u.Long;
}
Ret = !FlagOn(Pte, PA_PRESENT) && !FlagOn(Pte, 0x800) && (PAGE_MASK(Pte) != 0);
PointerPte = MiAddressToPte(Address);
Ret = !PointerPte->u.Hard.Valid
&& !FlagOn(PointerPte->u.Long, 0x800)
&& (PointerPte->u.Hard.PageFrameNumber != 0);
if (Address < MmSystemRangeStart)
MiUnlockProcessWorkingSetShared(Process, PsGetCurrentThread());
@ -429,7 +403,7 @@ NTAPI
MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
{
BOOLEAN Ret;
ULONG Pte;
PMMPTE PointerPte;
/* We never set swap entries for kernel addresses */
if (Address >= MmSystemRangeStart)
@ -452,8 +426,8 @@ MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
Pte = MiAddressToPte(Address)->u.Long;
Ret = !FlagOn(Pte, PA_PRESENT) && FlagOn(Pte, 0x800);
PointerPte = MiAddressToPte(Address);
Ret = !PointerPte->u.Hard.Valid && FlagOn(PointerPte->u.Long, 0x800);
MiUnlockProcessWorkingSetShared(Process, PsGetCurrentThread());
@ -464,7 +438,7 @@ VOID
NTAPI
MmGetPageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY* SwapEntry)
{
ULONG Pte;
PMMPTE PointerPte;
/* We never set swap entries for kernel addresses */
if (Address >= MmSystemRangeStart)
@ -489,9 +463,9 @@ MmGetPageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY* SwapEntry)
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
Pte = MiAddressToPte(Address)->u.Long;
if (!FlagOn(Pte, PA_PRESENT) && FlagOn(Pte, 0x800))
*SwapEntry = Pte >> 1;
PointerPte = MiAddressToPte(Address);
if (!PointerPte->u.Hard.Valid && FlagOn(PointerPte->u.Long, 0x800))
*SwapEntry = PointerPte->u.Long >> 1;
else
*SwapEntry = 0;
@ -505,7 +479,7 @@ MmCreatePageFileMapping(PEPROCESS Process,
SWAPENTRY SwapEntry)
{
PMMPTE PointerPte;
ULONG Pte;
ULONG_PTR Pte;
/* This should not be called for kernel space anymore */
ASSERT(Process != NULL);
@ -571,8 +545,10 @@ 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
{
@ -631,7 +607,7 @@ MmCreateVirtualMapping(PEPROCESS Process,
ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
if (!MmIsPageInUse(Page))
{
DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Page));
DPRINT1("Page %lx is not in use\n", Page);
KeBugCheck(MEMORY_MANAGEMENT);
}
@ -642,15 +618,21 @@ ULONG
NTAPI
MmGetPageProtect(PEPROCESS Process, PVOID Address)
{
ULONG_PTR Pte;
PMMPTE PointerPte;
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
{
@ -671,34 +653,29 @@ MmGetPageProtect(PEPROCESS Process, PVOID Address)
MiMakePdeExistAndMakeValid(MiAddressToPde(Address), Process, MM_NOIRQL);
}
Pte = MiAddressToPte(Address)->u.Long;
PointerPte = MiAddressToPte(Address);
if (!(Pte & PA_PRESENT))
if (!PointerPte->u.Flush.Valid)
{
Protect = PAGE_NOACCESS;
}
else
{
if (Pte & PA_READWRITE)
{
if (PointerPte->u.Flush.CopyOnWrite)
Protect = PAGE_WRITECOPY;
else if (PointerPte->u.Flush.Write)
Protect = PAGE_READWRITE;
}
else
{
Protect = PAGE_EXECUTE_READ;
}
if (Pte & PA_CD)
{
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_NOCACHE;
}
if (Pte & PA_WT)
{
if (PointerPte->u.Flush.WriteThrough)
Protect |= PAGE_WRITETHROUGH;
}
if (!(Pte & PA_USER))
{
Protect |= PAGE_SYSTEM;
}
}
if (Address < MmSystemRangeStart)
@ -713,8 +690,7 @@ MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
{
ULONG ProtectionMask;
PMMPTE PointerPte;
MMPTE TempPte;
ULONG_PTR Pte;
MMPTE TempPte, OldPte;
DPRINT("MmSetPageProtect(Process %p Address %p flProtect %x)\n",
Process, Address, flProtect);
@ -739,16 +715,16 @@ MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
TempPte.u.Hard.Accessed = PointerPte->u.Hard.Accessed;
TempPte.u.Hard.Dirty = PointerPte->u.Hard.Dirty;
Pte = InterlockedExchangePte(PointerPte, TempPte.u.Long);
OldPte.u.Long = InterlockedExchangePte(PointerPte, TempPte.u.Long);
// We should be able to bring a page back from PAGE_NOACCESS
if ((Pte & 0x800) || !(Pte >> PAGE_SHIFT))
if (!OldPte.u.Hard.Valid && (FlagOn(OldPte.u.Long, 0x800) || (OldPte.u.Hard.PageFrameNumber == 0)))
{
DPRINT1("Invalid Pte %lx\n", Pte);
DPRINT1("Invalid Pte %lx\n", OldPte.u.Long);
KeBugCheck(MEMORY_MANAGEMENT);
}
if (Pte != TempPte.u.Long)
if (OldPte.u.Long != TempPte.u.Long)
KeInvalidateTlbEntry(Address);
MiUnlockProcessWorkingSetUnsafe(Process, PsGetCurrentThread());
@ -759,7 +735,6 @@ NTAPI
MmSetDirtyBit(PEPROCESS Process, PVOID Address, BOOLEAN Bit)
{
PMMPTE PointerPte;
ULONG Pte;
DPRINT("MmSetDirtyBit(Process %p Address %p Bit %x)\n",
Process, Address, Bit);
@ -774,20 +749,15 @@ 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 ((Pte & 0x800) || !(Pte >> PAGE_SHIFT))
if (!PointerPte->u.Hard.Valid && (FlagOn(PointerPte->u.Long, 0x800) || (PointerPte->u.Hard.PageFrameNumber == 0)))
{
DPRINT1("Invalid Pte %lx\n", Pte);
DPRINT1("Invalid Pte %lx\n", PointerPte->u.Long);
KeBugCheck(MEMORY_MANAGEMENT);
}
PointerPte->u.Hard.Dirty = !!Bit;
if (!Bit)
KeInvalidateTlbEntry(Address);
@ -802,4 +772,21 @@ 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 */