📄 page.c
字号:
/* $Id: page.c 28174 2007-08-05 11:27:39Z fireball $
*
* 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)
*/
/* INCLUDES ***************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
#pragma alloc_text(INIT, MiInitPageDirectoryMap)
#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 PAGETABLE_MAP (0xc0000000)
#define PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (1024)))
#define PAE_PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (512)))
#define HYPERSPACE (Ke386Pae ? 0xc0800000 : 0xc0400000)
#define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
ULONG MmGlobalKernelPageDirectory[1024];
ULONGLONG MmGlobalKernelPageDirectoryForPAE[2048];
#define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT)
#define PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
#define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
#define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT)
#if defined(__GNUC__)
#define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
#else
__inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
{
LARGE_INTEGER dummy;
dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
return dummy;
}
#endif
extern BOOLEAN Ke386Pae;
extern BOOLEAN Ke386NoExecute;
/* FUNCTIONS ***************************************************************/
BOOLEAN MmUnmapPageTable(PULONG Pt);
VOID
STDCALL
MiFlushTlbIpiRoutine(PVOID Address)
{
if (Address == (PVOID)0xffffffff)
{
KeFlushCurrentTb();
}
else if (Address == (PVOID)0xfffffffe)
{
KeFlushCurrentTb();
}
else
{
__invlpg(Address);
}
}
VOID
MiFlushTlb(PULONG Pt, PVOID Address)
{
#ifdef CONFIG_SMP
if (Pt)
{
MmUnmapPageTable(Pt);
}
if (KeNumberProcessors>1)
{
KeIpiGenericCall(MiFlushTlbIpiRoutine, Address);
}
else
{
MiFlushTlbIpiRoutine(Address);
}
#else
if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
{
__invlpg(Address);
}
#endif
}
PULONG
MmGetPageDirectory(VOID)
{
return (PULONG)__readcr3();
}
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(0);
}
if (Ke386NoExecute &&
!(flProtect & PAGE_IS_EXECUTABLE))
{
Attributes = Attributes | 0x80000000;
}
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);
}
#define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
#define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
#define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
#define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
#define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
#define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE))
#define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
#define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7)))
#define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
#define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
#define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
#define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
NTSTATUS
NTAPI
Mmi386ReleaseMmInfo(PEPROCESS Process)
{
PUSHORT LdtDescriptor;
ULONG LdtBase;
ULONG i, j;
DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process);
LdtDescriptor = (PUSHORT) &Process->Pcb.LdtDescriptor;
LdtBase = LdtDescriptor[1] |
((LdtDescriptor[2] & 0xff) << 16) |
((LdtDescriptor[3] & ~0xff) << 16);
DPRINT("LdtBase: %x\n", LdtBase);
if (LdtBase)
{
ExFreePool((PVOID) LdtBase);
}
if (Ke386Pae)
{
PULONGLONG PageDirTable;
PULONGLONG PageDir;
PULONGLONG Pde;
ULONG k;
PageDirTable = (PULONGLONG)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
for (i = 0; i < 4; i++)
{
PageDir = (PULONGLONG)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable[i]));
if (i < PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart))
{
for (j = 0; j < 512; j++)
{
if (PageDir[j] != 0LL)
{
DPRINT1("ProcessId %d, Pde for %08x - %08x is not freed, RefCount %d\n",
Process->UniqueProcessId,
(i * 512 + j) * 512 * PAGE_SIZE, (i * 512 + j + 1) * 512 * PAGE_SIZE - 1,
((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable[i*512 + j]);
Pde = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDir[j]));
for (k = 0; k < 512; k++)
{
if(Pde[k] != 0)
{
if (Pde[k] & PA_PRESENT)
{
DPRINT1("Page at %08x is not freed\n",
(i * 512 + j) * 512 * PAGE_SIZE + k * PAGE_SIZE);
}
else
{
DPRINT1("Swapentry %x at %x is not freed\n",
(i * 512 + j) * 512 * PAGE_SIZE + k * PAGE_SIZE);
}
}
}
MmDeleteHyperspaceMapping(Pde);
MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[j]));
}
}
}
if (i == PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE))
{
MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)]));
MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1]));
}
MmDeleteHyperspaceMapping(PageDir);
MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDirTable[i]));
}
MmDeleteHyperspaceMapping((PVOID)PageDirTable);
MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
}
else
{
PULONG Pde;
PULONG PageDir;
PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart));
for (i = 0; i < ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i++)
{
if (PageDir[i] != 0)
{
DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n",
i * 4 * 1024 * 1024, (i + 1) * 4 * 1024 * 1024 - 1,
((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable[i]);
Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(PageDir[i]));
for (j = 0; j < 1024; j++)
{
if(Pde[j] != 0)
{
if (Pde[j] & PA_PRESENT)
{
DPRINT1("Page at %08x is not freed\n",
i * 4 * 1024 * 1024 + j * PAGE_SIZE);
}
else
{
DPRINT1("Swapentry %x at %x is not freed\n",
Pde[j], i * 4 * 1024 * 1024 + j * PAGE_SIZE);
}
}
}
MmDeleteHyperspaceMapping(Pde);
MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(PageDir[i]));
}
}
MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(PageDir[ADDR_TO_PDE_OFFSET(HYPERSPACE)]));
MmDeleteHyperspaceMapping(PageDir);
MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart));
}
#if defined(__GNUC__)
Process->Pcb.DirectoryTableBase.QuadPart = 0LL;
#else
Process->Pcb.DirectoryTableBase.QuadPart = 0;
#endif
DPRINT("Finished Mmi386ReleaseMmInfo()\n");
return(STATUS_SUCCESS);
}
NTSTATUS
STDCALL
MmCopyMmInfo(PEPROCESS Src,
PEPROCESS Dest,
PPHYSICAL_ADDRESS DirectoryTableBase)
{
NTSTATUS Status;
ULONG i, j;
PFN_TYPE Pfn[7];
ULONG Count;
DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
Count = Ke386Pae ? 7 : 2;
for (i = 0; i < Count; i++)
{
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]);
if (!NT_SUCCESS(Status))
{
for (j = 0; j < i; j++)
{
MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn[j]);
}
return Status;
}
}
if (Ke386Pae)
{
PULONGLONG PageDirTable;
PULONGLONG PageDir;
PageDirTable = MmCreateHyperspaceMapping(Pfn[0]);
for (i = 0; i < 4; i++)
{
PageDirTable[i] = PAE_PFN_TO_PTE(Pfn[1+i]) | PA_PRESENT;
}
MmDeleteHyperspaceMapping(PageDirTable);
for (i = PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart); i < 4; i++)
{
PageDir = (PULONGLONG)MmCreateHyperspaceMapping(Pfn[i+1]);
memcpy(PageDir, &MmGlobalKernelPageDirectoryForPAE[i * 512], 512 * sizeof(ULONGLONG));
if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP) == i)
{
for (j = 0; j < 4; j++)
{
PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP) + j] = PAE_PFN_TO_PTE(Pfn[1+j]) | PA_PRESENT | PA_READWRITE;
}
}
if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE) == i)
{
PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)] = PAE_PFN_TO_PTE(Pfn[5]) | PA_PRESENT | PA_READWRITE;
PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1] = PAE_PFN_TO_PTE(Pfn[6]) | PA_PRESENT | PA_READWRITE;
}
MmDeleteHyperspaceMapping(PageDir);
}
}
else
{
PULONG PageDirectory;
PageDirectory = MmCreateHyperspaceMapping(Pfn[0]);
memcpy(PageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart),
MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart),
(1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart)) * sizeof(ULONG));
DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP));
PageDirectory[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)] = PFN_TO_PTE(Pfn[0]) | PA_PRESENT | PA_READWRITE;
PageDirectory[ADDR_TO_PDE_OFFSET(HYPERSPACE)] = PFN_TO_PTE(Pfn[1]) | PA_PRESENT | PA_READWRITE;
MmDeleteHyperspaceMapping(PageDirectory);
}
DirectoryTableBase->QuadPart = PFN_TO_PTE(Pfn[0]);
DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase->QuadPart);
return(STATUS_SUCCESS);
}
VOID
NTAPI
MmDeletePageTable(PEPROCESS Process, PVOID Address)
{
PEPROCESS CurrentProcess = PsGetCurrentProcess();
if (Process != NULL && Process != CurrentProcess)
{
KeAttachProcess(&Process->Pcb);
}
if (Ke386Pae)
{
ULONGLONG ZeroPde = 0LL;
(void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPde);
MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address));
}
else
{
*(ADDR_TO_PDE(Address)) = 0;
MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address));
}
if (Address >= MmSystemRangeStart)
{
KEBUGCHECK(0);
// MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
}
if (Process != NULL && Process != CurrentProcess)
{
KeDetachProcess();
}
}
VOID
NTAPI
MmFreePageTable(PEPROCESS Process, PVOID Address)
{
PEPROCESS CurrentProcess = PsGetCurrentProcess();
ULONG i;
PFN_TYPE Pfn;
DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address);
if (Process != NULL && Process != CurrentProcess)
{
KeAttachProcess(&Process->Pcb);
}
if (Ke386Pae)
{
PULONGLONG PageTable;
ULONGLONG ZeroPte = 0LL;
PageTable = (PULONGLONG)PAGE_ROUND_DOWN((PVOID)PAE_ADDR_TO_PTE(Address));
for (i = 0; i < 512; i++)
{
if (PageTable[i] != 0LL)
{
DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
((ULONG)Address / (4*1024*1024)), i, PageTable[i]);
KEBUGCHECK(0);
}
}
Pfn = PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address)));
(void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPte);
MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address));
}
else
{
PULONG PageTable;
PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address));
for (i = 0; i < 1024; i++)
{
if (PageTable[i] != 0)
{
DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
((ULONG)Address / (4*1024*1024)), i, PageTable[i]);
KEBUGCHECK(0);
}
}
Pfn = PTE_TO_PFN(*(ADDR_TO_PDE(Address)));
*(ADDR_TO_PDE(Address)) = 0;
MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address));
}
if (Address >= MmSystemRangeStart)
{
// MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
KEBUGCHECK(0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -