[NTOS:MM]
[reactos.git] / reactos / ntoskrnl / mm / marea.c
index 488184a..c52cad8 100644 (file)
 MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
 ULONG MiStaticMemoryAreaCount;
 
-/* FUNCTIONS *****************************************************************/
+MM_AVL_TABLE MiRosKernelVadRoot;
+BOOLEAN MiRosKernelVadRootInitialized;
 
-/**
- * @name MmIterateFirstNode
- *
- * @param Node
- *        Head node of the MEMORY_AREA tree.
- *
- * @return The leftmost MEMORY_AREA node (ie. the one with lowest
- *         address)
- */
+/* FUNCTIONS *****************************************************************/
 
-static PMEMORY_AREA MmIterateFirstNode(PMEMORY_AREA Node)
+PMEMORY_AREA NTAPI
+MmLocateMemoryAreaByAddress(
+    PMMSUPPORT AddressSpace,
+    PVOID Address_)
 {
-    while (Node->LeftChild != NULL)
-        Node = Node->LeftChild;
-
-    return Node;
-}
+    ULONG_PTR StartVpn = (ULONG_PTR)Address_ / PAGE_SIZE;
+    PEPROCESS Process;
+    PMM_AVL_TABLE Table;
+    PMMADDRESS_NODE Node;
+    PMEMORY_AREA MemoryArea;
+    TABLE_SEARCH_RESULT Result;
+    PMMVAD_LONG Vad;
 
-/**
- * @name MmIterateNextNode
- *
- * @param Node
- *        Current node in the tree.
- *
- * @return Next node in the tree (sorted by address).
- */
+    Process = MmGetAddressSpaceOwner(AddressSpace);
+    Table = (Process != NULL) ? &Process->VadRoot : &MiRosKernelVadRoot;
 
-static PMEMORY_AREA MmIterateNextNode(PMEMORY_AREA Node)
-{
-    if (Node->RightChild != NULL)
-    {
-        Node = Node->RightChild;
-        while (Node->LeftChild != NULL)
-            Node = Node->LeftChild;
-    }
-    else
+    Result = MiCheckForConflictingNode(StartVpn, StartVpn, Table, &Node);
+    if (Result != TableFoundNode)
     {
-        PMEMORY_AREA TempNode = NULL;
-
-        do
-        {
-            /* Check if we're at the end of tree. */
-            if (Node->Parent == NULL)
-                return NULL;
-
-            TempNode = Node;
-            Node = Node->Parent;
-        }
-        while (TempNode == Node->RightChild);
+        return NULL;
     }
-    return Node;
-}
-
-/**
- * @name MmIterateLastNode
- *
- * @param Node
- *        Head node of the MEMORY_AREA tree.
- *
- * @return The rightmost MEMORY_AREA node (ie. the one with highest
- *         address)
- */
-
-static PMEMORY_AREA MmIterateLastNode(PMEMORY_AREA Node)
-{
-    while (Node->RightChild != NULL)
-        Node = Node->RightChild;
-
-    return Node;
-}
-
-/**
- * @name MmIteratePreviousNode
- *
- * @param Node
- *        Current node in the tree.
- *
- * @return Previous node in the tree (sorted by address).
- */
 
-static PMEMORY_AREA MmIteratePrevNode(PMEMORY_AREA Node)
-{
-    if (Node->LeftChild != NULL)
-    {
-        Node = Node->LeftChild;
-        while (Node->RightChild != NULL)
-            Node = Node->RightChild;
-    }
-    else
+    Vad = (PMMVAD_LONG)Node;
+    if (Vad->u.VadFlags.Spare == 0)
     {
-        PMEMORY_AREA TempNode = NULL;
-
-        do
+        /* Check if this is VM VAD */
+        if (Vad->ControlArea == NULL)
         {
-            /* Check if we're at the end of tree. */
-            if (Node->Parent == NULL)
-                return NULL;
-
-            TempNode = Node;
-            Node = Node->Parent;
+            /* We store the reactos MEMORY_AREA here */
+            MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte;
         }
-        while (TempNode == Node->LeftChild);
-    }
-    return Node;
-}
-
-PMEMORY_AREA NTAPI
-MmLocateMemoryAreaByAddress(
-    PMMSUPPORT AddressSpace,
-    PVOID Address_)
-{
-    PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
-    ULONG_PTR Address = (ULONG_PTR)Address_;
-
-    DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
-           AddressSpace, Address);
-
-    while (Node != NULL)
-    {
-        if (Address < MA_GetStartingAddress(Node))
-            Node = Node->LeftChild;
-        else if (Address >= MA_GetEndingAddress(Node))
-            Node = Node->RightChild;
         else
         {
-            DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
-                   Address, Node, MA_GetStartingAddress(Node), MA_GetEndingAddress(Node));
-            return Node;
+            /* This is a section VAD. Store the MAREA here for now */
+            MemoryArea = (PMEMORY_AREA)Vad->u4.Banked;
         }
     }
