2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-01-26 13:58:37 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/i386/page.c
|
|
|
|
* PURPOSE: Low level memory managment manipulation
|
|
|
|
*
|
|
|
|
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
1999-11-12 12:01:17 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ***************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
1999-11-12 12:01:17 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
1999-11-12 12:01:17 +00:00
|
|
|
|
2005-11-28 23:25:31 +00:00
|
|
|
#if defined (ALLOC_PRAGMA)
|
|
|
|
#pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
|
|
|
|
#pragma alloc_text(INIT, MiInitPageDirectoryMap)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
/* GLOBALS *****************************************************************/
|
|
|
|
|
2002-05-14 21:19:21 +00:00
|
|
|
#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)
|
2004-08-14 09:17:05 +00:00
|
|
|
#define PA_BIT_GLOBAL (8)
|
2002-05-14 21:19:21 +00:00
|
|
|
|
|
|
|
#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)
|
2004-08-14 09:17:05 +00:00
|
|
|
#define PA_GLOBAL (1 << PA_BIT_GLOBAL)
|
1999-11-12 12:01:17 +00:00
|
|
|
|
2008-02-15 06:53:49 +00:00
|
|
|
#define HYPERSPACE (0xc0400000)
|
2005-07-16 09:01:07 +00:00
|
|
|
#define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
|
2005-01-25 22:50:47 +00:00
|
|
|
|
2004-09-09 20:42:33 +00:00
|
|
|
ULONG MmGlobalKernelPageDirectory[1024];
|
2001-02-18 22:16:05 +00:00
|
|
|
|
2004-08-01 07:27:25 +00:00
|
|
|
#define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
|
2005-05-09 01:38:29 +00:00
|
|
|
#define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
|
2004-09-07 11:08:16 +00:00
|
|
|
|
|
|
|
#if defined(__GNUC__)
|
2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
* ntoskrnl/ke/i386/exp.c (KiDoubleFaultHandler): Print CR3
correctly.
2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
* ntoskrnl/include/internal/ps.h: Added KTHREAD_STACK_LIMIT definition.
* ntoskrnl/ke/i386/tskswitch.S (Ki386ContextSwitch): Force all the
pages of the kernel stack to be accessible from this process.
2002-06-04 David Welch <welch@cwcom.net>
* ntoskrnl/cc/view.c (ReadCacheSegmentChain): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/cc/copy.c (CcRosCreateCacheSegment): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/cc/copy.c (CcFreeCachePage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/include/internal/mm.h: Changed prototypes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/include/internal/ps.h (KPROCESS): Changed type of
page directory base to PHYSICAL_ADDRESS.
* ntoskrnl/include/internal/i386/mm.h: Changed prototypes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kthread.c (KeFreeStackPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kthread.c (KeInitializeThread): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/process.c (KeAttachProcess, KeDetachProcess): Changes
to use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kernel.c (PcrPages, KeApplicationProcessorInit): Changes
to use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MM_ALLOCATION_REQUEST): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MmReleasePageMemoryConsumer): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MmRequestPageMemoryConsumer): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/cont.c (MmFreeContinuousPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/cont.c (MmAllocateContinuousAlignedMemory): Changes to
use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/freelist.c (MmTransferOwnershipPage,
MmGetLRUFirstUserPage, MmGetLRUNextUserPage, MmGetContinuousPages,
MmInitializePageList, MmSetFlagsPage, MmSetRmapListHeadPage,
MmGetRmapListHeadPage, MmMarkPageMapped, MmMarkPageUnmapped,
MmGetFlagsPage, MmSetSavedSwapEntryPage, MmGetSavedSwapEntryPage,
MmReferencePage, MmGetReferenceCountPage, MmIsUsablePage,
MmDereferencePage, MmGetLockCountPage, MmLockPage, MmUnlockPage,
MmAllocPage): Changes to use PHYSICAL_ADDRESS type for physical
addresses.
* ntoskrnl/mm/iospace.c (MmMapIoSpace): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/kmap.c (ExAllocatePage, MiZeroPage, MiCopyFromUserPage,
ExAllocatePageWithPhysPage): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/marea.c (MmFreeMemoryArea): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/mdl.c (MmUnlockPages, MmMapLockedPages,
MmProbeAndLockPages): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/mm.c (MmSharedDataPagePhysicalAddress,
MmCommitPagedPoolAddress, MmNotPresentFault): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/mminit.c (MmInitVirtualMemory): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/ncache.c (MmAllocateNonCachedMemory,
MmFreeNonCachedPage): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/npool.c (grow_kernel_pool): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/rmap.c (MmPageOutPhysicalAddress, MmInsertRmap,
MmDeleteAllRmaps, MmDeleteRmap): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/section.c (MiReadPage, MmNotPresentFaultSectionView,
MmAccessFaultSectionView, MmPageOutDeleteMapping,
MmPageOutSectionView, MmFreeSectionPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/slab.c (ExGrowSlabCache): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/virtual.c (MmPageOutVirtualMemory,
MmNotPresentFaultVirtualMemory, MmFreeVirtualMemoryPage): Changes to
use PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/wset.c (MmTrimUserMemory): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/page.c (Mmi386ReleaseMmInfo, MmCopyMmInfo,
MmGetPhysicalAddressForProcess, MmCreateVirtualMapping,
MmCreateVirtualMappingUnsafe, MmCreateVirtualMappingForProcess,
MmDeleteVirtualMapping): Changes to use PHYSICAL_ADDRESS type for
physical address.
* ntoskrnl/ps/process (PsInitProcessManagment): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/ps/thread.c (PsAllocateCallbackStack): Changes to use
PHYSICAL_ADDRESS type for physical address.
2002-06-04 David Welch <welch@cwcom.net>
* Lots of change since the ChangeLog was last updated.
svn path=/trunk/; revision=3000
2002-06-04 15:26:58 +00:00
|
|
|
#define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
|
2003-12-30 18:52:06 +00:00
|
|
|
#else
|
|
|
|
__inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
LARGE_INTEGER dummy;
|
|
|
|
dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
|
|
|
|
return dummy;
|
2003-12-30 18:52:06 +00:00
|
|
|
}
|
|
|
|
#endif
|
2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
* ntoskrnl/ke/i386/exp.c (KiDoubleFaultHandler): Print CR3
correctly.
2002-06-04 David Welch <welch@whitehall1-5.seh.ox.ac.uk>
* ntoskrnl/include/internal/ps.h: Added KTHREAD_STACK_LIMIT definition.
* ntoskrnl/ke/i386/tskswitch.S (Ki386ContextSwitch): Force all the
pages of the kernel stack to be accessible from this process.
2002-06-04 David Welch <welch@cwcom.net>
* ntoskrnl/cc/view.c (ReadCacheSegmentChain): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/cc/copy.c (CcRosCreateCacheSegment): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/cc/copy.c (CcFreeCachePage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/include/internal/mm.h: Changed prototypes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/include/internal/ps.h (KPROCESS): Changed type of
page directory base to PHYSICAL_ADDRESS.
* ntoskrnl/include/internal/i386/mm.h: Changed prototypes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kthread.c (KeFreeStackPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kthread.c (KeInitializeThread): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/process.c (KeAttachProcess, KeDetachProcess): Changes
to use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/ke/kernel.c (PcrPages, KeApplicationProcessorInit): Changes
to use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MM_ALLOCATION_REQUEST): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MmReleasePageMemoryConsumer): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/balance.c (MmRequestPageMemoryConsumer): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/cont.c (MmFreeContinuousPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/cont.c (MmAllocateContinuousAlignedMemory): Changes to
use PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/freelist.c (MmTransferOwnershipPage,
MmGetLRUFirstUserPage, MmGetLRUNextUserPage, MmGetContinuousPages,
MmInitializePageList, MmSetFlagsPage, MmSetRmapListHeadPage,
MmGetRmapListHeadPage, MmMarkPageMapped, MmMarkPageUnmapped,
MmGetFlagsPage, MmSetSavedSwapEntryPage, MmGetSavedSwapEntryPage,
MmReferencePage, MmGetReferenceCountPage, MmIsUsablePage,
MmDereferencePage, MmGetLockCountPage, MmLockPage, MmUnlockPage,
MmAllocPage): Changes to use PHYSICAL_ADDRESS type for physical
addresses.
* ntoskrnl/mm/iospace.c (MmMapIoSpace): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/kmap.c (ExAllocatePage, MiZeroPage, MiCopyFromUserPage,
ExAllocatePageWithPhysPage): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/marea.c (MmFreeMemoryArea): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/mdl.c (MmUnlockPages, MmMapLockedPages,
MmProbeAndLockPages): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/mm.c (MmSharedDataPagePhysicalAddress,
MmCommitPagedPoolAddress, MmNotPresentFault): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/mminit.c (MmInitVirtualMemory): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/ncache.c (MmAllocateNonCachedMemory,
MmFreeNonCachedPage): Changes to use PHYSICAL_ADDRESS type for
physical addresses.
* ntoskrnl/mm/npool.c (grow_kernel_pool): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/rmap.c (MmPageOutPhysicalAddress, MmInsertRmap,
MmDeleteAllRmaps, MmDeleteRmap): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/section.c (MiReadPage, MmNotPresentFaultSectionView,
MmAccessFaultSectionView, MmPageOutDeleteMapping,
MmPageOutSectionView, MmFreeSectionPage): Changes to use
PHYSICAL_ADDRESS type for physical addresses.
* ntoskrnl/mm/slab.c (ExGrowSlabCache): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/virtual.c (MmPageOutVirtualMemory,
MmNotPresentFaultVirtualMemory, MmFreeVirtualMemoryPage): Changes to
use PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/wset.c (MmTrimUserMemory): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/mm/page.c (Mmi386ReleaseMmInfo, MmCopyMmInfo,
MmGetPhysicalAddressForProcess, MmCreateVirtualMapping,
MmCreateVirtualMappingUnsafe, MmCreateVirtualMappingForProcess,
MmDeleteVirtualMapping): Changes to use PHYSICAL_ADDRESS type for
physical address.
* ntoskrnl/ps/process (PsInitProcessManagment): Changes to use
PHYSICAL_ADDRESS type for physical address.
* ntoskrnl/ps/thread.c (PsAllocateCallbackStack): Changes to use
PHYSICAL_ADDRESS type for physical address.
2002-06-04 David Welch <welch@cwcom.net>
* Lots of change since the ChangeLog was last updated.
svn path=/trunk/; revision=3000
2002-06-04 15:26:58 +00:00
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
|
2004-11-27 16:37:52 +00:00
|
|
|
BOOLEAN MmUnmapPageTable(PULONG Pt);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
MiFlushTlb(PULONG Pt, PVOID Address)
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
|
|
|
|
{
|
2009-11-04 22:51:00 +00:00
|
|
|
KeInvalidateTlbEntry(Address);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2004-11-27 16:37:52 +00:00
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
static ULONG
|
2001-01-08 02:14:06 +00:00
|
|
|
ProtectToPTE(ULONG flProtect)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
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");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2005-05-09 01:38:29 +00:00
|
|
|
static PULONG
|
2006-05-18 20:32:17 +00:00
|
|
|
MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
|
2000-08-20 17:02:10 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG PdeOffset = ADDR_TO_PDE_OFFSET(Address);
|
|
|
|
NTSTATUS Status;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Pfn;
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Entry;
|
|
|
|
PULONG Pt, PageDir;
|
|
|
|
|
|
|
|
if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
|
|
|
|
{
|
2008-08-11 08:40:52 +00:00
|
|
|
PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]));
|
2008-07-31 07:04:58 +00:00
|
|
|
if (PageDir == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2008-08-16 01:58:59 +00:00
|
|
|
if (0 == InterlockedCompareExchangePte(&PageDir[PdeOffset], 0, 0))
|
2008-07-31 07:04:58 +00:00
|
|
|
{
|
|
|
|
if (Create == FALSE)
|
|
|
|
{
|
|
|
|
MmDeleteHyperspaceMapping(PageDir);
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-08-01 07:27:25 +00:00
|
|
|
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
|
2008-07-31 07:04:58 +00:00
|
|
|
if (!NT_SUCCESS(Status) || Pfn == 0)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2008-08-16 01:58:59 +00:00
|
|
|
Entry = InterlockedCompareExchangePte(&PageDir[PdeOffset], PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Entry != 0)
|
|
|
|
{
|
|
|
|
MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
|
|
|
|
Pfn = PTE_TO_PFN(Entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Pfn = PTE_TO_PFN(PageDir[PdeOffset]);
|
|
|
|
}
|
|
|
|
MmDeleteHyperspaceMapping(PageDir);
|
|
|
|
Pt = MmCreateHyperspaceMapping(Pfn);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
return Pt + ADDR_TO_PTE_OFFSET(Address);
|
|
|
|
}
|
|
|
|
PageDir = (PULONG)MiAddressToPde(Address);
|
2008-08-16 01:58:59 +00:00
|
|
|
if (0 == InterlockedCompareExchangePte(PageDir, 0, 0))
|
2008-07-31 07:04:58 +00:00
|
|
|
{
|
|
|
|
if (Address >= MmSystemRangeStart)
|
|
|
|
{
|
2008-08-16 01:58:59 +00:00
|
|
|
if (0 == InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory[PdeOffset], 0, 0))
|
2008-07-31 07:04:58 +00:00
|
|
|
{
|
|
|
|
if (Create == FALSE)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
2009-06-21 05:33:48 +00:00
|
|
|
Status = MmRequestPageMemoryConsumer(MC_SYSTEM, FALSE, &Pfn);
|
2008-07-31 07:04:58 +00:00
|
|
|
if (!NT_SUCCESS(Status) || Pfn == 0)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
|
2008-08-16 01:58:59 +00:00
|
|
|
if(0 != InterlockedCompareExchangePte(&MmGlobalKernelPageDirectory[PdeOffset], Entry, 0))
|
2008-07-31 07:04:58 +00:00
|
|
|
{
|
2009-06-21 05:33:48 +00:00
|
|
|
MmReleasePageMemoryConsumer(MC_SYSTEM, Pfn);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2009-06-21 05:33:48 +00:00
|
|
|
InterlockedExchangePte(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
|
|
|
|
RtlZeroMemory(MiPteToAddress(PageDir), PAGE_SIZE);
|
|
|
|
return (PULONG)MiAddressToPte(Address);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2008-08-16 01:58:59 +00:00
|
|
|
InterlockedExchangePte(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (Create == FALSE)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
|
|
|
|
if (!NT_SUCCESS(Status) || Pfn == 0)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2008-08-16 01:58:59 +00:00
|
|
|
Entry = InterlockedCompareExchangePte(PageDir, PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Entry != 0)
|
|
|
|
{
|
|
|
|
MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (PULONG)MiAddressToPte(Address);
|
2000-07-06 14:34:52 +00:00
|
|
|
}
|
|
|
|
|
2004-09-07 11:08:16 +00:00
|
|
|
BOOLEAN MmUnmapPageTable(PULONG Pt)
|
2000-07-06 14:34:52 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Pt)
|
|
|
|
{
|
|
|
|
MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt));
|
|
|
|
}
|
|
|
|
return FALSE;
|
2004-09-09 20:42:33 +00:00
|
|
|
}
|
|
|
|
|
2006-05-18 20:32:17 +00:00
|
|
|
static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
|
2004-09-07 11:08:16 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Pte;
|
|
|
|
PULONG Pt;
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
if (Pt)
|
|
|
|
{
|
|
|
|
Pte = *Pt;
|
|
|
|
MmUnmapPageTable(Pt);
|
|
|
|
return Pte;
|
|
|
|
}
|
|
|
|
return 0;
|
2004-09-07 11:08:16 +00:00
|
|
|
}
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmGetPfnForProcess(PEPROCESS Process,
|
2004-08-01 07:27:25 +00:00
|
|
|
PVOID Address)
|
1999-11-24 11:51:55 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Entry;
|
|
|
|
Entry = MmGetPageEntryForProcess(Process, Address);
|
|
|
|
if (!(Entry & PA_PRESENT))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return(PTE_TO_PFN(Entry));
|
1999-11-24 11:51:55 +00:00
|
|
|
}
|
2002-11-05 21:13:15 +00:00
|
|
|
|
2001-12-31 01:53:46 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2010-07-15 22:50:12 +00:00
|
|
|
MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page)
|
2001-12-31 01:53:46 +00:00
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* FUNCTION: Delete a virtual mapping
|
2001-12-31 01:53:46 +00:00
|
|
|
*/
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
BOOLEAN WasValid;
|
|
|
|
ULONG Pte;
|
|
|
|
PULONG Pt;
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Atomically disable the present bit and get the old value.
|
|
|
|
*/
|
|
|
|
do
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
Pte = *Pt;
|
2008-08-16 01:58:59 +00:00
|
|
|
} while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_PRESENT, Pte));
|
2008-07-31 07:04:58 +00:00
|
|
|
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
WasValid = (PAGE_MASK(Pte) != 0);
|
|
|
|
if (!WasValid)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return some information to the caller
|
|
|
|
*/
|
|
|
|
if (WasDirty != NULL)
|
|
|
|
{
|
|
|
|
*WasDirty = Pte & PA_DIRTY;
|
|
|
|
}
|
|
|
|
if (Page != NULL)
|
|
|
|
{
|
|
|
|
*Page = PTE_TO_PFN(Pte);
|
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
}
|
2002-11-05 21:13:15 +00:00
|
|
|
|
2003-07-13 14:36:32 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2003-07-13 14:36:32 +00:00
|
|
|
MmRawDeleteVirtualMapping(PVOID Address)
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
PULONG Pt;
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(NULL, Address, FALSE);
|
|
|
|
if (Pt && *Pt)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Set the entry to zero
|
|
|
|
*/
|
2008-08-16 01:58:59 +00:00
|
|
|
InterlockedExchangePte(Pt, 0);
|
2008-07-31 07:04:58 +00:00
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
}
|
2003-07-13 14:36:32 +00:00
|
|
|
}
|
|
|
|
|
2001-03-25 03:34:30 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
|
2010-07-15 22:50:12 +00:00
|
|
|
BOOLEAN* WasDirty, PPFN_NUMBER Page)
|
2000-08-20 17:02:10 +00:00
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* FUNCTION: Delete a virtual mapping
|
2000-08-20 17:02:10 +00:00
|
|
|
*/
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
BOOLEAN WasValid = FALSE;
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Pfn;
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Pte;
|
|
|
|
PULONG Pt;
|
|
|
|
|
|
|
|
DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
|
|
|
|
Process, Address, FreePage, WasDirty, Page);
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
|
|
|
if (WasDirty != NULL)
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
*WasDirty = FALSE;
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
if (Page != NULL)
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
*Page = 0;
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Atomically set the entry to zero and get the old value.
|
|
|
|
*/
|
2008-08-16 01:58:59 +00:00
|
|
|
Pte = InterlockedExchangePte(Pt, 0);
|
2008-07-31 07:04:58 +00:00
|
|
|
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
|
|
|
|
WasValid = (PAGE_MASK(Pte) != 0);
|
|
|
|
if (WasValid)
|
|
|
|
{
|
|
|
|
Pfn = PTE_TO_PFN(Pte);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Pfn = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FreePage && WasValid)
|
|
|
|
{
|
|
|
|
MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return some information to the caller
|
|
|
|
*/
|
|
|
|
if (WasDirty != NULL)
|
|
|
|
{
|
|
|
|
*WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
if (Page != NULL)
|
|
|
|
{
|
|
|
|
*Page = Pfn;
|
|
|
|
}
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2001-12-31 19:06:49 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
|
2004-04-10 22:36:07 +00:00
|
|
|
SWAPENTRY* SwapEntry)
|
2001-12-31 19:06:49 +00:00
|
|
|
/*
|
2005-05-09 01:38:29 +00:00
|
|
|
* FUNCTION: Delete a virtual mapping
|
2001-12-31 19:06:49 +00:00
|
|
|
*/
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Pte;
|
|
|
|
PULONG Pt;
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
|
|
|
*SwapEntry = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Atomically set the entry to zero and get the old value.
|
|
|
|
*/
|
2008-08-16 01:58:59 +00:00
|
|
|
Pte = InterlockedExchangePte(Pt, 0);
|
2008-07-31 07:04:58 +00:00
|
|
|
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return some information to the caller
|
|
|
|
*/
|
|
|
|
*SwapEntry = Pte >> 1;
|
2001-12-31 19:06:49 +00:00
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
BOOLEAN
|
2001-02-18 22:16:05 +00:00
|
|
|
Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
PULONG Pt, Pde;
|
|
|
|
Pde = (PULONG)MiAddressToPde(PAddress);
|
|
|
|
if (*Pde == 0)
|
|
|
|
{
|
|
|
|
Pt = MmGetPageTableForProcess(NULL, PAddress, FALSE);
|
|
|
|
if (Pt != NULL)
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
return TRUE;
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return(FALSE);
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmIsDirtyPage(PEPROCESS Process, PVOID Address)
|
2000-06-25 03:59:17 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
|
2000-06-25 03:59:17 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmSetCleanPage(PEPROCESS Process, PVOID Address)
|
2000-07-07 10:30:57 +00:00
|
|
|
{
|
2008-02-28 14:05:47 +00:00
|
|
|
PULONG Pt;
|
|
|
|
ULONG Pte;
|
2008-07-31 07:04:58 +00:00
|
|
|
|
2008-02-28 14:05:47 +00:00
|
|
|
if (Address < MmSystemRangeStart && Process == NULL)
|
|
|
|
{
|
|
|
|
DPRINT1("MmSetCleanPage is called for user space without a process.\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-02-28 14:05:47 +00:00
|
|
|
}
|
2008-07-31 07:04:58 +00:00
|
|
|
|
2008-02-28 14:05:47 +00:00
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
2008-07-31 07:04:58 +00:00
|
|
|
|
2008-02-28 14:05:47 +00:00
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-02-28 14:05:47 +00:00
|
|
|
}
|
2008-07-31 07:04:58 +00:00
|
|
|
|
2008-02-28 14:05:47 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
Pte = *Pt;
|
2008-08-16 01:58:59 +00:00
|
|
|
} while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_DIRTY, Pte));
|
2008-07-31 07:04:58 +00:00
|
|
|
|
2008-02-28 14:05:47 +00:00
|
|
|
if (Pte & PA_DIRTY)
|
|
|
|
{
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmUnmapPageTable(Pt);
|
|
|
|
}
|
2000-07-07 10:30:57 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmSetDirtyPage(PEPROCESS Process, PVOID Address)
|
2002-01-08 00:49:02 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
PULONG Pt;
|
|
|
|
ULONG Pte;
|
|
|
|
|
|
|
|
if (Address < MmSystemRangeStart && Process == NULL)
|
|
|
|
{
|
|
|
|
DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
Pte = *Pt;
|
2008-08-16 01:58:59 +00:00
|
|
|
} while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_DIRTY, Pte));
|
2008-07-31 07:04:58 +00:00
|
|
|
if (!(Pte & PA_DIRTY))
|
|
|
|
{
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmUnmapPageTable(Pt);
|
|
|
|
}
|
2008-02-15 06:53:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
PULONG Pt;
|
|
|
|
ULONG Pte;
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
Pte = *Pt;
|
2008-08-16 01:58:59 +00:00
|
|
|
} while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_PRESENT, Pte));
|
2008-07-31 07:04:58 +00:00
|
|
|
if (!(Pte & PA_PRESENT))
|
|
|
|
{
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmUnmapPageTable(Pt);
|
|
|
|
}
|
2001-12-31 01:53:46 +00:00
|
|
|
}
|
2002-11-05 21:13:15 +00:00
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmIsPagePresent(PEPROCESS Process, PVOID Address)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2009-02-19 11:47:34 +00:00
|
|
|
return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT;
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
|
2001-12-31 19:06:49 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Entry;
|
|
|
|
Entry = MmGetPageEntryForProcess(Process, Address);
|
2009-02-19 11:47:34 +00:00
|
|
|
return !(Entry & PA_PRESENT) && (Entry & 0x800) && Entry != 0;
|
2001-12-31 19:06:49 +00:00
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmCreatePageFileMapping(PEPROCESS Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID Address,
|
|
|
|
SWAPENTRY SwapEntry)
|
2001-12-31 19:06:49 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
PULONG Pt;
|
|
|
|
ULONG Pte;
|
|
|
|
|
|
|
|
if (Process == NULL && Address < MmSystemRangeStart)
|
|
|
|
{
|
|
|
|
DPRINT1("No process\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
if (Process != NULL && Address >= MmSystemRangeStart)
|
|
|
|
{
|
|
|
|
DPRINT1("Setting kernel address with process context\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2009-03-10 20:52:39 +00:00
|
|
|
|
2008-07-31 07:04:58 +00:00
|
|
|
if (SwapEntry & (1 << 31))
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, TRUE);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
Pte = *Pt;
|
2008-08-16 01:58:59 +00:00
|
|
|
InterlockedExchangePte(Pt, SwapEntry << 1);
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Pte != 0)
|
|
|
|
{
|
|
|
|
MiFlushTlb(Pt, Address);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmUnmapPageTable(Pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
2001-12-31 19:06:49 +00:00
|
|
|
}
|
|
|
|
|
2003-08-27 21:28:08 +00:00
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmCreateVirtualMappingUnsafe(PEPROCESS Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID Address,
|
|
|
|
ULONG flProtect,
|
2010-07-15 22:50:12 +00:00
|
|
|
PPFN_NUMBER Pages,
|
2004-08-01 07:27:25 +00:00
|
|
|
ULONG PageCount)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Attributes;
|
|
|
|
PVOID Addr;
|
|
|
|
ULONG i;
|
|
|
|
ULONG oldPdeOffset, PdeOffset;
|
|
|
|
PULONG Pt = NULL;
|
|
|
|
ULONG Pte;
|
|
|
|
BOOLEAN NoExecute = FALSE;
|
|
|
|
|
|
|
|
DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
|
|
|
|
Process, Address, flProtect, Pages, *Pages, PageCount);
|
|
|
|
|
|
|
|
if (Process == NULL)
|
|
|
|
{
|
|
|
|
if (Address < MmSystemRangeStart)
|
|
|
|
{
|
|
|
|
DPRINT1("No process\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
if (PageCount > 0x10000 ||
|
|
|
|
(ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
|
|
|
|
{
|
2009-02-19 11:47:34 +00:00
|
|
|
DPRINT1("Page count too large\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (Address >= MmSystemRangeStart)
|
|
|
|
{
|
|
|
|
DPRINT1("Setting kernel address with process context\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
|
|
|
|
(ULONG_PTR) Address / PAGE_SIZE + PageCount >
|
|
|
|
(ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
|
|
|
|
{
|
2009-02-19 11:47:34 +00:00
|
|
|
DPRINT1("Page Count too large\n");
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Attributes = ProtectToPTE(flProtect);
|
|
|
|
if (Attributes & 0x80000000)
|
|
|
|
{
|
|
|
|
NoExecute = TRUE;
|
|
|
|
}
|
|
|
|
Attributes &= 0xfff;
|
|
|
|
if (Address >= MmSystemRangeStart)
|
|
|
|
{
|
|
|
|
Attributes &= ~PA_USER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Attributes |= PA_USER;
|
|
|
|
}
|
|
|
|
|
|
|
|
Addr = Address;
|
|
|
|
oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1;
|
|
|
|
for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
|
|
|
|
{
|
|
|
|
if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
DPRINT1("Setting physical address but not allowing access at address "
|
|
|
|
"0x%.8X with attributes %x/%x.\n",
|
|
|
|
Addr, Attributes, flProtect);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
|
|
|
|
if (oldPdeOffset != PdeOffset)
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
MmUnmapPageTable(Pt);
|
2008-07-31 07:04:58 +00:00
|
|
|
Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
Pt++;
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
oldPdeOffset = PdeOffset;
|
|
|
|
|
|
|
|
Pte = *Pt;
|
2009-02-19 11:47:34 +00:00
|
|
|
if (PAGE_MASK(Pte) != 0 && !(Pte & PA_PRESENT) && (Pte & 0x800))
|
2008-07-31 07:04:58 +00:00
|
|
|
{
|
2009-02-19 11:47:34 +00:00
|
|
|
DPRINT1("Bad PTE %lx\n", Pte);
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2008-08-16 01:58:59 +00:00
|
|
|
InterlockedExchangePte(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Pte != 0)
|
|
|
|
{
|
2005-07-06 08:20:26 +00:00
|
|
|
if (Address > MmSystemRangeStart ||
|
2004-09-09 20:42:33 +00:00
|
|
|
(Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024))
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
MiFlushTlb(Pt, Address);
|
2004-09-09 20:42:33 +00:00
|
|
|
}
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Addr > Address)
|
|
|
|
{
|
|
|
|
MmUnmapPageTable(Pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
return(STATUS_SUCCESS);
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
NTSTATUS
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmCreateVirtualMapping(PEPROCESS Process,
|
2004-04-10 22:36:07 +00:00
|
|
|
PVOID Address,
|
|
|
|
ULONG flProtect,
|
2010-07-15 22:50:12 +00:00
|
|
|
PPFN_NUMBER Pages,
|
2004-08-01 07:27:25 +00:00
|
|
|
ULONG PageCount)
|
2001-03-26 20:46:53 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
for (i = 0; i < PageCount; i++)
|
|
|
|
{
|
|
|
|
if (!MmIsPageInUse(Pages[i]))
|
|
|
|
{
|
|
|
|
DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i]));
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return(MmCreateVirtualMappingUnsafe(Process,
|
|
|
|
Address,
|
|
|
|
flProtect,
|
|
|
|
Pages,
|
|
|
|
PageCount));
|
2001-03-26 20:46:53 +00:00
|
|
|
}
|
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
ULONG
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmGetPageProtect(PEPROCESS Process, PVOID Address)
|
2001-02-10 22:51:11 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Entry;
|
|
|
|
ULONG Protect;
|
2008-02-15 06:53:49 +00:00
|
|
|
|
2008-07-31 07:04:58 +00:00
|
|
|
Entry = MmGetPageEntryForProcess(Process, Address);
|
|
|
|
|
|
|
|
|
|
|
|
if (!(Entry & PA_PRESENT))
|
|
|
|
{
|
|
|
|
Protect = PAGE_NOACCESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (Entry & PA_READWRITE)
|
|
|
|
{
|
|
|
|
Protect = PAGE_READWRITE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Protect = PAGE_EXECUTE_READ;
|
|
|
|
}
|
|
|
|
if (Entry & PA_CD)
|
|
|
|
{
|
|
|
|
Protect |= PAGE_NOCACHE;
|
|
|
|
}
|
|
|
|
if (Entry & PA_WT)
|
|
|
|
{
|
|
|
|
Protect |= PAGE_WRITETHROUGH;
|
|
|
|
}
|
|
|
|
if (!(Entry & PA_USER))
|
|
|
|
{
|
|
|
|
Protect |= PAGE_SYSTEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return(Protect);
|
2001-02-10 22:51:11 +00:00
|
|
|
}
|
|
|
|
|
2004-04-10 22:36:07 +00:00
|
|
|
VOID
|
2005-09-14 01:05:50 +00:00
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG Attributes = 0;
|
|
|
|
BOOLEAN NoExecute = FALSE;
|
|
|
|
PULONG Pt;
|
|
|
|
|
|
|
|
DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n",
|
|
|
|
Process, Address, flProtect);
|
|
|
|
|
|
|
|
Attributes = ProtectToPTE(flProtect);
|
2009-02-19 11:47:34 +00:00
|
|
|
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Attributes & 0x80000000)
|
|
|
|
{
|
|
|
|
NoExecute = TRUE;
|
|
|
|
}
|
|
|
|
Attributes &= 0xfff;
|
|
|
|
if (Address >= MmSystemRangeStart)
|
|
|
|
{
|
|
|
|
Attributes &= ~PA_USER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Attributes |= PA_USER;
|
|
|
|
}
|
|
|
|
|
|
|
|
Pt = MmGetPageTableForProcess(Process, Address, FALSE);
|
|
|
|
if (Pt == NULL)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2008-08-16 01:58:59 +00:00
|
|
|
InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
|
2008-07-31 07:04:58 +00:00
|
|
|
MiFlushTlb(Pt, Address);
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2003-07-11 01:23:16 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2008-11-29 20:47:48 +00:00
|
|
|
PHYSICAL_ADDRESS NTAPI
|
2001-01-08 02:14:06 +00:00
|
|
|
MmGetPhysicalAddress(PVOID vaddr)
|
1999-11-12 12:01:17 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Returns the physical address corresponding to a virtual address
|
|
|
|
*/
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
PHYSICAL_ADDRESS p;
|
|
|
|
ULONG Pte;
|
|
|
|
|
|
|
|
DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
|
|
|
|
Pte = MmGetPageEntryForProcess(NULL, vaddr);
|
|
|
|
if (Pte != 0 && Pte & PA_PRESENT)
|
|
|
|
{
|
|
|
|
p.QuadPart = PAGE_MASK(Pte);
|
|
|
|
p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
p.QuadPart = 0;
|
|
|
|
}
|
|
|
|
return p;
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
2000-04-02 13:32:43 +00:00
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
2006-05-18 20:32:17 +00:00
|
|
|
MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size)
|
2003-05-07 21:41:03 +00:00
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG StartOffset, EndOffset, Offset;
|
|
|
|
PULONG Pde;
|
2009-07-26 08:20:29 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Check if the process isn't there anymore
|
|
|
|
// This is probably a bad sign, since it means the caller is setting cr3 to
|
|
|
|
// 0 or something...
|
|
|
|
//
|
|
|
|
if ((PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]) == 0) && (Process != PsGetCurrentProcess()))
|
|
|
|
{
|
|
|
|
DPRINT1("Process: %16s is dead: %p\n", Process->ImageFileName, Process->Pcb.DirectoryTableBase[0]);
|
|
|
|
ASSERT(FALSE);
|
|
|
|
return;
|
|
|
|
}
|
2009-03-14 21:29:37 +00:00
|
|
|
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Address < MmSystemRangeStart)
|
|
|
|
{
|
2008-11-26 18:56:41 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
2009-03-14 21:29:37 +00:00
|
|
|
|
2008-07-31 07:04:58 +00:00
|
|
|
StartOffset = ADDR_TO_PDE_OFFSET(Address);
|
|
|
|
EndOffset = ADDR_TO_PDE_OFFSET((PVOID)((ULONG_PTR)Address + Size));
|
2009-03-14 21:29:37 +00:00
|
|
|
|
2008-07-31 07:04:58 +00:00
|
|
|
if (Process != NULL && Process != PsGetCurrentProcess())
|
|
|
|
{
|
2009-03-14 21:29:37 +00:00
|
|
|
Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]));
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Pde = (PULONG)PAGEDIRECTORY_MAP;
|
|
|
|
}
|
|
|
|
for (Offset = StartOffset; Offset <= EndOffset; Offset++)
|
|
|
|
{
|
|
|
|
if (Offset != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP))
|
|
|
|
{
|
2008-08-16 01:58:59 +00:00
|
|
|
InterlockedCompareExchangePte(&Pde[Offset], MmGlobalKernelPageDirectory[Offset], 0);
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
2009-03-14 21:29:37 +00:00
|
|
|
if (Pde != (PULONG)PAGEDIRECTORY_MAP)
|
|
|
|
{
|
|
|
|
MmDeleteHyperspaceMapping(Pde);
|
|
|
|
}
|
2004-09-09 20:42:33 +00:00
|
|
|
}
|
2005-01-25 22:50:47 +00:00
|
|
|
|
2005-09-14 01:05:50 +00:00
|
|
|
VOID
|
|
|
|
INIT_FUNCTION
|
|
|
|
NTAPI
|
2004-09-09 20:42:33 +00:00
|
|
|
MmInitGlobalKernelPageDirectory(VOID)
|
|
|
|
{
|
2008-07-31 07:04:58 +00:00
|
|
|
ULONG i;
|
|
|
|
PULONG CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP;
|
|
|
|
|
|
|
|
DPRINT("MmInitGlobalKernelPageDirectory()\n");
|
|
|
|
|
|
|
|
for (i = ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 1024; i++)
|
|
|
|
{
|
|
|
|
if (i != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) &&
|
|
|
|
i != ADDR_TO_PDE_OFFSET(HYPERSPACE) &&
|
|
|
|
0 == MmGlobalKernelPageDirectory[i] && 0 != CurrentPageDirectory[i])
|
|
|
|
{
|
2004-09-09 20:42:33 +00:00
|
|
|
MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
|
2008-07-31 07:04:58 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-07 21:41:03 +00:00
|
|
|
}
|
2004-09-09 20:42:33 +00:00
|
|
|
|
2000-04-02 13:32:43 +00:00
|
|
|
/* EOF */
|