[ros-diffs] [arty] 25375: Start of an implementation of page.c

arty at svn.reactos.org arty at svn.reactos.org
Mon Jan 8 10:28:40 CET 2007


Author: arty
Date: Mon Jan  8 12:28:39 2007
New Revision: 25375

URL: http://svn.reactos.org/svn/reactos?rev=25375&view=rev
Log:
Start of an implementation of page.c

Added:
    branches/powerpc/reactos/ntoskrnl/mm/powerpc/
    branches/powerpc/reactos/ntoskrnl/mm/powerpc/page.c

Added: branches/powerpc/reactos/ntoskrnl/mm/powerpc/page.c
URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/ntoskrnl/mm/powerpc/page.c?rev=25375&view=auto
==============================================================================
--- branches/powerpc/reactos/ntoskrnl/mm/powerpc/page.c (added)
+++ branches/powerpc/reactos/ntoskrnl/mm/powerpc/page.c Mon Jan  8 12:28:39 2007
@@ -1,0 +1,1325 @@
+/* $Id: page.c 23907 2006-09-04 05:52:23Z arty $
+ *
+ * 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 at cwcom.net)
+ * Revised for PowerPC by arty
+ */
+
+/* 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 PAGETABLE_MAP		(0xc0000000)
+#define PAGEDIRECTORY_MAP	(0xc0000000 + (PAGETABLE_MAP / (1024)))
+
+#define PA_PRESENT (1ll<<63)
+#define PA_USER (1ll<<62)
+#define PA_ACCESSED 0x200
+#define PA_DIRTY 0x100
+#define PA_WT 0x20
+#define PA_CD 0x10
+#define PA_READWRITE 3
+
+#define HYPERSPACE		(0xc0400000)
+#define IS_HYPERSPACE(v)	(((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
+
+#define PP_FROM_PROTECT(X) \
+  ((X & (PAGE_NOACCESS | PAGE_GUARD)) ? 0 : \
+   (X & PAGE_IS_WRITABLE) ? 2 : \
+   (X & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE)) ? 3 : 0)
+
+ULONG MmGlobalKernelPageDirectory[1024];
+
+#define PTE_TO_PFN(X)  ((X) >> PAGE_SHIFT)
+#define 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
+
+/* FUNCTIONS ***************************************************************/
+
+BOOLEAN MmUnmapPageTable(PULONG Pt);
+
+VOID
+STDCALL
+MiFlushTlbIpiRoutine(PVOID Address)
+{
+   if (Address == (PVOID)0xffffffff)
+   {
+      KeFlushCurrentTb();
+   }
+   else if (Address == (PVOID)0xfffffffe)
+   {
+      FLUSH_TLB;
+   }
+   else
+   {
+      FLUSH_TLB_ONE(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)
+   {
+      FLUSH_TLB_ONE(Address);
+   }
+#endif
+}
+
+
+
+PULONG
+MmGetPageDirectory(VOID)
+{
+   unsigned int page_dir=0;
+   return((PULONG)page_dir);
+}
+
+static ULONGLONG
+ProtectToPTE(ULONG flProtect)
+{
+    return PP_FROM_PROTECT(flProtect);
+}
+
+#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)
+
+NTSTATUS
+STDCALL
+MmCopyMmInfo(PEPROCESS Src,
+             PEPROCESS Dest,
+             PPHYSICAL_ADDRESS DirectoryTableBase)
+{
+    NTSTATUS Status;
+    ULONG i, j;
+    PFN_TYPE Pfn[7];
+    ULONG Count;
+    PULONG PageDirectory;
+    
+    DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
+    
+    Count = 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;
+	}
+    }
+    
+    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);
+   }
+
+   *(ADDR_TO_PDE(Address)) = 0;
+   MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address));
+
+   if (Address >= MmSystemRangeStart)
+   {
+      KEBUGCHECK(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);
+   }
+
+   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);
+   }
+   else
+   {
+      MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
+   }
+   if (Process != NULL && Process != CurrentProcess)
+   {
+      KeDetachProcess();
+   }
+}
+
+static PULONG
+MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
+{
+   ULONG PdeOffset = ADDR_TO_PDE_OFFSET(Address);
+   NTSTATUS Status;
+   PFN_TYPE Pfn;
+   ULONG Entry;
+   PULONG Pt, PageDir;
+
+   if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
+   {
+      PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
+      if (PageDir == NULL)
+      {
+         KEBUGCHECK(0);
+      }
+      if (0 == InterlockedCompareExchangeUL(&PageDir[PdeOffset], 0, 0))
+      {
+         if (Create == FALSE)
+	 {
+	    MmDeleteHyperspaceMapping(PageDir);
+	    return NULL;
+	 }
+         Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
+	 if (!NT_SUCCESS(Status) || Pfn == 0)
+	 {
+	    KEBUGCHECK(0);
+	 }
+         Entry = InterlockedCompareExchangeUL(&PageDir[PdeOffset], PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
+	 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)
+      {
+         KEBUGCHECK(0);
+      }
+      return Pt + ADDR_TO_PTE_OFFSET(Address);
+   }
+   PageDir = ADDR_TO_PDE(Address);
+   if (0 == InterlockedCompareExchangeUL(PageDir, 0, 0))
+   {
+      if (Address >= MmSystemRangeStart)
+      {
+         if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], 0, 0))
+	 {
+	    if (Create == FALSE)
+	    {
+               return NULL;
+	    }
+            Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
+	    if (!NT_SUCCESS(Status) || Pfn == 0)
+	    {
+	       KEBUGCHECK(0);
+	    }
+	    Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
+	    if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], Entry, 0))
+	    {
+	       MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
+	    }
+	 }
+         (void)InterlockedExchangeUL(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
+      }
+      else
+      {
+	 if (Create == FALSE)
+	 {
+            return NULL;
+	 }
+         Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
+	 if (!NT_SUCCESS(Status) || Pfn == 0)
+	 {
+	    KEBUGCHECK(0);
+	 }
+         Entry = InterlockedCompareExchangeUL(PageDir, PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
+	 if (Entry != 0)
+	 {
+	    MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
+	 }
+      }
+   }
+   return (PULONG)ADDR_TO_PTE(Address);
+}
+
+BOOLEAN MmUnmapPageTable(PULONG Pt)
+{
+    if (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024)
+    {
+	return TRUE;
+    }
+
+    if (Pt)
+    {
+	MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt));
+    }
+    return FALSE;
+}
+
+static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
+{
+   ULONG Pte;
+   PULONG Pt;
+
+   Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+   if (Pt)
+   {
+      Pte = *Pt;
+      MmUnmapPageTable(Pt);
+      return Pte;
+   }
+   return 0;
+}
+
+PFN_TYPE
+NTAPI
+MmGetPfnForProcess(PEPROCESS Process,
+                   PVOID Address)
+{
+    ULONG Entry;
+    Entry = MmGetPageEntryForProcess(Process, Address);
+    return(PTE_TO_PFN(Entry));
+}
+
+VOID
+NTAPI
+MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_TYPE Page)
+/*
+ * FUNCTION: Delete a virtual mapping
+ */
+{
+    BOOLEAN WasValid;
+    ULONG Pte;
+    PULONG Pt;
+    
+    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    /*
+     * Atomically disable the present bit and get the old value.
+     */
+    do
+    {
+        Pte = *Pt;
+    } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_PRESENT, Pte));
+    
+    MiFlushTlb(Pt, Address);
+    WasValid = (PAGE_MASK(Pte) != 0);
+    if (!WasValid)
+    {
+	KEBUGCHECK(0);
+    }
+    
+    /*
+     * Return some information to the caller
+     */
+    if (WasDirty != NULL)
+    {
+	*WasDirty = Pte & PA_DIRTY;
+    }
+    if (Page != NULL)
+    {
+	*Page = PTE_TO_PFN(Pte);
+    }
+}
+
+VOID
+NTAPI
+MmRawDeleteVirtualMapping(PVOID Address)
+{
+    PULONG Pt;
+    
+    Pt = MmGetPageTableForProcess(NULL, Address, FALSE);
+    if (Pt && *Pt)
+    {
+	/*
+	 * Set the entry to zero
+	 */
+	(void)InterlockedExchangeUL(Pt, 0);
+	MiFlushTlb(Pt, Address);
+    }
+}
+
+VOID
+NTAPI
+MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
+                       BOOLEAN* WasDirty, PPFN_TYPE Page)
+/*
+ * FUNCTION: Delete a virtual mapping
+ */
+{
+    BOOLEAN WasValid = FALSE;
+    PFN_TYPE Pfn;
+    
+    DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
+	   Process, Address, FreePage, WasDirty, Page);
+    
+    ULONG Pte;
+    PULONG Pt;
+    
+    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+    
+    if (Pt == NULL)
+    {
+	if (WasDirty != NULL)
+	{
+            *WasDirty = FALSE;
+	}
+	if (Page != NULL)
+	{
+            *Page = 0;
+	}
+	return;
+    }
+    
+    /*
+     * Atomically set the entry to zero and get the old value.
+     */
+    Pte = InterlockedExchangeUL(Pt, 0);
+    
+    MiFlushTlb(Pt, Address);
+    
+    WasValid = (PAGE_MASK(Pte) != 0);
+    if (WasValid)
+    {
+	Pfn = PTE_TO_PFN(Pte);
+	MmMarkPageUnmapped(Pfn);
+    }
+    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;
+    }
+    /*
+     * Decrement the reference count for this page table.
+     */
+    if (Process != NULL && WasValid &&
+	((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
+	Address < MmSystemRangeStart)
+    {
+	PUSHORT Ptrc;
+	ULONG Idx;
+	
+	Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
+	Idx = ADDR_TO_PAGE_TABLE(Address);
+	
+	Ptrc[Idx]--;
+	if (Ptrc[Idx] == 0)
+	{
+	    MmFreePageTable(Process, Address);
+	}
+    }
+}
+
+VOID
+NTAPI
+MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
+                        SWAPENTRY* SwapEntry)
+/*
+ * FUNCTION: Delete a virtual mapping
+ */
+{
+    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.
+     */
+    Pte = InterlockedExchangeUL(Pt, 0);
+    
+    MiFlushTlb(Pt, Address);
+    
+    /*
+     * Decrement the reference count for this page table.
+     */
+    if (Process != NULL && Pte &&
+	((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
+	Address < MmSystemRangeStart)
+    {
+	PUSHORT Ptrc;
+	
+	Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
+	
+	Ptrc[ADDR_TO_PAGE_TABLE(Address)]--;
+	if (Ptrc[ADDR_TO_PAGE_TABLE(Address)] == 0)
+	{
+            MmFreePageTable(Process, Address);
+	}
+    }
+        
+    /*
+     * Return some information to the caller
+     */
+    *SwapEntry = Pte >> 1;
+}
+
+BOOLEAN
+Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
+{
+    PULONG Pt, Pde;
+    Pde = ADDR_TO_PDE(PAddress);
+    if (*Pde == 0)
+    {
+	Pt = MmGetPageTableForProcess(NULL, PAddress, FALSE);
+#if 0
+	/* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
+	FLASH_TLB_ONE(PAddress);
+#endif
+	if (Pt != NULL)
+	{
+            return TRUE;
+	}
+    }
+    return(FALSE);
+}
+
+BOOLEAN
+NTAPI
+MmIsDirtyPage(PEPROCESS Process, PVOID Address)
+{
+    return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
+}
+
+BOOLEAN
+NTAPI
+MmIsAccessedAndResetAccessPage(PEPROCESS Process, PVOID Address)
+{
+    PULONG Pt;
+    ULONG Pte;
+    
+    if (Address < MmSystemRangeStart && Process == NULL)
+    {
+	DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
+	KEBUGCHECK(0);
+    }
+
+    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    
+    do
+    {
+	Pte = *Pt;
+    } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_ACCESSED, Pte));
+    
+    if (Pte & PA_ACCESSED)
+    {
+	MiFlushTlb(Pt, Address);
+	return TRUE;
+    }
+    else
+    {
+	MmUnmapPageTable(Pt);
+	return FALSE;
+    }
+}
+
+VOID
+NTAPI
+MmSetCleanPage(PEPROCESS Process, PVOID Address)
+{
+    PULONG Pt;
+    ULONG Pte;
+    
+    if (Address < MmSystemRangeStart && Process == NULL)
+    {
+	DPRINT1("MmSetCleanPage is called for user space without a process.\n");
+	KEBUGCHECK(0);
+    }
+    
+    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+    
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    
+    do
+    {
+	Pte = *Pt;
+    } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_DIRTY, Pte));
+    
+    if (Pte & PA_DIRTY)
+    {
+	MiFlushTlb(Pt, Address);
+    }
+    else
+    {
+	MmUnmapPageTable(Pt);
+    }
+}
+
+VOID
+NTAPI
+MmSetDirtyPage(PEPROCESS Process, PVOID Address)
+{
+    PULONG Pt;
+    ULONG Pte;
+    
+    if (Address < MmSystemRangeStart && Process == NULL)
+    {
+	DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
+	KEBUGCHECK(0);
+    }
+    
+    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    
+    do
+    {
+	Pte = *Pt;
+    } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_DIRTY, Pte));
+    if (!(Pte & PA_DIRTY))
+    {
+	MiFlushTlb(Pt, Address);
+    }
+    else
+    {
+	MmUnmapPageTable(Pt);
+    }
+}
+
+VOID
+NTAPI
+MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
+{
+    PULONG Pt;
+    ULONG Pte;
+    
+    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    
+    do
+    {
+	Pte = *Pt;
+    } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_PRESENT, Pte));
+    if (!(Pte & PA_PRESENT))
+    {
+	MiFlushTlb(Pt, Address);
+    }
+    else
+    {
+	MmUnmapPageTable(Pt);
+    }
+}
+
+BOOLEAN
+NTAPI
+MmIsPagePresent(PEPROCESS Process, PVOID Address)
+{
+    return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT ? TRUE : FALSE;
+}
+
+BOOLEAN
+NTAPI
+MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
+{
+    ULONG Entry;
+    Entry = MmGetPageEntryForProcess(Process, Address);
+    return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
+}
+
+NTSTATUS
+NTAPI
+MmCreateVirtualMappingForKernel(PVOID Address,
+                                ULONG flProtect,
+                                PPFN_TYPE Pages,
+				ULONG PageCount)
+{
+    ULONG Attributes;
+    ULONG i;
+    PVOID Addr;
+    ULONG PdeOffset, oldPdeOffset;
+    BOOLEAN NoExecute = FALSE;
+    PULONG Pt;
+    ULONG Pte;
+    
+    DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
+           Address, flProtect, Pages, PageCount);
+    
+    if (Address < MmSystemRangeStart)
+    {
+	DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
+	KEBUGCHECK(0);
+    }
+    
+    Attributes = ProtectToPTE(flProtect);
+    if (Attributes & 0x80000000)
+    {
+	NoExecute = TRUE;
+    }
+    Attributes &= 0xfff;
+    
+    Addr = Address;
+    
+    oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr);
+    Pt = MmGetPageTableForProcess(NULL, Addr, TRUE);
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    Pt--;
+    
+    for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
+    {
+	if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
+	{
+            DPRINT1("Setting physical address but not allowing access at address "
+                    "0x%.8X with attributes %x/%x.\n",
+                    Addr, Attributes, flProtect);
+            KEBUGCHECK(0);
+	}
+	
+	PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
+	if (oldPdeOffset != PdeOffset)
+	{
+            Pt = MmGetPageTableForProcess(NULL, Addr, TRUE);
+	    if (Pt == NULL)
+	    {
+		KEBUGCHECK(0);
+	    }
+	}
+	else
+	{
+            Pt++;
+	}
+	oldPdeOffset = PdeOffset;
+	
+	Pte = *Pt;
+	if (Pte != 0)
+	{
+            KEBUGCHECK(0);
+	}
+	(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
+    }
+
+    return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+NTAPI
+MmCreatePageFileMapping(PEPROCESS Process,
+                        PVOID Address,
+                        SWAPENTRY SwapEntry)
+{
+    PULONG Pt;
+    ULONG Pte;
+    
+    if (Process == NULL && Address < MmSystemRangeStart)
+    {
+	DPRINT1("No process\n");
+	KEBUGCHECK(0);
+    }
+    if (Process != NULL && Address >= MmSystemRangeStart)
+    {
+	DPRINT1("Setting kernel address with process context\n");
+	KEBUGCHECK(0);
+    }
+    if (SwapEntry & (1 << 31))
+    {
+	KEBUGCHECK(0);
+    }
+    
+    Pt = MmGetPageTableForProcess(Process, Address, TRUE);
+    if (Pt == NULL)
+    {
+	KEBUGCHECK(0);
+    }
+    Pte = *Pt;
+    if (PAGE_MASK((Pte)) != 0)
+    {
+	MmMarkPageUnmapped(PTE_TO_PFN((Pte)));
+    }
+    (void)InterlockedExchangeUL(Pt, SwapEntry << 1);
+    if (Pte != 0)
+    {
+	MiFlushTlb(Pt, Address);
+    }
+    else
+    {
+	MmUnmapPageTable(Pt);
+    }
+
+    if (Process != NULL &&
+	((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
+	Address < MmSystemRangeStart)
+    {
+	PUSHORT Ptrc;
+	ULONG Idx;
+	
+	Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
+	Idx = ADDR_TO_PAGE_TABLE(Address);
+	Ptrc[Idx]++;
+    }
+    return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+NTAPI
+MmCreateVirtualMappingUnsafe(PEPROCESS Process,
+                             PVOID Address,
+                             ULONG flProtect,
+                             PPFN_TYPE Pages,
+                             ULONG PageCount)
+{
+    ULONG Attributes;
+    PVOID Addr;
+    ULONG i;
+    ULONG oldPdeOffset, PdeOffset;
+    BOOLEAN NoExecute = FALSE;
+    PULONG Pt = NULL;
+    ULONG Pte;
+    
+    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");
+	    KEBUGCHECK(0);
+	}
+	if (PageCount > 0x10000 ||
+	    (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
+	{
+	    DPRINT1("Page count to large\n");
+	    KEBUGCHECK(0);
+	}
+    }
+    else
+    {
+	if (Address >= MmSystemRangeStart)
+	{
+	    DPRINT1("Setting kernel address with process context\n");
+	    KEBUGCHECK(0);
+	}
+	if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
+	    (ULONG_PTR) Address / PAGE_SIZE + PageCount >
+	    (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
+	{
+	    DPRINT1("Page Count to large\n");
+	    KEBUGCHECK(0);
+	}
+    }
+    
+    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)
+	{
+            DPRINT1("Setting physical address but not allowing access at address "
+                    "0x%.8X with attributes %x/%x.\n",
+                    Addr, Attributes, flProtect);
+            KEBUGCHECK(0);
+	}
+	PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
+	if (oldPdeOffset != PdeOffset)
+	{
+            MmUnmapPageTable(Pt);
+	    Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
+	    if (Pt == NULL)
+	    {
+		KEBUGCHECK(0);
+	    }
+	}
+	else
+	{
+            Pt++;
+	}
+	oldPdeOffset = PdeOffset;
+	
+	Pte = *Pt;
+	MmMarkPageMapped(Pages[i]);
+	if (PAGE_MASK((Pte)) != 0 && !((Pte) & PA_PRESENT))
+	{
+            KEBUGCHECK(0);
+	}
+	if (PAGE_MASK((Pte)) != 0)
+	{
+            MmMarkPageUnmapped(PTE_TO_PFN((Pte)));
+	}
+	(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
+	if (Address < MmSystemRangeStart &&
+	    ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
+	    Attributes & PA_PRESENT)
+	{
+            PUSHORT Ptrc;
+	    
+            Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
+	    
+            Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
+	}
+	if (Pte != 0)
+	{
+            if (Address > MmSystemRangeStart ||
+                (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024))
+            {
+		MiFlushTlb(Pt, Address);
+            }
+	}
+    }
+    if (Addr > Address)
+    {
+	MmUnmapPageTable(Pt);
+    }
+    return(STATUS_SUCCESS);
+}
+
+NTSTATUS
+NTAPI
+MmCreateVirtualMapping(PEPROCESS Process,
+                       PVOID Address,
+                       ULONG flProtect,
+                       PPFN_TYPE Pages,
+                       ULONG PageCount)
+{
+   ULONG i;
+
+   for (i = 0; i < PageCount; i++)
+   {
+      if (!MmIsUsablePage(Pages[i]))
+      {
+         DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages[i]));
+         KEBUGCHECK(0);
+      }
+   }
+
+   return(MmCreateVirtualMappingUnsafe(Process,
+                                       Address,
+                                       flProtect,
+                                       Pages,
+                                       PageCount));
+}
+
+ULONG
+NTAPI
+MmGetPageProtect(PEPROCESS Process, PVOID Address)
+{
+    ULONG Entry;
+    ULONG Protect;
+    
+    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);
+}
+
+VOID
+NTAPI
+MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
+{
+   ULONG Attributes = 0;
+
+   DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
+          Process, Address, flProtect);
+
+   Attributes = ProtectToPTE(flProtect);
+
+#if 0
+   Pt = MmGetPageTableForProcess(Process, Address, FALSE);
+   if (Pt == NULL)
+   {
+       KEBUGCHECK(0);
+   }
+   InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
+   MiFlushTlb(Pt, Address);
+#endif
+}
+
+/*
+ * @implemented
+ */
+PHYSICAL_ADDRESS STDCALL
+MmGetPhysicalAddress(PVOID vaddr)
+/*
+ * FUNCTION: Returns the physical address corresponding to a virtual address
+ */
+{
+    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;
+}
+
+PVOID
+NTAPI
+MmCreateHyperspaceMapping(PFN_TYPE Page)
+{
+    PVOID Address;
+    ULONG i;
+    ULONG Entry;
+    PULONG Pte;
+    Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE;
+    Pte = ADDR_TO_PTE(HYPERSPACE) + Page % 1024;
+    if (Page & 1024)
+    {
+	for (i = Page % 1024; i < 1024; i++, Pte++)
+	{
+            if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
+            {
+		break;
+            }
+	}
+	if (i >= 1024)
+	{
+            Pte = ADDR_TO_PTE(HYPERSPACE);
+            for (i = 0; i < Page % 1024; i++, Pte++)
+            {
+		if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
+		{
+		    break;
+		}
+            }
+            if (i >= Page % 1024)
+            {
+		KEBUGCHECK(0);
+            }
+	}
+    }
+    else
+    {
+	for (i = Page % 1024; (LONG)i >= 0; i--, Pte--)
+	{
+            if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
+            {
+		break;
+            }
+	}
+	if ((LONG)i < 0)
+	{
+            Pte = ADDR_TO_PTE(HYPERSPACE) + 1023;
+            for (i = 1023; i > Page % 1024; i--, Pte--)
+            {
+		if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
+		{
+		    break;
+		}
+            }
+            if (i <= Page % 1024)
+            {
+		KEBUGCHECK(0);
+            }
+	}
+    }
+    Address = (PVOID)((ULONG_PTR)HYPERSPACE + i * PAGE_SIZE);
+    FLUSH_TLB_ONE(Address);
+    return Address;
+}
+
+PFN_TYPE
+NTAPI
+MmChangeHyperspaceMapping(PVOID Address, PFN_TYPE NewPage)
+{
+    PFN_TYPE Pfn;
+    ASSERT (IS_HYPERSPACE(Address));
+    ULONG Entry;
+    Entry = InterlockedExchange((PLONG)ADDR_TO_PTE(Address), PFN_TO_PTE(NewPage) | PA_PRESENT | PA_READWRITE);
+    Pfn = PTE_TO_PFN(Entry);
+    FLUSH_TLB_ONE(Address);
+    return Pfn;
+}
+
+PFN_TYPE
+NTAPI
+MmDeleteHyperspaceMapping(PVOID Address)
+{
+   PFN_TYPE Pfn;
+   ASSERT (IS_HYPERSPACE(Address));
+   ULONG Entry;
+   Entry = InterlockedExchange((PLONG)ADDR_TO_PTE(Address), 0);
+   Pfn = PTE_TO_PFN(Entry);
+   FLUSH_TLB_ONE(Address);
+   return Pfn;
+}
+
+VOID
+NTAPI
+MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size)
+{
+    ULONG StartOffset, EndOffset, Offset;
+    PULONG Pde;
+    
+    if (Address < MmSystemRangeStart)
+    {
+	KEBUGCHECK(0);
+    }
+    StartOffset = ADDR_TO_PDE_OFFSET(Address);
+    EndOffset = ADDR_TO_PDE_OFFSET((PVOID)((ULONG_PTR)Address + Size));
+    
+    if (Process != NULL && Process != PsGetCurrentProcess())
+    {
+	Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart));
+    }
+    else
+    {
+	Pde = (PULONG)PAGEDIRECTORY_MAP;
+    }
+    for (Offset = StartOffset; Offset <= EndOffset; Offset++)
+    {
+	if (Offset != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP))
+	{
+            (void)InterlockedCompareExchangeUL(&Pde[Offset], MmGlobalKernelPageDirectory[Offset], 0);
+	}
+    }
+    if (Pde != (PULONG)PAGEDIRECTORY_MAP)
+    {
+	MmDeleteHyperspaceMapping(Pde);
+    }
+}
+
+VOID
+INIT_FUNCTION
+NTAPI
+MmInitGlobalKernelPageDirectory(VOID)
+{
+    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])
+	{
+            MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
+	}
+    }
+}
+
+ULONG
+NTAPI
+MiGetUserPageDirectoryCount(VOID)
+{
+   return ADDR_TO_PDE_OFFSET(MmSystemRangeStart);
+}
+
+VOID
+INIT_FUNCTION
+NTAPI
+MiInitPageDirectoryMap(VOID)
+{
+   MEMORY_AREA* kernel_map_desc = NULL;
+   MEMORY_AREA* hyperspace_desc = NULL;
+   PHYSICAL_ADDRESS BoundaryAddressMultiple;
+   PVOID BaseAddress;
+   NTSTATUS Status;
+
+   DPRINT("MiInitPageDirectoryMap()\n");
+
+   BoundaryAddressMultiple.QuadPart = 0;
+   BaseAddress = (PVOID)PAGETABLE_MAP;
+   Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
+                               MEMORY_AREA_SYSTEM,
+                               &BaseAddress,
+			       0x400000,
+                               PAGE_READWRITE,
+                               &kernel_map_desc,
+                               TRUE,
+                               0,
+                               BoundaryAddressMultiple);
+   if (!NT_SUCCESS(Status))
+   {
+      KEBUGCHECK(0);
+   }
+   BaseAddress = (PVOID)HYPERSPACE;
+   Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
+                               MEMORY_AREA_SYSTEM,
+                               &BaseAddress,
+		               0x400000,
+                               PAGE_READWRITE,
+                               &hyperspace_desc,
+                               TRUE,
+                               0,
+                               BoundaryAddressMultiple);
+   if (!NT_SUCCESS(Status))
+   {
+      KEBUGCHECK(0);
+   }
+}
+
+/* EOF */




More information about the Ros-diffs mailing list