+    else
+    {
+        MemoryArea = (PMEMORY_AREA)Node;
+    }
 
-    DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address);
-    return NULL;
+    return MemoryArea;
 }
 
-PMEMORY_AREA NTAPI
+PMEMORY_AREA
+NTAPI
 MmLocateMemoryAreaByRegion(
     PMMSUPPORT AddressSpace,
     PVOID Address_,
     ULONG_PTR Length)
 {
-    PMEMORY_AREA Node;
-    ULONG_PTR Address = (ULONG_PTR)Address_;
-    ULONG_PTR Extent = Address + Length;
-
-    /* Special case for empty tree. */
-    if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
-        return NULL;
-
-    /* Traverse the tree from left to right. */
-    for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
-            Node != NULL;
-            Node = MmIterateNextNode(Node))
-    {
-        if (MA_GetStartingAddress(Node) >= Address &&
-                MA_GetStartingAddress(Node) < Extent)
-        {
-            DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
-                   Address, (ULONG_PTR)Address + Length, MA_GetStartingAddress(Node),
-                   MA_GetEndingAddress(Node));
-            return Node;
-        }
-        if (MA_GetEndingAddress(Node) > Address &&
-                MA_GetEndingAddress(Node) < Extent)
-        {
-            DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
-                   Address, (ULONG_PTR)Address + Length, MA_GetStartingAddress(Node),
-                   MA_GetEndingAddress(Node));
-            return Node;
-        }
-        if (MA_GetStartingAddress(Node) <= Address &&
-                MA_GetEndingAddress(Node) >= Extent)
-        {
-            DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
-                   Address, (ULONG_PTR)Address + Length, MA_GetStartingAddress(Node),
-                   MA_GetEndingAddress(Node));
-            return Node;
-        }
-        if (MA_GetStartingAddress(Node) >= Extent)
-        {
-            DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
-            return NULL;
-        }
-    }
-
-    return NULL;
-}
-
-/**
- * @name MmCompressHelper
- *
- * This is helper of MmRebalanceTree. Performs a compression transformation
- * count times, starting at root.
- */
+    ULONG_PTR StartVpn = (ULONG_PTR)Address_ / PAGE_SIZE;
+    ULONG_PTR EndVpn = ((ULONG_PTR)Address_ + Length - 1) / PAGE_SIZE;
+    PEPROCESS Process;
+    PMM_AVL_TABLE Table;
+    PMMADDRESS_NODE Node;
+    PMEMORY_AREA MemoryArea;
+    TABLE_SEARCH_RESULT Result;
+    PMMVAD_LONG Vad;
 
-static VOID
-MmCompressHelper(
-    PMMSUPPORT AddressSpace,
-    ULONG Count)
-{
-    PMEMORY_AREA Root = NULL;
-    PMEMORY_AREA Red = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
-    PMEMORY_AREA Black = Red->LeftChild;
+    Process = MmGetAddressSpaceOwner(AddressSpace);
+    Table = (Process != NULL) ? &Process->VadRoot : &MiRosKernelVadRoot;
 
-    while (Count--)
+    Result = MiCheckForConflictingNode(StartVpn, EndVpn, Table, &Node);
+    if (Result != TableFoundNode)
     {
-        if (Root)
-            Root->LeftChild = Black;
-        else
-            AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)Black;
-        Black->Parent = Root;
-        Red->LeftChild = Black->RightChild;
-        if (Black->RightChild)
-            Black->RightChild->Parent = Red;
-        Black->RightChild = Red;
-        Red->Parent = Black;
-        Root = Black;
-
-        if (Count)
-        {
-            Red = Root->LeftChild;
-            Black = Red->LeftChild;
-        }
+        return NULL;
     }
