2001-03-16 18:11:24 +00:00
|
|
|
/* $Id: page.c,v 1.23 2001/03/16 18:11:24 dwelch Exp $
|
2000-04-02 13:32:43 +00:00
|
|
|
*
|
1999-11-12 12:01:17 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top directory
|
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/i386/page.c
|
|
|
|
* PURPOSE: low level memory managment manipulation
|
|
|
|
* PROGRAMER: David Welch (welch@cwcom.net)
|
|
|
|
* UPDATE HISTORY:
|
|
|
|
* 9/3/98: Created
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ***************************************************************/
|
|
|
|
|
|
|
|
#include <ddk/ntddk.h>
|
|
|
|
#include <internal/mm.h>
|
2001-03-16 18:11:24 +00:00
|
|
|
#include <internal/i386/mm.h>
|
1999-11-12 12:01:17 +00:00
|
|
|
#include <internal/ex.h>
|
2000-07-04 08:52:47 +00:00
|
|
|
#include <internal/ps.h>
|
1999-11-12 12:01:17 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <internal/debug.h>
|
|
|
|
|
|
|
|
/* GLOBALS *****************************************************************/
|
|
|
|
|
|
|
|
#define PA_BIT_PRESENT (0)
|
|
|
|
#define PA_BIT_READWRITE (1)
|
|
|
|
#define PA_BIT_USER (2)
|
2001-01-08 02:14:06 +00:00
|
|
|
#define PA_BIT_WT (3)
|
|
|
|
#define PA_BIT_CD (4)
|
|
|
|
#define PA_BIT_ACCESSED (5)
|
2000-06-25 03:59:17 +00:00
|
|
|
#define PA_BIT_DIRTY (6)
|
1999-11-12 12:01:17 +00:00
|
|
|
|
2001-02-10 22:51:11 +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)
|
|
|
|
#define PA_DIRTY (1 << PA_BIT_DIRTY)
|
1999-11-12 12:01:17 +00:00
|
|
|
|
|
|
|
#define PAGETABLE_MAP (0xf0000000)
|
|
|
|
#define PAGEDIRECTORY_MAP (0xf0000000 + (PAGETABLE_MAP / (1024)))
|
|
|
|
|
2001-02-18 22:16:05 +00:00
|
|
|
ULONG MmGlobalKernelPageDirectory[1024] = {0, };
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
/* FUNCTIONS ***************************************************************/
|
|
|
|
|
2001-01-08 02:14:06 +00:00
|
|
|
PULONG
|
|
|
|
MmGetPageDirectory(VOID)
|
2000-10-07 13:41:58 +00:00
|
|
|
{
|
|
|
|
unsigned int page_dir=0;
|
|
|
|
__asm__("movl %%cr3,%0\n\t"
|
|
|
|
: "=r" (page_dir));
|
|
|
|
return((PULONG)page_dir);
|
|
|
|
}
|
|
|
|
|
2001-01-08 02:14:06 +00:00
|
|
|
static ULONG
|
|
|
|
ProtectToPTE(ULONG flProtect)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2001-01-08 02:14:06 +00:00
|
|
|
ULONG Attributes = 0;
|
|
|
|
|
|
|
|
if (flProtect & PAGE_NOACCESS || flProtect & PAGE_GUARD)
|
|
|
|
{
|
|
|
|
Attributes = 0;
|
|
|
|
}
|
1999-11-12 12:01:17 +00:00
|
|
|
if (flProtect & PAGE_READWRITE || flProtect & PAGE_EXECUTE_READWRITE)
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
Attributes = PA_PRESENT | PA_READWRITE;
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
if (flProtect & PAGE_READONLY || flProtect & PAGE_EXECUTE ||
|
|
|
|
flProtect & PAGE_EXECUTE_READ)
|
|
|
|
{
|
2001-02-10 22:51:11 +00:00
|
|
|
Attributes = PA_PRESENT;
|
2001-01-08 02:14:06 +00:00
|
|
|
}
|
|
|
|
if (!(flProtect & PAGE_SYSTEM))
|
|
|
|
{
|
|
|
|
Attributes = Attributes | PA_USER;
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
if (flProtect & PAGE_NOCACHE)
|
2001-01-08 02:14:06 +00:00
|
|
|
{
|
|
|
|
Attributes = Attributes | PA_CD;
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
if (flProtect & PAGE_WRITETHROUGH)
|
2001-01-08 02:14:06 +00:00
|
|
|
{
|
|
|
|
Attributes = Attributes | PA_WT;
|
|
|
|
}
|
1999-11-12 12:01:17 +00:00
|
|
|
return(Attributes);
|
|
|
|
}
|
|
|
|
|
2000-08-20 17:02:10 +00:00
|
|
|
#define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (4 * 1024 * 1024))
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
#define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
|
|
|
|
(((ULONG)v / (1024 * 1024))&(~0x3)))
|
2000-04-07 02:24:03 +00:00
|
|
|
#define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)v / 1024))&(~0x3)))
|
1999-11-12 12:01:17 +00:00
|
|
|
|
2001-02-18 22:16:05 +00:00
|
|
|
#define ADDR_TO_PDE_OFFSET(v) (((ULONG)v / (4 * 1024 * 1024)))
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
NTSTATUS Mmi386ReleaseMmInfo(PEPROCESS Process)
|
|
|
|
{
|
|
|
|
DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process);
|
|
|
|
|
1999-12-20 02:14:40 +00:00
|
|
|
MmDereferencePage(Process->Pcb.PageTableDirectory);
|
1999-11-12 12:01:17 +00:00
|
|
|
Process->Pcb.PageTableDirectory = NULL;
|
|
|
|
|
|
|
|
DPRINT("Finished Mmi386ReleaseMmInfo()\n");
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS MmCopyMmInfo(PEPROCESS Src, PEPROCESS Dest)
|
|
|
|
{
|
|
|
|
PULONG PhysPageDirectory;
|
|
|
|
PULONG PageDirectory;
|
|
|
|
PULONG CurrentPageDirectory;
|
|
|
|
PKPROCESS KProcess = &Dest->Pcb;
|
|
|
|
ULONG i;
|
|
|
|
|
|
|
|
DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
|
|
|
|
|
|
|
|
PageDirectory = ExAllocatePage();
|
|
|
|
if (PageDirectory == NULL)
|
|
|
|
{
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
PhysPageDirectory = (PULONG)(MmGetPhysicalAddress(PageDirectory)).u.LowPart;
|
|
|
|
KProcess->PageTableDirectory = PhysPageDirectory;
|
|
|
|
CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP;
|
|
|
|
|
|
|
|
memset(PageDirectory,0,PAGESIZE);
|
|
|
|
for (i=768; i<896; i++)
|
|
|
|
{
|
|
|
|
PageDirectory[i] = CurrentPageDirectory[i];
|
|
|
|
}
|
2000-10-07 13:41:58 +00:00
|
|
|
for (i=961; i<1024; i++)
|
|
|
|
{
|
|
|
|
PageDirectory[i] = CurrentPageDirectory[i];
|
|
|
|
}
|
1999-12-22 14:48:30 +00:00
|
|
|
DPRINT("Addr %x\n",PAGETABLE_MAP / (4*1024*1024));
|
|
|
|
PageDirectory[PAGETABLE_MAP / (4*1024*1024)] =
|
|
|
|
(ULONG)PhysPageDirectory | 0x7;
|
1999-11-12 12:01:17 +00:00
|
|
|
|
|
|
|
ExUnmapPage(PageDirectory);
|
|
|
|
|
|
|
|
DPRINT("Finished MmCopyMmInfo()\n");
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID MmDeletePageTable(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
|
|
|
*(ADDR_TO_PDE(Address)) = 0;
|
2001-02-18 22:16:05 +00:00
|
|
|
if (Address >= (PVOID)KERNEL_BASE)
|
|
|
|
{
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
|
|
|
|
}
|
1999-11-12 12:01:17 +00:00
|
|
|
FLUSH_TLB;
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-20 17:02:10 +00:00
|
|
|
VOID MmFreePageTable(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
PULONG PageTable;
|
|
|
|
ULONG i;
|
|
|
|
ULONG npage;
|
|
|
|
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
|
|
|
PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address));
|
|
|
|
for (i = 0; i < 1024; i++)
|
|
|
|
{
|
|
|
|
if (PageTable[i] != 0)
|
|
|
|
{
|
2001-02-18 17:43:32 +00:00
|
|
|
DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
|
|
|
|
((ULONG)Address / 4*1024*1024), i, PageTable[i]);
|
|
|
|
KeBugCheck(0);
|
2000-08-20 17:02:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
npage = *(ADDR_TO_PDE(Address));
|
|
|
|
*(ADDR_TO_PDE(Address)) = 0;
|
2001-02-18 22:16:05 +00:00
|
|
|
if (Address >= (PVOID)KERNEL_BASE)
|
|
|
|
{
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
MmDereferencePage((PVOID)PAGE_MASK(npage));
|
|
|
|
FLUSH_TLB;
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS MmGetPageEntry2(PVOID PAddress, PULONG* Pte)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Get a pointer to the page table entry for a virtual address
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PULONG Pde;
|
|
|
|
ULONG Address = (ULONG)PAddress;
|
|
|
|
ULONG npage;
|
|
|
|
|
|
|
|
DPRINT("MmGetPageEntry(Address %x)\n", Address);
|
|
|
|
|
|
|
|
Pde = ADDR_TO_PDE(Address);
|
2001-02-18 22:16:05 +00:00
|
|
|
if ((*Pde) == 0)
|
2000-08-20 17:02:10 +00:00
|
|
|
{
|
2001-02-18 22:16:05 +00:00
|
|
|
if (Address >= KERNEL_BASE &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*Pde) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
npage = (ULONG)MmAllocPage(0);
|
|
|
|
if (npage == 0)
|
|
|
|
{
|
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
|
|
|
(*Pde) = npage | 0x7;
|
|
|
|
if (Address >= KERNEL_BASE)
|
|
|
|
{
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] =
|
|
|
|
*Pde;
|
|
|
|
}
|
|
|
|
memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGESIZE);
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
}
|
|
|
|
*Pte = ADDR_TO_PTE(Address);
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
ULONG Entry;
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
|
|
|
Entry = *MmGetPageEntry(Address);
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
return(Entry);
|
|
|
|
}
|
|
|
|
|
2000-07-06 14:34:52 +00:00
|
|
|
ULONG MmGetPageEntry1(PVOID PAddress)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Get a pointer to the page table entry for a virtual address
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PULONG page_tlb;
|
|
|
|
PULONG page_dir;
|
|
|
|
ULONG Address = (ULONG)PAddress;
|
|
|
|
|
|
|
|
DPRINT("MmGetPageEntry(Address %x)\n", Address);
|
|
|
|
|
|
|
|
page_dir = ADDR_TO_PDE(Address);
|
2001-02-18 22:16:05 +00:00
|
|
|
if ((*page_dir) == 0 &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
2000-07-06 14:34:52 +00:00
|
|
|
DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir);
|
|
|
|
if ((*page_dir) == 0)
|
|
|
|
{
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
page_tlb = ADDR_TO_PTE(Address);
|
|
|
|
DPRINT("page_tlb %x\n",page_tlb);
|
|
|
|
return(*page_tlb);
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG MmGetPageEntryForProcess1(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
ULONG Entry;
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
|
|
|
Entry = MmGetPageEntry1(Address);
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
return(Entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-24 11:51:55 +00:00
|
|
|
ULONG MmGetPhysicalAddressForProcess(PEPROCESS Process,
|
|
|
|
PVOID Address)
|
|
|
|
{
|
|
|
|
ULONG PageEntry;
|
|
|
|
|
|
|
|
PageEntry = MmGetPageEntryForProcess(Process, Address);
|
|
|
|
|
|
|
|
if (!(PageEntry & PA_PRESENT))
|
|
|
|
{
|
|
|
|
return(0);
|
|
|
|
}
|
|
|
|
return(PAGE_MASK(PageEntry));
|
|
|
|
}
|
|
|
|
|
2000-08-20 17:02:10 +00:00
|
|
|
VOID MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOL FreePage)
|
|
|
|
/*
|
2001-02-06 00:11:20 +00:00
|
|
|
` * FUNCTION: Delete a virtual mapping
|
2000-08-20 17:02:10 +00:00
|
|
|
*/
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2000-08-20 17:02:10 +00:00
|
|
|
PULONG Pte;
|
|
|
|
PULONG Pde;
|
1999-11-12 12:01:17 +00:00
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
2001-02-10 22:51:11 +00:00
|
|
|
BOOLEAN WasValid;
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
Pde = ADDR_TO_PDE(Address);
|
2001-02-18 22:16:05 +00:00
|
|
|
if ((*Pde) == 0 &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*Pde) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
if ((*Pde) == 0)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
Pte = ADDR_TO_PTE(Address);
|
2001-02-10 22:51:11 +00:00
|
|
|
WasValid = (PAGE_MASK(*Pte) != 0);
|
2001-03-08 22:06:02 +00:00
|
|
|
if (WasValid)
|
|
|
|
{
|
|
|
|
MmMarkPageUnmapped((PVOID)PAGE_MASK(*Pte));
|
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
if (FreePage && WasValid)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
2000-08-20 17:02:10 +00:00
|
|
|
MmDereferencePage((PVOID)PAGE_MASK(*Pte));
|
|
|
|
}
|
|
|
|
*Pte = 0;
|
2001-02-10 22:51:11 +00:00
|
|
|
if (Process != NULL && WasValid &&
|
2000-08-20 17:02:10 +00:00
|
|
|
Process->AddressSpace.PageTableRefCountTable != NULL &&
|
|
|
|
ADDR_TO_PAGE_TABLE(Address) < 768)
|
|
|
|
{
|
|
|
|
PUSHORT Ptrc;
|
|
|
|
|
|
|
|
Ptrc = Process->AddressSpace.PageTableRefCountTable;
|
|
|
|
|
|
|
|
Ptrc[ADDR_TO_PAGE_TABLE(Address)]--;
|
2001-02-18 17:43:32 +00:00
|
|
|
#if 1
|
2000-08-20 17:02:10 +00:00
|
|
|
if (Ptrc[ADDR_TO_PAGE_TABLE(Address)] == 0)
|
1999-12-18 17:48:23 +00:00
|
|
|
{
|
2000-08-20 17:02:10 +00:00
|
|
|
MmFreePageTable(Process, Address);
|
1999-12-18 17:48:23 +00:00
|
|
|
}
|
2001-02-10 22:51:11 +00:00
|
|
|
#endif
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-18 22:16:05 +00:00
|
|
|
BOOLEAN
|
|
|
|
Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
|
|
|
|
{
|
|
|
|
PULONG page_dir;
|
|
|
|
ULONG Address = (ULONG)PAddress;
|
|
|
|
|
|
|
|
page_dir = ADDR_TO_PDE(Address);
|
|
|
|
if ((*page_dir) == 0 &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
2000-06-25 03:59:17 +00:00
|
|
|
BOOLEAN MmIsPageTablePresent(PVOID PAddress)
|
|
|
|
{
|
|
|
|
PULONG page_dir;
|
|
|
|
ULONG Address = (ULONG)PAddress;
|
|
|
|
|
|
|
|
page_dir = ADDR_TO_PDE(Address);
|
2001-02-18 22:16:05 +00:00
|
|
|
if ((*page_dir) == 0 &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
2000-06-25 03:59:17 +00:00
|
|
|
return((*page_dir) == 0);
|
|
|
|
}
|
1999-11-24 11:51:55 +00:00
|
|
|
|
2000-07-06 14:34:52 +00:00
|
|
|
NTSTATUS MmCreatePageTable(PVOID PAddress)
|
|
|
|
{
|
|
|
|
PULONG page_dir;
|
|
|
|
ULONG Address = (ULONG)PAddress;
|
|
|
|
ULONG npage;
|
|
|
|
|
|
|
|
DPRINT("MmGetPageEntry(Address %x)\n", Address);
|
|
|
|
|
|
|
|
page_dir = ADDR_TO_PDE(Address);
|
|
|
|
DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir);
|
2001-02-18 22:16:05 +00:00
|
|
|
if ((*page_dir) == 0 &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
2000-07-06 14:34:52 +00:00
|
|
|
if ((*page_dir) == 0)
|
|
|
|
{
|
|
|
|
npage = (ULONG)MmAllocPage(0);
|
|
|
|
if (npage == 0)
|
|
|
|
{
|
|
|
|
return(STATUS_UNSUCCESSFUL);
|
|
|
|
}
|
|
|
|
(*page_dir) = npage | 0x7;
|
|
|
|
memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGESIZE);
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
PULONG MmGetPageEntry(PVOID PAddress)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Get a pointer to the page table entry for a virtual address
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
PULONG page_tlb;
|
|
|
|
PULONG page_dir;
|
|
|
|
ULONG Address = (ULONG)PAddress;
|
2000-07-06 14:34:52 +00:00
|
|
|
ULONG npage;
|
1999-11-12 12:01:17 +00:00
|
|
|
|
|
|
|
DPRINT("MmGetPageEntry(Address %x)\n", Address);
|
|
|
|
|
|
|
|
page_dir = ADDR_TO_PDE(Address);
|
|
|
|
DPRINT("page_dir %x *page_dir %x\n",page_dir,*page_dir);
|
2001-02-18 22:16:05 +00:00
|
|
|
if ((*page_dir) == 0 &&
|
|
|
|
MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] != 0)
|
|
|
|
{
|
|
|
|
(*page_dir) = MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)];
|
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
1999-11-12 12:01:17 +00:00
|
|
|
if ((*page_dir) == 0)
|
|
|
|
{
|
2000-07-06 14:34:52 +00:00
|
|
|
npage = (ULONG)MmAllocPage(0);
|
|
|
|
if (npage == 0)
|
|
|
|
{
|
|
|
|
KeBugCheck(0);
|
|
|
|
}
|
|
|
|
(*page_dir) = npage | 0x7;
|
1999-12-22 14:48:30 +00:00
|
|
|
memset((PVOID)PAGE_ROUND_DOWN(ADDR_TO_PTE(Address)), 0, PAGESIZE);
|
1999-11-12 12:01:17 +00:00
|
|
|
FLUSH_TLB;
|
|
|
|
}
|
|
|
|
page_tlb = ADDR_TO_PTE(Address);
|
|
|
|
DPRINT("page_tlb %x\n",page_tlb);
|
|
|
|
return(page_tlb);
|
|
|
|
}
|
|
|
|
|
2000-06-25 03:59:17 +00:00
|
|
|
BOOLEAN MmIsPageDirty(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
return((MmGetPageEntryForProcess(Process, Address)) & PA_DIRTY);
|
|
|
|
}
|
|
|
|
|
2000-07-07 10:30:57 +00:00
|
|
|
VOID MmSetCleanPage(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
PULONG PageEntry;
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
|
|
|
|
if (Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
|
|
|
PageEntry = MmGetPageEntry(Address);
|
|
|
|
(*PageEntry) = (*PageEntry) & (~PA_DIRTY);
|
|
|
|
FLUSH_TLB;
|
|
|
|
if (Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
BOOLEAN MmIsPagePresent(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
2000-07-06 14:34:52 +00:00
|
|
|
return((MmGetPageEntryForProcess1(Process, Address)) & PA_PRESENT);
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-20 17:02:10 +00:00
|
|
|
NTSTATUS MmCreateVirtualMapping(PEPROCESS Process,
|
|
|
|
PVOID Address,
|
|
|
|
ULONG flProtect,
|
|
|
|
ULONG PhysicalAddress)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
ULONG Attributes = 0;
|
2000-08-20 17:02:10 +00:00
|
|
|
PULONG Pte;
|
|
|
|
NTSTATUS Status;
|
1999-11-12 12:01:17 +00:00
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
if (!MmIsUsablePage((PVOID)PhysicalAddress))
|
|
|
|
{
|
2001-02-18 17:43:32 +00:00
|
|
|
DPRINT1("Page not usable\n");
|
2001-02-10 22:51:11 +00:00
|
|
|
KeBugCheck(0);
|
|
|
|
}
|
2001-02-18 17:43:32 +00:00
|
|
|
if (Process == NULL && Address < (PVOID)KERNEL_BASE)
|
|
|
|
{
|
|
|
|
DPRINT1("No process\n");
|
|
|
|
KeBugCheck(0);
|
|
|
|
}
|
|
|
|
if (Process != NULL && Address >= (PVOID)KERNEL_BASE)
|
|
|
|
{
|
|
|
|
DPRINT1("Setting kernel address with process context\n");
|
|
|
|
KeBugCheck(0);
|
|
|
|
}
|
2001-03-08 22:06:02 +00:00
|
|
|
MmMarkPageMapped((PVOID)PhysicalAddress);
|
2001-02-18 17:43:32 +00:00
|
|
|
|
1999-11-12 12:01:17 +00:00
|
|
|
Attributes = ProtectToPTE(flProtect);
|
|
|
|
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
|
|
|
|
Status = MmGetPageEntry2(Address, &Pte);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
return(Status);
|
|
|
|
}
|
2001-03-08 22:06:02 +00:00
|
|
|
if (PAGE_MASK((*Pte)) != 0)
|
|
|
|
{
|
|
|
|
MmMarkPageUnmapped((PVOID)PAGE_MASK((*Pte)));
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
*Pte = PhysicalAddress | Attributes;
|
|
|
|
if (Process != NULL &&
|
|
|
|
Process->AddressSpace.PageTableRefCountTable != NULL &&
|
|
|
|
ADDR_TO_PAGE_TABLE(Address) < 768 &&
|
|
|
|
Attributes & PA_PRESENT)
|
|
|
|
{
|
|
|
|
PUSHORT Ptrc;
|
|
|
|
|
|
|
|
Ptrc = Process->AddressSpace.PageTableRefCountTable;
|
|
|
|
|
|
|
|
Ptrc[ADDR_TO_PAGE_TABLE(Address)]++;
|
|
|
|
}
|
1999-11-12 12:01:17 +00:00
|
|
|
FLUSH_TLB;
|
|
|
|
if (Process != NULL && Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
2000-08-20 17:02:10 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
|
|
|
|
2001-02-10 22:51:11 +00:00
|
|
|
ULONG
|
|
|
|
MmGetPageProtect(PEPROCESS Process, PVOID Address)
|
|
|
|
{
|
|
|
|
ULONG Entry;
|
|
|
|
ULONG Protect;
|
|
|
|
|
|
|
|
Entry = MmGetPageEntryForProcess1(Process, Address);
|
|
|
|
|
|
|
|
if (!(Entry & PA_PRESENT))
|
|
|
|
{
|
|
|
|
Protect = PAGE_NOACCESS;
|
|
|
|
}
|
|
|
|
else if (Entry & PA_READWRITE)
|
|
|
|
{
|
|
|
|
Protect = PAGE_READWRITE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Protect = PAGE_EXECUTE_READ;
|
|
|
|
}
|
|
|
|
return(Protect);
|
|
|
|
}
|
|
|
|
|
2001-01-08 02:14:06 +00:00
|
|
|
VOID
|
|
|
|
MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
|
1999-11-12 12:01:17 +00:00
|
|
|
{
|
|
|
|
ULONG Attributes = 0;
|
|
|
|
PULONG PageEntry;
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
|
|
|
|
Attributes = ProtectToPTE(flProtect);
|
|
|
|
|
|
|
|
if (Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(Process);
|
|
|
|
}
|
|
|
|
PageEntry = MmGetPageEntry(Address);
|
|
|
|
(*PageEntry) = PAGE_MASK(*PageEntry) | Attributes;
|
|
|
|
FLUSH_TLB;
|
|
|
|
if (Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-08 02:14:06 +00:00
|
|
|
PHYSICAL_ADDRESS STDCALL
|
|
|
|
MmGetPhysicalAddress(PVOID vaddr)
|
1999-11-12 12:01:17 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Returns the physical address corresponding to a virtual address
|
|
|
|
*/
|
|
|
|
{
|
1999-12-22 14:48:30 +00:00
|
|
|
PHYSICAL_ADDRESS p;
|
1999-11-12 12:01:17 +00:00
|
|
|
|
1999-12-22 14:48:30 +00:00
|
|
|
DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
|
1999-11-12 12:01:17 +00:00
|
|
|
|
2000-07-19 14:18:20 +00:00
|
|
|
p.QuadPart = PAGE_MASK(*MmGetPageEntry(vaddr));
|
1999-11-12 12:01:17 +00:00
|
|
|
|
1999-12-22 14:48:30 +00:00
|
|
|
return p;
|
1999-11-12 12:01:17 +00:00
|
|
|
}
|
2000-04-02 13:32:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* EOF */
|