[RSHELL]
[reactos.git] / ntoskrnl / mm / marea.c
index d102a2d..759be7a 100644 (file)
 
 #include <ntoskrnl.h>
 #define NDEBUG
+#include "../cache/section/newmm.h"
 #include <debug.h>
 
+#include "ARM3/miarm.h"
+
 MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
 ULONG MiStaticMemoryAreaCount;
 
-/* #define VALIDATE_MEMORY_AREAS */
-
 /* FUNCTIONS *****************************************************************/
 
 /**
@@ -158,56 +159,6 @@ static PMEMORY_AREA MmIteratePrevNode(PMEMORY_AREA Node)
    return Node;
 }
 
-#ifdef VALIDATE_MEMORY_AREAS
-static VOID MmVerifyMemoryAreas(PMMSUPPORT AddressSpace)
-{
-   PMEMORY_AREA Node;
-
-   ASSERT(AddressSpace != NULL);
-
-   /* Special case for empty tree. */
-   if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
-      return;
-
-   /* Traverse the tree from left to right. */
-   for (Node = MmIterateFirstNode(AddressSpace->WorkingSetExpansionLinks.Flink);
-        Node != NULL;
-        Node = MmIterateNextNode(Node))
-   {
-      /* FiN: The starting address can be NULL if someone explicitely asks
-       * for NULL address. */
-      ASSERT(Node->StartingAddress == NULL);
-      ASSERT(Node->EndingAddress >= Node->StartingAddress);
-   }
-}
-#else
-#define MmVerifyMemoryAreas(x)
-#endif
-
-VOID NTAPI
-MmDumpMemoryAreas(PMMSUPPORT AddressSpace)
-{
-   PMEMORY_AREA Node;
-
-   DbgPrint("MmDumpMemoryAreas()\n");
-
-   /* Special case for empty tree. */
-   if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
-      return;
-
-   /* Traverse the tree from left to right. */
-   for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
-        Node != NULL;
-        Node = MmIterateNextNode(Node))
-   {
-      DbgPrint("Start %p End %p Protect %x Flags %x\n",
-               Node->StartingAddress, Node->EndingAddress,
-               Node->Protect, Node->Flags);
-   }
-
-   DbgPrint("Finished MmDumpMemoryAreas()\n");
-}
-
 PMEMORY_AREA NTAPI
 MmLocateMemoryAreaByAddress(
    PMMSUPPORT AddressSpace,
@@ -218,8 +169,6 @@ MmLocateMemoryAreaByAddress(
    DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
            AddressSpace, Address);
 
-   MmVerifyMemoryAreas(AddressSpace);
-
    while (Node != NULL)
    {
       if (Address < Node->StartingAddress)
@@ -247,8 +196,6 @@ MmLocateMemoryAreaByRegion(
    PMEMORY_AREA Node;
    PVOID Extent = (PVOID)((ULONG_PTR)Address + Length);
 
-   MmVerifyMemoryAreas(AddressSpace);
-
    /* Special case for empty tree. */
    if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
       return NULL;
@@ -407,6 +354,17 @@ MmRebalanceTree(
    }
 }
 
+VOID
+NTAPI
+MiInsertVad(IN PMMVAD Vad,
+IN PEPROCESS Process);
+
+ULONG
+NTAPI
+MiMakeProtectionMask(
+    IN ULONG Protect
+);
+
 static VOID
 MmInsertMemoryArea(
    PMMSUPPORT AddressSpace,
@@ -415,8 +373,43 @@ MmInsertMemoryArea(
    PMEMORY_AREA Node;
    PMEMORY_AREA PreviousNode;
    ULONG Depth = 0;
+   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
 
-   MmVerifyMemoryAreas(AddressSpace);
+   /* Build a lame VAD if this is a user-space allocation */
+   if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3))
+   {
+       PMMVAD Vad;
+
+       ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE);
+       Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), TAG_MVAD);
+       ASSERT(Vad);
+       RtlZeroMemory(Vad, sizeof(MMVAD));
+       Vad->StartingVpn = PAGE_ROUND_DOWN(marea->StartingAddress) >> PAGE_SHIFT;
+       /*
+        * For some strange reason, it is perfectly valid to create a MAREA from 0x1000 to... 0x1000.
+        * In a normal OS/Memory Manager, this would be retarded, but ReactOS allows this (how it works
+        * I don't even want to know).
+        */
+        if (marea->EndingAddress != marea->StartingAddress)
+        {
+            Vad->EndingVpn = PAGE_ROUND_DOWN((ULONG_PTR)marea->EndingAddress - 1) >> PAGE_SHIFT;
+        }
+        else
+        {
+            Vad->EndingVpn = Vad->StartingVpn;
+        }
+       Vad->u.VadFlags.Spare = 1;
+       Vad->u.VadFlags.PrivateMemory = 1;
+       Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect);
+
+       /* Insert the VAD */
+       MiInsertVad(Vad, Process);
+       marea->Vad = Vad;
+   }
+   else
+   {
+       marea->Vad = NULL;
+   }
 
    if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
    {
@@ -469,75 +462,68 @@ MmFindGapBottomUp(
    ULONG_PTR Length,
    ULONG_PTR Granularity)
 {
-   PVOID LowestAddress  = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
-   PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
-                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
-   PVOID AlignedAddress;
-   PMEMORY_AREA Node;
-   PMEMORY_AREA FirstNode;
-   PMEMORY_AREA PreviousNode;
+    ULONG_PTR LowestAddress, HighestAddress, Candidate;
+    PMEMORY_AREA Root, Node;
 
-   MmVerifyMemoryAreas(AddressSpace);
-
-   DPRINT("LowestAddress: %p HighestAddress: %p\n",
-          LowestAddress, HighestAddress);
-
-   AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
-
-   /* Special case for empty tree. */
-   if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
-   {
-      if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
-      {
-         DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
-         return AlignedAddress;
-      }
-      DPRINT("MmFindGapBottomUp: 0\n");
-      return 0;
-   }
+    /* Get the margins of the address space */
+    if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
+    {
+        LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
+        HighestAddress = (ULONG_PTR)MmHighestUserAddress;
+    }
+    else
+    {
+        LowestAddress = (ULONG_PTR)MmSystemRangeStart;
+        HighestAddress = MAXULONG_PTR;
+    }
 
-   /* Go to the node with lowest address in the tree. */
-   FirstNode = Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
+    /* Start with the lowest address */
+    Candidate = LowestAddress;
 
-   /* Traverse the tree from left to right. */
-   PreviousNode = Node;
-   for (;;)
-   {
-      Node = MmIterateNextNode(Node);
-      if (Node == NULL)
-         break;
+    /* Check for overflow */
+    if ((Candidate + Length) < Candidate) return NULL;
 
-      AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
-      if (Node->StartingAddress > AlignedAddress &&
-          (ULONG_PTR)Node->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
-      {
-         DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
-         return AlignedAddress;
-      }
+    /* Get the root of the address space tree */
+    Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
 
-      PreviousNode = Node;
-   }
+    /* Go to the node with lowest address in the tree. */
+    Node = Root ? MmIterateFirstNode(Root) : NULL;
+    while (Node && ((ULONG_PTR)Node->EndingAddress < LowestAddress))
+    {
+        Node = MmIterateNextNode(Node);
+    }
 
-   /* Check if there is enough space after the last memory area. */
-   AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
-   if ((ULONG_PTR)HighestAddress > (ULONG_PTR)AlignedAddress &&
-       (ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
-   {
-      DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
-      return AlignedAddress;
-   }
+    /* Traverse the tree from low to high addresses */
+    while (Node && ((ULONG_PTR)Node->EndingAddress < HighestAddress))
+    {
+        /* Check if the memory area fits before the current node */
+        if ((ULONG_PTR)Node->StartingAddress >= (Candidate + Length))
+        {
+            DPRINT("MmFindGapBottomUp: %p\n", Candidate);
+            ASSERT(Candidate >= LowestAddress);
+            return (PVOID)Candidate;
+        }
+
+        /* Calculate next possible adress above this node */
+        Candidate = ALIGN_UP_BY((ULONG_PTR)Node->EndingAddress, Granularity);
+
+        /* Check for overflow */
+        if ((Candidate + Length) < (ULONG_PTR)Node->EndingAddress) return NULL;
+
+        /* Go to the next higher node */
+        Node = MmIterateNextNode(Node);
+    }
 
-   /* Check if there is enough space before the first memory area. */
-   AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
-   if (FirstNode->StartingAddress > AlignedAddress &&
-       (ULONG_PTR)FirstNode->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
-   {
-      DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
-      return AlignedAddress;
-   }
+    /* Check if there is enough space after the last memory area. */
+    if ((Candidate + Length) <= HighestAddress)
+    {
+        DPRINT("MmFindGapBottomUp: %p\n", Candidate);
+        ASSERT(Candidate >= LowestAddress);
+        return (PVOID)Candidate;
+    }
 
-   DPRINT("MmFindGapBottomUp: 0\n");
-   return 0;
+    DPRINT("MmFindGapBottomUp: 0\n");
+    return NULL;
 }
 
 
@@ -547,83 +533,68 @@ MmFindGapTopDown(
    ULONG_PTR Length,
    ULONG_PTR Granularity)
 {
-   PVOID LowestAddress  = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
-   PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
-                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
-   PVOID AlignedAddress;
-   PMEMORY_AREA Node;
-   PMEMORY_AREA PreviousNode;
-
-   MmVerifyMemoryAreas(AddressSpace);
-
-   DPRINT("LowestAddress: %p HighestAddress: %p\n",
-          LowestAddress, HighestAddress);
-
-   AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)HighestAddress - Length + 1, Granularity);
+    ULONG_PTR LowestAddress, HighestAddress, Candidate;
+    PMEMORY_AREA Root, Node;
 
-   /* Check for overflow. */
-   if (AlignedAddress > HighestAddress)
-      return NULL;
-
-   /* Special case for empty tree. */
-   if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
-   {
-      if (AlignedAddress >= LowestAddress)
-      {
-         DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
-         return AlignedAddress;
-      }
-      DPRINT("MmFindGapTopDown: 0\n");
-      return 0;
-   }
-
-   /* Go to the node with highest address in the tree. */
-   Node = MmIterateLastNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
-
-   /* Check if there is enough space after the last memory area. */
-   if (Node->EndingAddress <= AlignedAddress)
-   {
-      DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
-      return AlignedAddress;
-   }
-
-   /* Traverse the tree from left to right. */
-   PreviousNode = Node;
-   for (;;)
-   {
-      Node = MmIteratePrevNode(Node);
-      if (Node == NULL)
-         break;
+    /* Get the margins of the address space */
+    if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
+    {
+        LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
+        HighestAddress = (ULONG_PTR)MmHighestUserAddress;
+    }
+    else
+    {
+        LowestAddress = (ULONG_PTR)MmSystemRangeStart;
+        HighestAddress = MAXULONG_PTR;
+    }
 
-      AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
+    /* Calculate the highest candidate */
+    Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity);
 
-      /* Check for overflow. */
-      if (AlignedAddress > PreviousNode->StartingAddress)
-         return NULL;
+    /* Check for overflow. */
+    if (Candidate > HighestAddress) return NULL;
 
-      if (Node->EndingAddress <= AlignedAddress)
-      {
-         DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
-         return AlignedAddress;
-      }
+    /* Get the root of the address space tree */
+    Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
 
-      PreviousNode = Node;
-   }
+    /* Go to the node with highest address in the tree. */
+    Node = Root ? MmIterateLastNode(Root) : NULL;
+    while (Node && ((ULONG_PTR)Node->StartingAddress > HighestAddress))
+    {
+        Node = MmIteratePrevNode(Node);
+    }
 
-   AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
+    /* Traverse the tree from high to low addresses */
+    while (Node && ((ULONG_PTR)Node->StartingAddress > LowestAddress))
+    {
+        /* Check if the memory area fits after the current node */
+        if ((ULONG_PTR)Node->EndingAddress <= Candidate)
+        {
+            DPRINT("MmFindGapTopDown: %p\n", Candidate);
+            return (PVOID)Candidate;
+        }
+
+        /* Calculate next possible adress below this node */
+        Candidate = ALIGN_DOWN_BY((ULONG_PTR)Node->StartingAddress - Length,
+                                  Granularity);
+
+        /* Check for overflow. */
+        if (Candidate > (ULONG_PTR)Node->StartingAddress)
+            return NULL;
 
-   /* Check for overflow. */
-   if (AlignedAddress > PreviousNode->StartingAddress)
-      return NULL;
+        /* Go to the next lower node */
+        Node = MmIteratePrevNode(Node);
+    }
 
-   if (AlignedAddress >= LowestAddress)
-   {
-      DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
-      return AlignedAddress;
-   }
+    /* Check if the last candidate is inside the given range */
+    if (Candidate >= LowestAddress)
+    {
+        DPRINT("MmFindGapTopDown: %p\n", Candidate);
+        return (PVOID)Candidate;
+    }
 
-   DPRINT("MmFindGapTopDown: 0\n");
-   return 0;
+    DPRINT("MmFindGapTopDown: 0\n");
+    return NULL;
 }
 
 
@@ -651,8 +622,6 @@ MmFindGapAtAddress(
    PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
                           (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
 
-   MmVerifyMemoryAreas(AddressSpace);
-
    Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
 
    if (LowestAddress < MmSystemRangeStart)
@@ -702,6 +671,104 @@ MmFindGapAtAddress(
    }
 }
 
+VOID
+NTAPI
+MiRemoveNode(IN PMMADDRESS_NODE Node,
+IN PMM_AVL_TABLE Table);
+
+#if DBG
+
+static
+VOID
+MiRosCheckMemoryAreasRecursive(
+   PMEMORY_AREA Node)
+{
+    /* Check if the allocation is ok */
+    ExpCheckPoolAllocation(Node, NonPagedPool, 'ERAM');
+
+    /* Check some fields */
+    ASSERT(Node->Magic == 'erAM');
+    ASSERT(PAGE_ALIGN(Node->StartingAddress) == Node->StartingAddress);
+    ASSERT(Node->EndingAddress != NULL);
+    ASSERT(PAGE_ALIGN(Node->EndingAddress) == Node->EndingAddress);
+    ASSERT((ULONG_PTR)Node->StartingAddress < (ULONG_PTR)Node->EndingAddress);
+    ASSERT((Node->Type == 0) ||
+           (Node->Type == MEMORY_AREA_CACHE) ||
+          // (Node->Type == MEMORY_AREA_CACHE_SEGMENT) ||
+           (Node->Type == MEMORY_AREA_SECTION_VIEW) ||
+           (Node->Type == MEMORY_AREA_OWNED_BY_ARM3) ||
+           (Node->Type == (MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC)));
+
+    /* Recursively check children */
+    if (Node->LeftChild != NULL)
+        MiRosCheckMemoryAreasRecursive(Node->LeftChild);
+    if (Node->RightChild != NULL)
+        MiRosCheckMemoryAreasRecursive(Node->RightChild);
+}
+
+VOID
+NTAPI
+MiRosCheckMemoryAreas(
+   PMMSUPPORT AddressSpace)
+{
+    PMEMORY_AREA RootNode;
+    PEPROCESS AddressSpaceOwner;
+    BOOLEAN NeedReleaseLock;
+
+    NeedReleaseLock = FALSE;
+
+    /* Get the address space owner */
+    AddressSpaceOwner = CONTAINING_RECORD(AddressSpace, EPROCESS, Vm);
+
+    /* Check if we already own the address space lock */
+    if (AddressSpaceOwner->AddressCreationLock.Owner != KeGetCurrentThread())
+    {
+        /* We must own it! */
+        MmLockAddressSpace(AddressSpace);
+        NeedReleaseLock = TRUE;
+    }
+
+    /* Check all memory areas */
+    RootNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
+    MiRosCheckMemoryAreasRecursive(RootNode);
+
+    /* Release the lock, if we acquired it */
+    if (NeedReleaseLock)
+    {
+        MmUnlockAddressSpace(AddressSpace);
+    }
+}
+
+extern KGUARDED_MUTEX PspActiveProcessMutex;
+
+VOID
+NTAPI
+MiCheckAllProcessMemoryAreas(VOID)
+{
+    PEPROCESS Process;
+    PLIST_ENTRY Entry;
+
+    /* Acquire the Active Process Lock */
+    KeAcquireGuardedMutex(&PspActiveProcessMutex);
+
+    /* Loop the process list */
+    Entry = PsActiveProcessHead.Flink;
+    while (Entry != &PsActiveProcessHead)
+    {
+        /* Get the process */
+        Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
+
+        /* Check memory areas */
+        MiRosCheckMemoryAreas(&Process->Vm);
+
+        Entry = Entry->Flink;
+    }
+
+    /* Release the lock */
+    KeReleaseGuardedMutex(&PspActiveProcessMutex);
+}
+
+#endif
 
 /**
  * @name MmFreeMemoryArea
@@ -721,6 +788,12 @@ MmFindGapAtAddress(
  *
  * @remarks Lock the address space before calling this function.
  */
+VOID
+NTAPI
+MiDeletePte(IN PMMPTE PointerPte,
+            IN PVOID VirtualAddress,
+            IN PEPROCESS CurrentProcess,
+            IN PMMPTE PrototypePte);
 
 NTSTATUS NTAPI
 MmFreeMemoryArea(
@@ -732,51 +805,88 @@ MmFreeMemoryArea(
    PMEMORY_AREA *ParentReplace;
    ULONG_PTR Address;
    PVOID EndAddress;
-   PEPROCESS CurrentProcess = PsGetCurrentProcess();
-   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
-    
-   if (Process != NULL &&
-       Process != CurrentProcess)
-   {
-      KeAttachProcess(&Process->Pcb);
-   }
 
-   EndAddress = MM_ROUND_UP(MemoryArea->EndingAddress, PAGE_SIZE);
-   for (Address = (ULONG_PTR)MemoryArea->StartingAddress;
-        Address < (ULONG_PTR)EndAddress;
-        Address += PAGE_SIZE)
-   {
-      if (MemoryArea->Type == MEMORY_AREA_IO_MAPPING)
-      {
-         MmRawDeleteVirtualMapping((PVOID)Address);
-      }
-      else
-      {
-         BOOLEAN Dirty = FALSE;
-         SWAPENTRY SwapEntry = 0;
-         PFN_NUMBER Page = 0;
+   /* Make sure we own the address space lock! */
+   ASSERT(CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock.Owner == KeGetCurrentThread());
 
-         if (MmIsPageSwapEntry(Process, (PVOID)Address))
-         {
-            MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
-         }
-         else
-         {
-            MmDeleteVirtualMapping(Process, (PVOID)Address, FALSE, &Dirty, &Page);
-         }
-         if (FreePage != NULL)
-         {
-            FreePage(FreePageContext, MemoryArea, (PVOID)Address,
-                     Page, SwapEntry, (BOOLEAN)Dirty);
-         }
-      }
-   }
+    /* Check magic */
+    ASSERT(MemoryArea->Magic == 'erAM');
 
-   if (Process != NULL &&
-       Process != CurrentProcess)
+   if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
    {
-      KeDetachProcess();
-   }
+       PEPROCESS CurrentProcess = PsGetCurrentProcess();
+       PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+
+       if (Process != NULL &&
+           Process != CurrentProcess)
+       {
+          KeAttachProcess(&Process->Pcb);
+       }
+
+       EndAddress = MM_ROUND_UP(MemoryArea->EndingAddress, PAGE_SIZE);
+       for (Address = (ULONG_PTR)MemoryArea->StartingAddress;
+            Address < (ULONG_PTR)EndAddress;
+            Address += PAGE_SIZE)
+       {
+             BOOLEAN Dirty = FALSE;
+             SWAPENTRY SwapEntry = 0;
+             PFN_NUMBER Page = 0;
+
+             if (MmIsPageSwapEntry(Process, (PVOID)Address))
+             {
+                MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
+             }
+             else
+             {
+                MmDeleteVirtualMapping(Process, (PVOID)Address, FALSE, &Dirty, &Page);
+             }
+             if (FreePage != NULL)
+             {
+                FreePage(FreePageContext, MemoryArea, (PVOID)Address,
+                         Page, SwapEntry, (BOOLEAN)Dirty);
+             }
+#if (_MI_PAGING_LEVELS == 2)
+            /* Remove page table reference */
+            ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+            if ((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart))
+            {
+                ASSERT(AddressSpace != MmGetKernelAddressSpace());
+                if (MiQueryPageTableReferences((PVOID)Address) == 0)
+                {
+                    /* No PTE relies on this PDE. Release it */
+                    KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+                    PMMPDE PointerPde = MiAddressToPde(Address);
+                    ASSERT(PointerPde->u.Hard.Valid == 1);
+                    MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL);
+                    ASSERT(PointerPde->u.Hard.Valid == 0);
+                    KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+                }
+            }
+#endif
+       }
+
+       if (Process != NULL &&
+           Process != CurrentProcess)
+       {
+          KeDetachProcess();
+       }
+
+       if (MemoryArea->Vad)
+       {
+           ASSERT(MemoryArea->EndingAddress < MmSystemRangeStart);
+           ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW || MemoryArea->Type == MEMORY_AREA_CACHE);
+
+           /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */
+           ASSERT(((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare != 0);
+           if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1)
+           {
+               MiRemoveNode(MemoryArea->Vad, &Process->VadRoot);
+           }
+
+           ExFreePoolWithTag(MemoryArea->Vad, TAG_MVAD);
+           MemoryArea->Vad = NULL;
+       }
+    }
 
    /* Remove the tree item. */
    {
@@ -839,57 +949,6 @@ MmFreeMemoryArea(
    return STATUS_SUCCESS;
 }
 
-/**
- * @name MmFreeMemoryAreaByPtr
- *
- * Free an existing memory area given a pointer inside it.
- *
- * @param AddressSpace
- *        Address space to free the area from.
- * @param BaseAddress
- *        Address in the memory area we're about to free.
- * @param FreePage
- *        Callback function for each freed page.
- * @param FreePageContext
- *        Context passed to the callback function.
- *
- * @return Status
- *
- * @see MmFreeMemoryArea
- *
- * @todo Should we require the BaseAddress to be really the starting
- *       address of the memory area or is the current relaxed check
- *       (BaseAddress can point anywhere in the memory area) acceptable?
- *
- * @remarks Lock the address space before calling this function.
- */
-
-NTSTATUS NTAPI
-MmFreeMemoryAreaByPtr(
-   PMMSUPPORT AddressSpace,
-   PVOID BaseAddress,
-   PMM_FREE_PAGE_FUNC FreePage,
-   PVOID FreePageContext)
-{
-   PMEMORY_AREA MemoryArea;
-
-   DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
-          "FreePageContext %p)\n", AddressSpace, BaseAddress,
-          FreePageContext);
-
-   MmVerifyMemoryAreas(AddressSpace);
-
-   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
-                                            BaseAddress);
-   if (MemoryArea == NULL)
-   {
-      KeBugCheck(MEMORY_MANAGEMENT);
-      return(STATUS_UNSUCCESSFUL);
-   }
-
-   return MmFreeMemoryArea(AddressSpace, MemoryArea, FreePage, FreePageContext);
-}
-
 /**
  * @name MmCreateMemoryArea
  *
@@ -925,25 +984,20 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
                    PMEMORY_AREA *Result,
                    BOOLEAN FixedAddress,
                    ULONG AllocationFlags,
-                   PHYSICAL_ADDRESS BoundaryAddressMultiple)
+                   ULONG Granularity)
 {
-   PVOID EndAddress;
-   ULONG Granularity;
-   ULONG tmpLength;
+   ULONG_PTR tmpLength;
    PMEMORY_AREA MemoryArea;
 
-   DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
+   DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, "
           "*BaseAddress %p, Length %p, AllocationFlags %x, "
           "FixedAddress %x, Result %p)\n",
           Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
           FixedAddress, Result);
 
-   MmVerifyMemoryAreas(AddressSpace);
-
-   Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
    if ((*BaseAddress) == 0 && !FixedAddress)
    {
-      tmpLength = PAGE_ROUND_UP(Length);
+      tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, Granularity);
       *BaseAddress = MmFindGap(AddressSpace,
                                tmpLength,
                                Granularity,
@@ -958,6 +1012,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
    {
       tmpLength = Length + ((ULONG_PTR) *BaseAddress
                          - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
+      tmpLength = (ULONG_PTR)MM_ROUND_UP(tmpLength, Granularity);
       *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
 
       if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart)
@@ -968,15 +1023,10 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
       if (MmGetAddressSpaceOwner(AddressSpace) &&
           (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
       {
+         DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n");
          return STATUS_ACCESS_VIOLATION;
       }
 
-      if (BoundaryAddressMultiple.QuadPart != 0)
-      {
-         EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
-         ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
-      }
-
       if (MmLocateMemoryAreaByRegion(AddressSpace,
                                      *BaseAddress,
                                      tmpLength) != NULL)
@@ -985,7 +1035,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
          return STATUS_CONFLICTING_ADDRESSES;
       }
    }
-    
+
     //
     // Is this a static memory area?
     //
@@ -1008,7 +1058,11 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
                                            TAG_MAREA);
     }
 
-    if (!MemoryArea) return STATUS_NO_MEMORY;
+   if (!MemoryArea)
+   {
+      DPRINT1("Not enough memory.\n");
+      return STATUS_NO_MEMORY;
+   }
 
    RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
    MemoryArea->Type = Type;
@@ -1017,7 +1071,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
    MemoryArea->Protect = Protect;
    MemoryArea->Flags = AllocationFlags;
    //MemoryArea->LockCount = 0;
-   MemoryArea->PageOpCount = 0;
+   MemoryArea->Magic = 'erAM';
    MemoryArea->DeleteInProgress = FALSE;
 
    MmInsertMemoryArea(AddressSpace, MemoryArea);
@@ -1030,13 +1084,15 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
 
 VOID NTAPI
 MmMapMemoryArea(PVOID BaseAddress,
-                ULONG Length,
+                SIZE_T Length,
                 ULONG Consumer,
                 ULONG Protection)
 {
    ULONG i;
    NTSTATUS Status;
 
+   ASSERT(((ULONG_PTR)BaseAddress % PAGE_SIZE) == 0);
+
    for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
    {
       PFN_NUMBER Page;
@@ -1060,36 +1116,98 @@ MmMapMemoryArea(PVOID BaseAddress,
    }
 }
 
+VOID
+NTAPI
+MmDeleteProcessAddressSpace2(IN PEPROCESS Process);
 
-VOID NTAPI
-MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process,
-                                 PMMSUPPORT AddressSpace,
-                                 PVOID BaseAddress)
+NTSTATUS
+NTAPI
+MmDeleteProcessAddressSpace(PEPROCESS Process)
 {
+   PVOID Address;
    PMEMORY_AREA MemoryArea;
-   PLIST_ENTRY Entry;
-   PMM_REGION Region;
-   BOOLEAN Reserved;
 
-   MmVerifyMemoryAreas(AddressSpace);
+   DPRINT("MmDeleteProcessAddressSpace(Process %p (%s))\n", Process,
+          Process->ImageFileName);
 
-   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
-   if (MemoryArea != NULL)
-   {
-      Entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
-      Reserved = TRUE;
-      while (Reserved && Entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
-      {
-         Region = CONTAINING_RECORD(Entry, MM_REGION, RegionListEntry);
-         Reserved = (MEM_RESERVE == Region->Type);
-         Entry = Entry->Flink;
-      }
+#ifndef _M_AMD64
+   RemoveEntryList(&Process->MmProcessLinks);
+#endif
+   MmLockAddressSpace(&Process->Vm);
 
-      if (Reserved)
+   while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
+   {
+      switch (MemoryArea->Type)
       {
-         MmFreeVirtualMemory(Process, MemoryArea);
+         case MEMORY_AREA_SECTION_VIEW:
+             Address = (PVOID)MemoryArea->StartingAddress;
+             MmUnlockAddressSpace(&Process->Vm);
+             MmUnmapViewOfSection(Process, Address);
+             MmLockAddressSpace(&Process->Vm);
+             break;
+
+         case MEMORY_AREA_CACHE:
+             Address = (PVOID)MemoryArea->StartingAddress;
+             MmUnlockAddressSpace(&Process->Vm);
+             MmUnmapViewOfCacheSegment(&Process->Vm, Address);
+             MmLockAddressSpace(&Process->Vm);
+             break;
+
+         case MEMORY_AREA_OWNED_BY_ARM3:
+             MmFreeMemoryArea(&Process->Vm,
+                              MemoryArea,
+                              NULL,
+                              NULL);
+             break;
+
+         default:
+            KeBugCheck(MEMORY_MANAGEMENT);
       }
    }
+
+#if (_MI_PAGING_LEVELS == 2)
+    {
+        KIRQL OldIrql;
+        PMMPDE pointerPde;
+        /* Attach to Process */
+        KeAttachProcess(&Process->Pcb);
+
+        /* Acquire PFN lock */
+        OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+        for (Address = MI_LOWEST_VAD_ADDRESS;
+             Address < MM_HIGHEST_VAD_ADDRESS;
+             Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT)))
+        {
+            /* At this point all references should be dead */
+            if (MiQueryPageTableReferences(Address) != 0)
+            {
+                DPRINT1("Process %p, Address %p, UsedPageTableEntries %lu\n",
+                        Process,
+                        Address,
+                        MiQueryPageTableReferences(Address));
+                ASSERT(MiQueryPageTableReferences(Address) == 0);
+            }
+            pointerPde = MiAddressToPde(Address);
+            /* Unlike in ARM3, we don't necesarrily free the PDE page as soon as reference reaches 0,
+             * so we must clean up a bit when process closes */
+            if (pointerPde->u.Hard.Valid)
+                MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL);
+            ASSERT(pointerPde->u.Hard.Valid == 0);
+        }
+        /* Release lock */
+        KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+        /* Detach */
+        KeDetachProcess();
+    }
+#endif
+
+   MmUnlockAddressSpace(&Process->Vm);
+
+   DPRINT("Finished MmReleaseMmInfo()\n");
+   MmDeleteProcessAddressSpace2(Process);
+   return(STATUS_SUCCESS);
 }
 
 /* EOF */