-}
-
-/**
- * @name MmRebalanceTree
- *
- * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
- * method described in libavl documentation in chapter 4.12.
- * (http://www.stanford.edu/~blp/avl/libavl.html/)
- */
 
-static VOID
-MmRebalanceTree(
-    PMMSUPPORT AddressSpace)
-{
-    PMEMORY_AREA PreviousNode;
-    PMEMORY_AREA CurrentNode;
-    PMEMORY_AREA TempNode;
-    ULONG NodeCount = 0;
-    ULONG Vine;   /* Number of nodes in main vine. */
-    ULONG Leaves; /* Nodes in incomplete bottom level, if any. */
-    INT Height;   /* Height of produced balanced tree. */
-
-    /* Transform the tree into Vine. */
-
-    PreviousNode = NULL;
-    CurrentNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
-    while (CurrentNode != NULL)
+    Vad = (PMMVAD_LONG)Node;
+    if (Vad->u.VadFlags.Spare == 0)
     {
-        if (CurrentNode->RightChild == NULL)
+        /* Check if this is VM VAD */
+        if (Vad->ControlArea == NULL)
         {
-            PreviousNode = CurrentNode;
-            CurrentNode = CurrentNode->LeftChild;
-            NodeCount++;
+            /* We store the reactos MEMORY_AREA here */
+            MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte;
         }
         else
         {
-            TempNode = CurrentNode->RightChild;
-
-            CurrentNode->RightChild = TempNode->LeftChild;
-            if (TempNode->LeftChild)
-                TempNode->LeftChild->Parent = CurrentNode;
-
-            TempNode->LeftChild = CurrentNode;
-            CurrentNode->Parent = TempNode;
-
-            CurrentNode = TempNode;
-
-            if (PreviousNode != NULL)
-                PreviousNode->LeftChild = TempNode;
-            else
-                AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)TempNode;
-            TempNode->Parent = PreviousNode;
+            /* This is a section VAD. Store the MAREA here for now */
+            MemoryArea = (PMEMORY_AREA)Vad->u4.Banked;
         }
     }
-
-    /* Transform Vine back into a balanced tree. */
-
-    Leaves = NodeCount + 1;
-    for (;;)
+    else
     {
-        ULONG Next = Leaves & (Leaves - 1);
-        if (Next == 0)
-            break;
-        Leaves = Next;
+        MemoryArea = (PMEMORY_AREA)Node;
     }
-    Leaves = NodeCount + 1 - Leaves;
-
-    MmCompressHelper(AddressSpace, Leaves);
 
-    Vine = NodeCount - Leaves;
-    Height = 1 + (Leaves > 0);
-    while (Vine > 1)
-    {
-        MmCompressHelper(AddressSpace, Vine / 2);
-        Vine /= 2;
-        Height++;
-    }
+    ASSERT(MemoryArea != NULL);
+    return MemoryArea;
 }
 
 VOID
 NTAPI
 MiInsertVad(IN PMMVAD Vad,
-            IN PEPROCESS Process);
+            IN PMM_AVL_TABLE VadRoot);
 
 ULONG
 NTAPI
@@ -367,250 +161,94 @@ MiMakeProtectionMask(
     IN ULONG Protect
 );
 
+
 static VOID
 MmInsertMemoryArea(
     PMMSUPPORT AddressSpace,
     PMEMORY_AREA marea)
 {
-    PMEMORY_AREA Node;
-    PMEMORY_AREA PreviousNode;
-    ULONG Depth = 0;
     PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
 
+    marea->VadNode.StartingVpn = marea->StartingVpn;
+    marea->VadNode.EndingVpn = marea->EndingVpn;
+    marea->VadNode.u.VadFlags.Spare = 1;
+    marea->VadNode.u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect);
+
     /* Build a lame VAD if this is a user-space allocation */
-    if ((MA_GetEndingAddress(marea) < (ULONG_PTR)MmSystemRangeStart) &&
-        (marea->Type != MEMORY_AREA_OWNED_BY_ARM3))
+    if (MA_GetEndingAddress(marea) < (ULONG_PTR)MmSystemRangeStart)
     {
-        PMMVAD Vad;
-
-        ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE);
-        Vad = &marea->VadNode;
-
-        RtlZeroMemory(Vad, sizeof(MMVAD));
-        Vad->StartingVpn = PAGE_ROUND_DOWN(MA_GetStartingAddress(marea)) >> 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 (MA_GetEndingAddress(marea) != MA_GetStartingAddress(marea))
-        {
-            Vad->EndingVpn = PAGE_ROUND_DOWN((ULONG_PTR)MA_GetEndingAddress(marea) - 1) >> PAGE_SHIFT;
-        }
-        else
+        ASSERT(Process != NULL);
+        if (marea->Type != MEMORY_AREA_OWNED_BY_ARM3)
         {
-            Vad->EndingVpn = Vad->StartingVpn;
-        }
-        Vad->u.VadFlags.Spare = 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)
-    {
-        AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)marea;
-        marea->LeftChild = marea->RightChild = marea->Parent = NULL;
-        return;
-    }
+            ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE);
 
-    Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
-    do
-    {
-        DPRINT("MA_GetEndingAddress(marea): %p Node->StartingAddress: %p\n",
-               MA_GetEndingAddress(marea), MA_GetStartingAddress(Node));
-        DPRINT("marea->StartingAddress: %p MA_GetEndingAddress(Node): %p\n",
-               MA_GetStartingAddress(marea), MA_GetEndingAddress(Node));
-        ASSERT(MA_GetEndingAddress(marea) <= MA_GetStartingAddress(Node) ||
-               MA_GetStartingAddress(marea) >= MA_GetEndingAddress(Node));
-        ASSERT(MA_GetStartingAddress(marea) != MA_GetStartingAddress(Node));
-
-        PreviousNode = Node;
-
-        if (MA_GetStartingAddress(marea) < MA_GetStartingAddress(Node))
-            Node = Node->LeftChild;
-        else
-            Node = Node->RightChild;
-
-        if (Node)
-        {
-            Depth++;
-            if (Depth == 22)
-            {
-                MmRebalanceTree(AddressSpace);
-                PreviousNode = Node->Parent;
-            }
+            /* Insert the VAD */
+            MiLockProcessWorkingSetUnsafe(PsGetCurrentProcess(), PsGetCurrentThread());
+            MiInsertVad(&marea->VadNode, &Process->VadRoot);
+            MiUnlockProcessWorkingSetUnsafe(PsGetCurrentProcess(), PsGetCurrentThread());
+            marea->Vad = &marea->VadNode;
         }
     }
-    while (Node != NULL);
-
-    marea->LeftChild = marea->RightChild = NULL;
-    marea->Parent = PreviousNode;
-    if (MA_GetStartingAddress(marea) < MA_GetStartingAddress(PreviousNode))
-        PreviousNode->LeftChild = marea;
-    else
-        PreviousNode->RightChild = marea;
-}
-
-static PVOID
-MmFindGapBottomUp(
-    PMMSUPPORT AddressSpace,
-    ULONG_PTR Length,
-    ULONG_PTR Granularity)
-{
-    ULONG_PTR LowestAddress, HighestAddress, Candidate;
-    PMEMORY_AREA Root, Node;
-
-    /* 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;
-    }
-
-    /* Start with the lowest address */
-    Candidate = LowestAddress;
-
-    /* Check for overflow */
-    if ((Candidate + Length) < Candidate) return NULL;
-
-    /* Get the root of the address space tree */
-    Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
-
-    /* Go to the node with lowest address in the tree. */
-    Node = Root ? MmIterateFirstNode(Root) : NULL;
-    while (Node && ((ULONG_PTR)MA_GetEndingAddress(Node) < LowestAddress))
-    {
-        Node = MmIterateNextNode(Node);
-    }
+        ASSERT(Process == NULL);
 
-    /* Traverse the tree from low to high addresses */
-    while (Node && ((ULONG_PTR)MA_GetEndingAddress(Node) < HighestAddress))
-    {
-        /* Check if the memory area fits before the current node */
-        if (MA_GetStartingAddress(Node) >= (Candidate + Length))
+        if (!MiRosKernelVadRootInitialized)
         {
-            DPRINT("MmFindGapBottomUp: %p\n", Candidate);
-            ASSERT(Candidate >= LowestAddress);
-            return (PVOID)Candidate;
+            MiRosKernelVadRoot.BalancedRoot.u1.Parent = &MiRosKernelVadRoot.BalancedRoot;
+            MiRosKernelVadRoot.Unused = 1;
+            MiRosKernelVadRootInitialized = TRUE;
         }
 
-        /* Calculate next possible adress above this node */
-        Candidate = ALIGN_UP_BY((ULONG_PTR)MA_GetEndingAddress(Node), Granularity);
-
-        /* Check for overflow */
-        if ((Candidate + Length) < (ULONG_PTR)MA_GetEndingAddress(Node)) return NULL;
-
-        /* Go to the next higher node */
-        Node = MmIterateNextNode(Node);
-    }
-
-    /* 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;
+        /* Insert the VAD */
+        MiLockWorkingSet(PsGetCurrentThread(), &MmSystemCacheWs);
+        MiInsertVad(&marea->VadNode, &MiRosKernelVadRoot);
+        MiUnlockWorkingSet(PsGetCurrentThread(), &MmSystemCacheWs);
+        marea->Vad = NULL;
     }
-
-    DPRINT("MmFindGapBottomUp: 0\n");
-    return NULL;
 }
 
-
-static PVOID
-MmFindGapTopDown(
+PVOID NTAPI
+MmFindGap(
     PMMSUPPORT AddressSpace,
     ULONG_PTR Length,
-    ULONG_PTR Granularity)
+    ULONG_PTR Granularity,
+    BOOLEAN TopDown)
 {
-    ULONG_PTR LowestAddress, HighestAddress, Candidate;
-    PMEMORY_AREA Root, Node;
+    PEPROCESS Process;
+    PMM_AVL_TABLE VadRoot;
+    TABLE_SEARCH_RESULT Result;
+    PMMADDRESS_NODE Parent;
+    ULONG_PTR StartingAddress, HighestAddress;
 
-    /* Get the margins of the address space */
-    if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
+    Process = MmGetAddressSpaceOwner(AddressSpace);
+    VadRoot = Process ? &Process->VadRoot : &MiRosKernelVadRoot;
+    if (TopDown)
     {
-        LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
-        HighestAddress = (ULONG_PTR)MmHighestUserAddress;
+        /* Find an address top-down */
+        HighestAddress = Process ? (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS : (LONG_PTR)-1;
+        Result = MiFindEmptyAddressRangeDownTree(Length,
+                                                 HighestAddress,
+                                                 Granularity,
+                                                 VadRoot,
+                                                 &StartingAddress,
+                                                 &Parent);
     }
     else
     {
-        LowestAddress = (ULONG_PTR)MmSystemRangeStart;
-        HighestAddress = MAXULONG_PTR;
-    }
-
-    /* Calculate the highest candidate */
-    Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity);
-
-    /* Check for overflow. */
-    if (Candidate > HighestAddress) return NULL;
-
-    /* Get the root of the address space tree */
-    Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
-
-    /* Go to the node with highest address in the tree. */
-    Node = Root ? MmIterateLastNode(Root) : NULL;
-    while (Node && (MA_GetStartingAddress(Node) > HighestAddress))
-    {
-        Node = MmIteratePrevNode(Node);
-    }
-
-    /* Traverse the tree from high to low addresses */
-    while (Node && (MA_GetStartingAddress(Node) > LowestAddress))
-    {
-        /* Check if the memory area fits after the current node */
-        if ((ULONG_PTR)MA_GetEndingAddress(Node) <= Candidate)
-        {
-            DPRINT("MmFindGapTopDown: %p\n", Candidate);
-            return (PVOID)Candidate;
-        }
-
-        /* Calculate next possible adress below this node */
-        Candidate = ALIGN_DOWN_BY(MA_GetStartingAddress(Node) - Length,
-                                  Granularity);
-
-        /* Check for overflow. */
-        if (Candidate > MA_GetStartingAddress(Node))
-            return NULL;
-
-        /* Go to the next lower node */
-        Node = MmIteratePrevNode(Node);
+        Result = MiFindEmptyAddressRangeInTree(Length,
+                                               Granularity,
+                                               VadRoot,
+                                               &Parent,
+                                               &StartingAddress);
     }
 
-    /* Check if the last candidate is inside the given range */
-    if (Candidate >= LowestAddress)
+    if (Result == TableFoundNode)
     {
-        DPRINT("MmFindGapTopDown: %p\n", Candidate);
-        return (PVOID)Candidate;
+        return NULL;
     }
 
-    DPRINT("MmFindGapTopDown: 0\n");
-    return NULL;
-}
-
-
-PVOID NTAPI
-MmFindGap(
-    PMMSUPPORT AddressSpace,
-    ULONG_PTR Length,
-    ULONG_PTR Granularity,
-    BOOLEAN TopDown)
-{
-    if (TopDown)
-        return MmFindGapTopDown(AddressSpace, Length, Granularity);
-
-    return MmFindGapBottomUp(AddressSpace, Length, Granularity);
+    return (PVOID)StartingAddress;
 }
 
 VOID
@@ -618,99 +256,6 @@ 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(MA_GetStartingAddress(Node)) == (PVOID)MA_GetStartingAddress(Node));
-    ASSERT(MA_GetEndingAddress(Node) != 0);
-    ASSERT(PAGE_ALIGN(MA_GetEndingAddress(Node)) == (PVOID)MA_GetEndingAddress(Node));
-    ASSERT(MA_GetStartingAddress(Node) < MA_GetEndingAddress(Node));
-    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
@@ -744,7 +289,6 @@ MmFreeMemoryArea(
     PMM_FREE_PAGE_FUNC FreePage,
     PVOID FreePageContext)
 {
-    PMEMORY_AREA *ParentReplace;
     ULONG_PTR Address;
     PVOID EndAddress;
 
@@ -813,73 +357,24 @@ MmFreeMemoryArea(
             KeDetachProcess();
         }
 
+        //if (MemoryArea->VadNode.StartingVpn < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT
         if (MemoryArea->Vad)
         {
             ASSERT(MA_GetEndingAddress(MemoryArea) < (ULONG_PTR)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);
+            ASSERT(MemoryArea->VadNode.u.VadFlags.Spare != 0);
             if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1)
             {
-                MiRemoveNode(MemoryArea->Vad, &Process->VadRoot);
+                MiRemoveNode((PMMADDRESS_NODE)&MemoryArea->VadNode, &Process->VadRoot);
             }
 
             MemoryArea->Vad = NULL;
         }
-    }
-
-    /* Remove the tree item. */
-    {
-        if (MemoryArea->Parent != NULL)
-        {
-            if (MemoryArea->Parent->LeftChild == MemoryArea)
-                ParentReplace = &MemoryArea->Parent->LeftChild;
-            else
-                ParentReplace = &MemoryArea->Parent->RightChild;
-        }
         else
-            ParentReplace = (PMEMORY_AREA*)&AddressSpace->WorkingSetExpansionLinks.Flink;
-
-        if (MemoryArea->RightChild == NULL)
         {
-            *ParentReplace = MemoryArea->LeftChild;
-            if (MemoryArea->LeftChild)
-                MemoryArea->LeftChild->Parent = MemoryArea->Parent;
-        }
-        else
-        {
-            if (MemoryArea->RightChild->LeftChild == NULL)
-            {
-                MemoryArea->RightChild->LeftChild = MemoryArea->LeftChild;
-                if (MemoryArea->LeftChild)
-                    MemoryArea->LeftChild->Parent = MemoryArea->RightChild;
-
-                *ParentReplace = MemoryArea->RightChild;
-                MemoryArea->RightChild->Parent = MemoryArea->Parent;
-            }
-            else
-            {
-                PMEMORY_AREA LowestNode;
-
-                LowestNode = MemoryArea->RightChild->LeftChild;
-                while (LowestNode->LeftChild != NULL)
-                    LowestNode = LowestNode->LeftChild;
-
-                LowestNode->Parent->LeftChild = LowestNode->RightChild;
-                if (LowestNode->RightChild)
-                    LowestNode->RightChild->Parent = LowestNode->Parent;
-
-                LowestNode->LeftChild = MemoryArea->LeftChild;
-                if (MemoryArea->LeftChild)
-                    MemoryArea->LeftChild->Parent = LowestNode;
-
-                LowestNode->RightChild = MemoryArea->RightChild;
-                MemoryArea->RightChild->Parent = LowestNode;
-
-                *ParentReplace = LowestNode;
-                LowestNode->Parent = MemoryArea->Parent;
-            }
+            MiRemoveNode((PMMADDRESS_NODE)&MemoryArea->VadNode, &MiRosKernelVadRoot);
         }
     }
 
@@ -923,7 +418,6 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
                    ULONG_PTR Length,
                    ULONG Protect,
                    PMEMORY_AREA *Result,
-                   BOOLEAN FixedAddress,
                    ULONG AllocationFlags,
                    ULONG Granularity)
 {
@@ -933,11 +427,39 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
 
     DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, "
            "*BaseAddress %p, Length %p, AllocationFlags %x, "
-           "FixedAddress %x, Result %p)\n",
+           "Result %p)\n",
            Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
-           FixedAddress, Result);
+           Result);
+
+    /* Is this a static memory area? */
+    if (Type & MEMORY_AREA_STATIC)
+    {
+        /* Use the static array instead of the pool */
+        ASSERT(MiStaticMemoryAreaCount < MI_STATIC_MEMORY_AREAS);
+        MemoryArea = &MiStaticMemoryAreas[MiStaticMemoryAreaCount++];
+    }
+    else
+    {
+        /* Allocate the memory area from nonpaged pool */
+        MemoryArea = ExAllocatePoolWithTag(NonPagedPool,
+                                           sizeof(MEMORY_AREA),
+                                           TAG_MAREA);
+    }
+
+    if (!MemoryArea)
+    {
+        DPRINT1("Not enough memory.\n");
+        return STATUS_NO_MEMORY;
+    }
+
+    RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
+    MemoryArea->Type = Type & ~MEMORY_AREA_STATIC;
+    MemoryArea->Protect = Protect;
+    MemoryArea->Flags = AllocationFlags;
+    MemoryArea->Magic = 'erAM';
+    MemoryArea->DeleteInProgress = FALSE;
 
-    if ((*BaseAddress) == 0 && !FixedAddress)
+    if (*BaseAddress == 0)
     {
         tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, PAGE_SIZE);
         *BaseAddress = MmFindGap(AddressSpace,
@@ -947,8 +469,13 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
         if ((*BaseAddress) == 0)
         {
             DPRINT("No suitable gap\n");
+            if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
             return STATUS_NO_MEMORY;
         }
+
+        MemoryArea->StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT;
+        MemoryArea->EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT;
+        MmInsertMemoryArea(AddressSpace, MemoryArea);
     }
     else
     {
@@ -958,6 +485,8 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
 
         if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart)
         {
+            ASSERT(FALSE);
+            if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
             return STATUS_ACCESS_VIOLATION;
         }
 
@@ -965,65 +494,79 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
                 (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
         {
             DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n");
+            if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
             return STATUS_ACCESS_VIOLATION;
         }
 
-        if (MmLocateMemoryAreaByRegion(AddressSpace,
-                                       *BaseAddress,
-                                       tmpLength) != NULL)
+        /* No need to check ARM3 owned memory areas, the range MUST be free */
+        if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
         {
-            DPRINT("Memory area already occupied\n");
-            return STATUS_CONFLICTING_ADDRESSES;
+            if (MmLocateMemoryAreaByRegion(AddressSpace,
+                                           *BaseAddress,
+                                           tmpLength) != NULL)
+            {
+                DPRINT("Memory area already occupied\n");
+                if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
+                return STATUS_CONFLICTING_ADDRESSES;
+            }
         }
+
+        MemoryArea->StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT;
+        MemoryArea->EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT;
+        MmInsertMemoryArea(AddressSpace, MemoryArea);
     }
 
-    //
-    // Is this a static memory area?
-    //
-    if (Type & MEMORY_AREA_STATIC)
+    *Result = MemoryArea;
+
+    DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress);
+    return STATUS_SUCCESS;
+}
+
+VOID
+NTAPI
+MiRosCleanupMemoryArea(
+    PEPROCESS Process,
+    PMMVAD Vad)
+{
+    PMEMORY_AREA MemoryArea;
+    PVOID BaseAddress;
+    NTSTATUS Status;
+
+    /* We must be called from MmCleanupAddressSpace and nowhere else!
+       Make sure things are as expected... */
+    ASSERT(Process == PsGetCurrentProcess());
+    ASSERT(Process->VmDeleted == TRUE);
+    ASSERT(((PsGetCurrentThread()->ThreadsProcess == Process) &&
+            (Process->ActiveThreads == 1)) ||
+           (Process->ActiveThreads == 0));
+
+    /* We are in cleanup, we don't need to synchronize */
+    MmUnlockAddressSpace(&Process->Vm);
+
+    MemoryArea = (PMEMORY_AREA)Vad;
+    BaseAddress = (PVOID)MA_GetStartingAddress(MemoryArea);
+
+    if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
     {
-        //
-        // Use the static array instead of the pool
-        //
-        ASSERT(MiStaticMemoryAreaCount < MI_STATIC_MEMORY_AREAS);
-        MemoryArea = &MiStaticMemoryAreas[MiStaticMemoryAreaCount++];
-        Type &= ~MEMORY_AREA_STATIC;
+        Status = MiRosUnmapViewOfSection(Process, BaseAddress, 0);
     }
-    else
+    else if (MemoryArea->Type == MEMORY_AREA_CACHE)
     {
-        //
-        // Allocate the memory area from nonpaged pool
-        //
-        MemoryArea = ExAllocatePoolWithTag(NonPagedPool,
-                                           sizeof(MEMORY_AREA),
-                                           TAG_MAREA);
+        Status = MmUnmapViewOfCacheSegment(&Process->Vm, BaseAddress);
     }
-
-    if (!MemoryArea)
+    else
     {
-        DPRINT1("Not enough memory.\n");
-        return STATUS_NO_MEMORY;
+        /* There shouldn't be anything else! */
+        ASSERT(FALSE);
     }
 
-    RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
-    MemoryArea->Type = Type;
-    MemoryArea->StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT;
-    MemoryArea->EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT;
-    MemoryArea->Protect = Protect;
-    MemoryArea->Flags = AllocationFlags;
-    //MemoryArea->LockCount = 0;
-    MemoryArea->Magic = 'erAM';
-    MemoryArea->DeleteInProgress = FALSE;
+    /* Make sure this worked! */
+    ASSERT(NT_SUCCESS(Status));
 
-    MmInsertMemoryArea(AddressSpace, MemoryArea);
-
-    *Result = MemoryArea;
-
-    DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress);
-    return STATUS_SUCCESS;
+    /* Lock the address space again */
+    MmLockAddressSpace(&Process->Vm);
 }
 
-
 VOID
 NTAPI
 MmDeleteProcessAddressSpace2(IN PEPROCESS Process);
@@ -1032,46 +575,21 @@ NTSTATUS
 NTAPI
 MmDeleteProcessAddressSpace(PEPROCESS Process)
 {
+    KIRQL OldIrql;
     PVOID Address;
-    PMEMORY_AREA MemoryArea;
 
     DPRINT("MmDeleteProcessAddressSpace(Process %p (%s))\n", Process,
            Process->ImageFileName);
 
 #ifndef _M_AMD64
+    OldIrql = MiAcquireExpansionLock();
     RemoveEntryList(&Process->MmProcessLinks);
+    MiReleaseExpansionLock(OldIrql);
 #endif
     MmLockAddressSpace(&Process->Vm);
 
-    while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
-    {
-        switch (MemoryArea->Type)
-        {
-        case MEMORY_AREA_SECTION_VIEW:
-            Address = (PVOID)MA_GetStartingAddress(MemoryArea);
-            MmUnlockAddressSpace(&Process->Vm);
-            MmUnmapViewOfSection(Process, Address);
-            MmLockAddressSpace(&Process->Vm);
-            break;
-
-        case MEMORY_AREA_CACHE:
-            Address = (PVOID)MA_GetStartingAddress(MemoryArea);
-            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);
-        }
-    }
+    /* There should not be any memory areas left! */
+    ASSERT(Process->Vm.WorkingSetExpansionLinks.Flink == NULL);
 
 #if (_MI_PAGING_LEVELS == 2)
     {
@@ -1096,6 +614,7 @@ MmDeleteProcessAddressSpace(PEPROCESS Process)
                         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 */
@@ -1103,6 +622,7 @@ MmDeleteProcessAddressSpace(PEPROCESS Process)
                 MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL);
             ASSERT(pointerPde->u.Hard.Valid == 0);
         }
+
         /* Release lock */
         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);