- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / mm / marea.c
index 2b6b051..a031f64 100644 (file)
-/*
- * COPYRIGHT:       See COPYING in the top level directory
+/* $Id$
+ *
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/mm/marea.c
  * PURPOSE:         Implements memory areas
- * PROGRAMMER:      David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ *
+ * PROGRAMMERS:     Rex Jolliff
+ *                  David Welch
+ *                  Eric Kohl
+ *                  Philip Susi
+ *                  Casper Hornstrup
+ *                  Eric Kohl
+ *                  Ge van Geldorp
+ *                  Royce Mitchell III
+ *                  Aleksey Bragin 
+ *                  Jason Filby
+ *                  Thomas Weidenmueller
+ *                  Gunnar Andre' Dalsnes
+ *                  Mike Nordell
+ *                  Alex Ionescu
+ *                  Filip Navara
+ *                  Herve Poussineau
+ *                  Steven Edwards
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/mm.h>
-#include <internal/mmhal.h>
-#include <internal/ps.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, MmInitMemoryAreas)
+#endif
+
+/* #define VALIDATE_MEMORY_AREAS */
+
 /* FUNCTIONS *****************************************************************/
 
-VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
+/**
+ * @name MmIterateFirstNode
+ *
+ * @param Node
+ *        Head node of the MEMORY_AREA tree.
+ *
+ * @return The leftmost MEMORY_AREA node (ie. the one with lowest
+ *         address)
+ */
+
+static PMEMORY_AREA MmIterateFirstNode(PMEMORY_AREA Node)
+{
+   while (Node->LeftChild != NULL)
+      Node = Node->LeftChild;
+
+   return Node;
+}
+
+/**
+ * @name MmIterateNextNode
+ *
+ * @param Node
+ *        Current node in the tree.
+ *
+ * @return Next node in the tree (sorted by address).
+ */
+
+static PMEMORY_AREA MmIterateNextNode(PMEMORY_AREA Node)
+{
+   if (Node->RightChild != NULL)
+   {
+      Node = Node->RightChild;
+      while (Node->LeftChild != NULL)
+         Node = Node->LeftChild;
+   }
+   else
+   {
+      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 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
+   {
+      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->LeftChild);
+   }
+   return Node;
+}
+
+#ifdef VALIDATE_MEMORY_AREAS
+static VOID MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace)
+{
+   PMEMORY_AREA Node;
+
+   ASSERT(AddressSpace != NULL);
+
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+      return;
+
+   /* Traverse the tree from left to right. */
+   for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+        Node != NULL;
+        Node = MmIterateNextNode(Node))
+   {
+      /* FiN: The starting address can be NULL if someone explicitely asks
+       * for NULL address. */
+      ASSERT(Node->StartingAddress >= AddressSpace->LowestAddress ||
+             Node->StartingAddress == NULL);
+      ASSERT(Node->EndingAddress >= Node->StartingAddress);
+   }
+}
+#else
+#define MmVerifyMemoryAreas(x)
+#endif
+
+VOID STDCALL
+MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace)
 {
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   
+   PMEMORY_AREA Node;
+
    DbgPrint("MmDumpMemoryAreas()\n");
-   
-   current_entry = ListHead->Flink;
-   while (current_entry!=ListHead)
-     {
-       current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-       DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
-              current->BaseAddress,current->Length,
-              current->BaseAddress+current->Length,current->Attributes,
-              current->Entry.Flink);
-       current_entry = current_entry->Flink;
-     }
+
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+      return;
+
+   /* Traverse the tree from left to right. */
+   for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+        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");
 }
 
-MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
-                                      PVOID Address)
+PMEMORY_AREA STDCALL
+MmLocateMemoryAreaByAddress(
+   PMADDRESS_SPACE AddressSpace,
+   PVOID Address)
+{
+   PMEMORY_AREA Node = AddressSpace->MemoryAreaRoot;
+
+   DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
+           AddressSpace, Address);
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   while (Node != NULL)
+   {
+      if (Address < Node->StartingAddress)
+         Node = Node->LeftChild;
+      else if (Address >= Node->EndingAddress)
+         Node = Node->RightChild;
+      else
+      {
+         DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
+                Address, Node, Node->StartingAddress, Node->EndingAddress);
+         return Node;
+      }
+   }
+
+   DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address);
+   return NULL;
+}
+
+PMEMORY_AREA STDCALL
+MmLocateMemoryAreaByRegion(
+   PMADDRESS_SPACE AddressSpace,
+   PVOID Address,
+   ULONG_PTR Length)
+{
+   PMEMORY_AREA Node;
+   PVOID Extent = (PVOID)((ULONG_PTR)Address + Length);
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+      return NULL;
+
+   /* Traverse the tree from left to right. */
+   for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+        Node != NULL;
+        Node = MmIterateNextNode(Node))
+   {
+      if (Node->StartingAddress >= Address &&
+          Node->StartingAddress < Extent)
+      {
+         DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
+                Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
+                Node->EndingAddress);
+         return Node;
+      }
+      if (Node->EndingAddress > Address &&
+          Node->EndingAddress < Extent)
+      {
+         DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
+                Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
+                Node->EndingAddress);
+         return Node;
+      }
+      if (Node->StartingAddress <= Address &&
+          Node->EndingAddress >= Extent)
+      {
+         DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
+                Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
+                Node->EndingAddress);
+         return Node;
+      }
+      if (Node->StartingAddress >= 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.
+ */
+
+static VOID
+MmCompressHelper(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG Count)
+{
+   PMEMORY_AREA Root = NULL;
+   PMEMORY_AREA Red = AddressSpace->MemoryAreaRoot;
+   PMEMORY_AREA Black = Red->LeftChild;
+
+   while (Count--)
+   {
+      if (Root)
+         Root->LeftChild = Black;
+      else
+         AddressSpace->MemoryAreaRoot = 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;
+      }
+   }
+}
+
+/**
+ * @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(
+   PMADDRESS_SPACE 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 = AddressSpace->MemoryAreaRoot;
+   while (CurrentNode != NULL)
+   {
+      if (CurrentNode->RightChild == NULL)
+      {
+         PreviousNode = CurrentNode;
+         CurrentNode = CurrentNode->LeftChild;
+         NodeCount++;
+      }
+      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->MemoryAreaRoot = TempNode;
+         TempNode->Parent = PreviousNode;
+      }
+   }
+
+   /* Transform Vine back into a balanced tree. */
+
+   Leaves = NodeCount + 1;
+   for (;;)
+   {
+      ULONG Next = Leaves & (Leaves - 1);
+      if (Next == 0)
+         break;
+      Leaves = Next;
+   }
+   Leaves = NodeCount + 1 - Leaves;
+
+   MmCompressHelper(AddressSpace, Leaves);
+
+   Vine = NodeCount - Leaves;
+   Height = 1 + (Leaves > 0);
+   while (Vine > 1)
+   {
+      MmCompressHelper(AddressSpace, Vine / 2);
+      Vine /= 2;
+      Height++;
+   }
+}
+
+static VOID
+MmInsertMemoryArea(
+   PMADDRESS_SPACE AddressSpace,
+   PMEMORY_AREA marea)
+{
+   PMEMORY_AREA Node;
+   PMEMORY_AREA PreviousNode;
+   ULONG Depth = 0;
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   if (AddressSpace->MemoryAreaRoot == NULL)
+   {
+      AddressSpace->MemoryAreaRoot = marea;
+      marea->LeftChild = marea->RightChild = marea->Parent = NULL;
+      return;
+   }
+
+   Node = AddressSpace->MemoryAreaRoot;
+   do
+   {
+      DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
+             marea->EndingAddress, Node->StartingAddress);
+      DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
+             marea->StartingAddress, Node->EndingAddress);
+      ASSERT(marea->EndingAddress <= Node->StartingAddress ||
+             marea->StartingAddress >= Node->EndingAddress);
+      ASSERT(marea->StartingAddress != Node->StartingAddress);
+
+      PreviousNode = Node;
+
+      if (marea->StartingAddress < Node->StartingAddress)
+         Node = Node->LeftChild;
+      else
+         Node = Node->RightChild;
+
+      if (Node)
+      {
+         Depth++;
+         if (Depth == 22)
+         {
+            MmRebalanceTree(AddressSpace);
+            PreviousNode = Node->Parent;
+         }
+      }
+   }
+   while (Node != NULL);
+
+   marea->LeftChild = marea->RightChild = NULL;
+   marea->Parent = PreviousNode;
+   if (marea->StartingAddress < PreviousNode->StartingAddress)
+      PreviousNode->LeftChild = marea;
+   else
+      PreviousNode->RightChild = marea;
+}
+
+static PVOID
+MmFindGapBottomUp(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG_PTR Length,
+   ULONG_PTR Granularity)
 {
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   PLIST_ENTRY previous_entry;
-
-   DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
-          AddressSpace, Address);
-   
-//   MmDumpMemoryAreas(&AddressSpace->MAreaListHead);
-   
-   previous_entry = &AddressSpace->MAreaListHead;
-   current_entry = AddressSpace->MAreaListHead.Flink;
-   while (current_entry != &AddressSpace->MAreaListHead)
-     {
-       current = CONTAINING_RECORD(current_entry,
-                                   MEMORY_AREA,
-                                   Entry);
-       DPRINT("Scanning %x BaseAddress %x Length %x\n",
-               current, current->BaseAddress, current->Length);
-       assert(current_entry->Blink->Flink == current_entry);
-       if (current_entry->Flink->Blink != current_entry)
-         {
-            DPRINT1("BaseAddress %x\n", current->BaseAddress);
-            DPRINT1("current_entry->Flink %x ", current_entry->Flink);
-            DPRINT1("&current_entry->Flink %x\n",
-                    &current_entry->Flink);
-            DPRINT1("current_entry->Flink->Blink %x\n",
-                    current_entry->Flink->Blink);
-            DPRINT1("&current_entry->Flink->Blink %x\n",
-                    &current_entry->Flink->Blink);
-            DPRINT1("&current_entry->Flink %x\n",
-                    &current_entry->Flink);
-         }
-       assert(current_entry->Flink->Blink == current_entry);
-       assert(previous_entry->Flink == current_entry);
-       if (current->BaseAddress <= Address &&
-           (current->BaseAddress + current->Length) > Address)
-         {
-            DPRINT("%s() = %x\n",__FUNCTION__,current);
-            return(current);
-         }
-       if (current->BaseAddress > Address)
-         {
-            DPRINT("%s() = NULL\n",__FUNCTION__);
-            return(NULL);
-         }
-       previous_entry = current_entry;
-       current_entry = current_entry->Flink;
-     }
-   DPRINT("%s() = NULL\n",__FUNCTION__);
-   return(NULL);
+   PVOID HighestAddress = AddressSpace->LowestAddress < MmSystemRangeStart ?
+                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
+   PVOID AlignedAddress;
+   PMEMORY_AREA Node;
+   PMEMORY_AREA FirstNode;
+   PMEMORY_AREA PreviousNode;
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   DPRINT("LowestAddress: %p HighestAddress: %p\n",
+          AddressSpace->LowestAddress, HighestAddress);
+
+   AlignedAddress = MM_ROUND_UP(AddressSpace->LowestAddress, Granularity);
+
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+   {
+      if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
+      {
+         DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
+         return AlignedAddress;
+      }
+      DPRINT("MmFindGapBottomUp: 0\n");
+      return 0;
+   }
+
+   /* Go to the node with lowest address in the tree. */
+   FirstNode = Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+
+   /* Traverse the tree from left to right. */
+   PreviousNode = Node;
+   for (;;)
+   {
+      Node = MmIterateNextNode(Node);
+      if (Node == NULL)
+         break;
+
+      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;
+      }
+
+      PreviousNode = 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;
+   }
+
+   /* Check if there is enough space before the first memory area. */
+   AlignedAddress = MM_ROUND_UP(AddressSpace->LowestAddress, Granularity);
+   if (FirstNode->StartingAddress > AlignedAddress &&
+       (ULONG_PTR)FirstNode->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
+   {
+      DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
+      return AlignedAddress;
+   }
+
+   DPRINT("MmFindGapBottomUp: 0\n");
+   return 0;
 }
 
-MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace, 
-                                     PVOID Address,
-                                     ULONG Length)
+
+static PVOID
+MmFindGapTopDown(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG_PTR Length,
+   ULONG_PTR Granularity)
 {
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   ULONG Extent;
-   
-   DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
-         AddressSpace, Address, Length);
-   
-   current_entry = AddressSpace->MAreaListHead.Flink;
-   while (current_entry != &AddressSpace->MAreaListHead)
-     {
-       current = CONTAINING_RECORD(current_entry,
-                                   MEMORY_AREA,
-                                   Entry);
-       DPRINT("current->BaseAddress %x current->Length %x\n",
-              current->BaseAddress,current->Length);
-       if (current->BaseAddress >= Address &&
-           current->BaseAddress < (Address+Length))
-         {
-            DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
-                   current);
-            return(current);
-         }
-       Extent = (ULONG)current->BaseAddress + current->Length;
-       if (Extent > (ULONG)Address &&
-           Extent < (ULONG)(Address+Length))
-         {
-            DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
-                   current);
-            return(current);
-         }
-       if (current->BaseAddress <= Address &&
-           Extent >= (ULONG)(Address+Length))
-         {
-            DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
-                   current);
-            return(current);
-         }
-       if (current->BaseAddress >= (Address+Length))
-         {
-            DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
-            return(NULL);
-         }
-       current_entry = current_entry->Flink;
-     }
-   DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
-   return(NULL);
+   PVOID HighestAddress = AddressSpace->LowestAddress < MmSystemRangeStart ?
+                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
+   PVOID AlignedAddress;
+   PMEMORY_AREA Node;
+   PMEMORY_AREA PreviousNode;
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   DPRINT("LowestAddress: %p HighestAddress: %p\n",
+          AddressSpace->LowestAddress, HighestAddress);
+
+   AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)HighestAddress - Length + 1, Granularity);
+
+   /* Check for overflow. */
+   if (AlignedAddress > HighestAddress)
+      return NULL;
+
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+   {
+      if (AlignedAddress >= (PVOID)AddressSpace->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(AddressSpace->MemoryAreaRoot);
+
+   /* 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;
+
+      AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
+
+      /* Check for overflow. */
+      if (AlignedAddress > PreviousNode->StartingAddress)
+         return NULL;
+
+      if (Node->EndingAddress <= AlignedAddress)
+      {
+         DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
+         return AlignedAddress;
+      }
+
+      PreviousNode = Node;
+   }
+
+   AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
+
+   /* Check for overflow. */
+   if (AlignedAddress > PreviousNode->StartingAddress)
+      return NULL;
+
+   if (AlignedAddress >= (PVOID)AddressSpace->LowestAddress)
+   {
+      DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
+      return AlignedAddress;
+   }
+
+   DPRINT("MmFindGapTopDown: 0\n");
+   return 0;
 }
 
-static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
-                              MEMORY_AREA* marea)
+
+PVOID STDCALL
+MmFindGap(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG_PTR Length,
+   ULONG_PTR Granularity,
+   BOOLEAN TopDown)
 {
-   PLIST_ENTRY ListHead;
-   PLIST_ENTRY current_entry;
-   PLIST_ENTRY inserted_entry = &marea->Entry;
-   MEMORY_AREA* current;
-   MEMORY_AREA* next;   
-   
-   DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
-   DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
-   DPRINT("marea->Length %x\n", marea->Length);
-   
-   ListHead = &AddressSpace->MAreaListHead;
-   
-   current_entry = ListHead->Flink;
-   CHECKPOINT;
-   if (IsListEmpty(ListHead))
-     {
-       CHECKPOINT;
-       InsertHeadList(ListHead,&marea->Entry);
-       DPRINT("Inserting at list head\n");
-       CHECKPOINT;
-       return;
-     }
-   CHECKPOINT;
-   current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-   CHECKPOINT;
-   if (current->BaseAddress > marea->BaseAddress)
-     {
-       CHECKPOINT;
-       InsertHeadList(ListHead,&marea->Entry);
-       DPRINT("Inserting at list head\n");
-       CHECKPOINT;
-       return;
-     }
-   CHECKPOINT;
-   while (current_entry->Flink!=ListHead)
-     {
-//     CHECKPOINT;
-       current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-       next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
-//     assert(current->BaseAddress != marea->BaseAddress);     
-//     assert(next->BaseAddress != marea->BaseAddress);
-       if (current->BaseAddress < marea->BaseAddress &&
-           current->Entry.Flink==ListHead)
-         {
-            DPRINT("Insert after %x\n", current_entry);
-            current_entry->Flink = inserted_entry;
-            inserted_entry->Flink=ListHead;
-            inserted_entry->Blink=current_entry;
-            ListHead->Blink = inserted_entry;               
-            return;
-         }
-       if (current->BaseAddress < marea->BaseAddress &&
-           next->BaseAddress > marea->BaseAddress)
-         {          
-            DPRINT("Inserting before %x\n", current_entry);
-            inserted_entry->Flink = current_entry->Flink;
-            inserted_entry->Blink = current_entry;
-            inserted_entry->Flink->Blink = inserted_entry;
-            current_entry->Flink=inserted_entry;
-            return;
-         }
-       current_entry = current_entry->Flink;
-     }
-   CHECKPOINT;
-   DPRINT("Inserting at list tail\n");
-   InsertTailList(ListHead,inserted_entry);
+   if (TopDown)
+      return MmFindGapTopDown(AddressSpace, Length, Granularity);
+
+   return MmFindGapBottomUp(AddressSpace, Length, Granularity);
 }
 
-static PVOID MmFindGap(PMADDRESS_SPACE AddressSpace,
-                      ULONG Length)
+ULONG_PTR STDCALL
+MmFindGapAtAddress(
+   PMADDRESS_SPACE AddressSpace,
+   PVOID Address)
 {
-   PLIST_ENTRY ListHead;
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   MEMORY_AREA* next;
-   ULONG Gap;
-   
-   DPRINT("MmFindGap(Length %x)\n",Length);
-   
-   ListHead = &AddressSpace->MAreaListHead;
-     
-   current_entry = ListHead->Flink;
-   while (current_entry->Flink!=ListHead)
-     {
-       current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-       next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
-       DPRINT("current %x current->BaseAddress %x ",current,
-              current->BaseAddress);
-       DPRINT("current->Length %x\n",current->Length);
-       DPRINT("next %x next->BaseAddress %x ",next,next->BaseAddress);
-       Gap = (next->BaseAddress ) -(current->BaseAddress + current->Length);
-       DPRINT("Base %x Gap %x\n",current->BaseAddress,Gap);
-       if (Gap >= Length)
-         {
-            return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
-         }
-       current_entry = current_entry->Flink;
-     }
-   
-   if (current_entry == ListHead)
-     {
-       return((PVOID)AddressSpace->LowestAddress);
-     }
-   
-   current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-   //DbgPrint("current %x returning %x\n",current,current->BaseAddress+
-//         current->Length);
-   return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
+   PMEMORY_AREA Node = AddressSpace->MemoryAreaRoot;
+   PMEMORY_AREA RightNeighbour = NULL;
+   PVOID HighestAddress = AddressSpace->LowestAddress < MmSystemRangeStart ?
+                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
+
+   if (AddressSpace->LowestAddress < MmSystemRangeStart)
+   {
+      if (Address >= MmSystemRangeStart)
+      {
+         return 0;
+      }
+   }
+   else
+   {
+      if (Address < AddressSpace->LowestAddress)
+      {
+         return 0;
+      }
+   }
+
+   while (Node != NULL)
+   {
+      if (Address < Node->StartingAddress)
+      {
+         RightNeighbour = Node;
+         Node = Node->LeftChild;
+      }
+      else if (Address >= Node->EndingAddress)
+      {
+         Node = Node->RightChild;
+      }
+      else
+      {
+         DPRINT("MmFindGapAtAddress: 0\n");
+         return 0;
+      }
+   }
+
+   if (RightNeighbour)
+   {
+      DPRINT("MmFindGapAtAddress: %p [%p]\n", Address,
+             (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address);
+      return (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address;
+   }
+   else
+   {
+      DPRINT("MmFindGapAtAddress: %p [%p]\n", Address,
+             (ULONG_PTR)HighestAddress - (ULONG_PTR)Address);
+      return (ULONG_PTR)HighestAddress - (ULONG_PTR)Address;
+   }
 }
 
-NTSTATUS MmInitMemoryAreas(VOID)
-/*
- * FUNCTION: Initialize the memory area list
+/**
+ * @name MmInitMemoryAreas
+ *
+ * Initialize the memory area list implementation.
  */
+
+NTSTATUS
+INIT_FUNCTION
+NTAPI
+MmInitMemoryAreas(VOID)
 {
    DPRINT("MmInitMemoryAreas()\n",0);
    return(STATUS_SUCCESS);
 }
 
-NTSTATUS 
-MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
-                PVOID BaseAddress,
-                ULONG Length,
-                VOID (*FreePage)(PVOID Context, PVOID Address),
-                PVOID FreePageContext)
+
+/**
+ * @name MmFreeMemoryArea
+ *
+ * Free an existing memory area.
+ *
+ * @param AddressSpace
+ *        Address space to free the area from.
+ * @param MemoryArea
+ *        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
+ *
+ * @remarks Lock the address space before calling this function.
+ */
+
+NTSTATUS STDCALL
+MmFreeMemoryArea(
+   PMADDRESS_SPACE AddressSpace,
+   PMEMORY_AREA MemoryArea,
+   PMM_FREE_PAGE_FUNC FreePage,
+   PVOID FreePageContext)
 {
-   MEMORY_AREA* MemoryArea;
-   ULONG i;
-   
-   DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
-          "FreePages %d)\n",AddressSpace,BaseAddress,Length,FreePages);
-
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                         BaseAddress);
-   if (MemoryArea == NULL)
-     {
-       KeBugCheck(0);
-       return(STATUS_UNSUCCESSFUL);
-     }
-   if (FreePage != NULL)
-     {
-       for (i=0;i<=(MemoryArea->Length/PAGESIZE);i++)
-         {
-           FreePage(FreePageContext, 
-                    MemoryArea->BaseAddress + (i * PAGESIZE));
-         }
-     }
-   for (i=0; i<=(MemoryArea->Length/PAGESIZE); i++)
-     {
-       if (AddressSpace->Process != NULL)
-         {
-            DPRINT("Freeing %x in %d\n", 
-                    MemoryArea->BaseAddress + (i*PAGESIZE),
-                    AddressSpace->Process->UniqueProcessId);
-         }
-       else
-         {
-//          DPRINT("Freeing %x in kernel address space\n");
-         }
-       MmDeleteVirtualMapping(AddressSpace->Process,
-                              MemoryArea->BaseAddress + (i*PAGESIZE),
-                              FALSE);
-     }
-   
-   RemoveEntryList(&(MemoryArea->Entry));
-   ExFreePool(MemoryArea);
-   
-   DPRINT("MmFreeMemoryArea() succeeded\n");
-   
-   return(STATUS_SUCCESS);
+   PMEMORY_AREA *ParentReplace;
+   ULONG_PTR Address;
+   PVOID EndAddress;
+   PROS_EPROCESS CurrentProcess = (PROS_EPROCESS)PsGetCurrentProcess();
+
+   if (AddressSpace->Process != NULL &&
+       AddressSpace->Process != CurrentProcess)
+   {
+      KeAttachProcess(&AddressSpace->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_TYPE Page = 0;
+
+         if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)Address))
+         {
+            MmDeletePageFileMapping(AddressSpace->Process, (PVOID)Address, &SwapEntry);
+         }
+         else
+         {
+            MmDeleteVirtualMapping(AddressSpace->Process, (PVOID)Address, FALSE, &Dirty, &Page);
+         }
+         if (FreePage != NULL)
+         {
+            FreePage(FreePageContext, MemoryArea, (PVOID)Address,
+                     Page, SwapEntry, (BOOLEAN)Dirty);
+         }
+      }
+   }
+
+   if (AddressSpace->Process != NULL &&
+       AddressSpace->Process != CurrentProcess)
+   {
+      KeDetachProcess();
+   }
+
+   /* Remove the tree item. */
+   {
+      if (MemoryArea->Parent != NULL)
+      {
+         if (MemoryArea->Parent->LeftChild == MemoryArea)
+            ParentReplace = &MemoryArea->Parent->LeftChild;
+         else
+            ParentReplace = &MemoryArea->Parent->RightChild;
+      }
+      else
+         ParentReplace = &AddressSpace->MemoryAreaRoot;
+
+      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;
+         }
+      }
+   }
+
+   ExFreePoolWithTag(MemoryArea, TAG_MAREA);
+
+   DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
+
+   return STATUS_SUCCESS;
 }
 
-PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
-                              PMADDRESS_SPACE AddressSpace,
-                              PMEMORY_AREA OriginalMemoryArea,
-                              PVOID BaseAddress,
-                              ULONG Length,
-                              ULONG NewType,
-                              ULONG NewAttributes)
+/**
+ * @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 STDCALL
+MmFreeMemoryAreaByPtr(
+   PMADDRESS_SPACE AddressSpace,
+   PVOID BaseAddress,
+   PMM_FREE_PAGE_FUNC FreePage,
+   PVOID FreePageContext)
 {
-   PMEMORY_AREA Result;
-   PMEMORY_AREA Split;
-   
-   Result = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
-   RtlZeroMemory(Result,sizeof(MEMORY_AREA));
-   Result->Type = NewType;
-   Result->BaseAddress = BaseAddress;
-   Result->Length = Length;
-   Result->Attributes = NewAttributes;
-   Result->LockCount = 0;
-   Result->Process = Process;
-   
-   if (BaseAddress == OriginalMemoryArea->BaseAddress)
-     {
-       OriginalMemoryArea->BaseAddress = BaseAddress + Length;
-       OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
-       MmInsertMemoryArea(AddressSpace, Result);
-       return(Result);
-     }
-   if ((BaseAddress + Length) == 
-       (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
-     {
-       OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length; 
-       MmInsertMemoryArea(AddressSpace, Result);
-
-       return(Result);
-     }
-      
-   Split = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
-   RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
-   Split->BaseAddress = BaseAddress + Length;
-   Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress) 
-                                                + Length);
-   
-   OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
-      
-   return(Split);
+   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(0);
+      return(STATUS_UNSUCCESSFUL);
+   }
+
+   return MmFreeMemoryArea(AddressSpace, MemoryArea, FreePage, FreePageContext);
 }
 
-NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
-                           PMADDRESS_SPACE AddressSpace,
-                           ULONG Type,
-                           PVOID* BaseAddress,
-                           ULONG Length,
-                           ULONG Attributes,
-                           MEMORY_AREA** Result)
-/*
- * FUNCTION: Create a memory area
- * ARGUMENTS:
- *     AddressSpace = Address space to create the area in
- *     Type = Type of the address space
- *     BaseAddress = 
- *     Length = Length to allocate
- *     Attributes = Protection attributes for the memory area
- *     Result = Receives a pointer to the memory area on exit
- * RETURNS: Status
- * NOTES: Lock the address space before calling this function
+/**
+ * @name MmCreateMemoryArea
+ *
+ * Create a memory area.
+ *
+ * @param AddressSpace
+ *        Address space to create the area in.
+ * @param Type
+ *        Type of the memory area.
+ * @param BaseAddress
+ *        Base address for the memory area we're about the create. On
+ *        input it contains either 0 (auto-assign address) or preferred
+ *        address. On output it contains the starting address of the
+ *        newly created area.
+ * @param Length
+ *        Length of the area to allocate.
+ * @param Attributes
+ *        Protection attributes for the memory area.
+ * @param Result
+ *        Receives a pointer to the memory area on successful exit.
+ *
+ * @return Status
+ *
+ * @remarks Lock the address space before calling this function.
  */
+
+NTSTATUS STDCALL
+MmCreateMemoryArea(PMADDRESS_SPACE AddressSpace,
+                   ULONG Type,
+                   PVOID *BaseAddress,
+                   ULONG_PTR Length,
+                   ULONG Protect,
+                   PMEMORY_AREA *Result,
+                   BOOLEAN FixedAddress,
+                   ULONG AllocationFlags,
+                   PHYSICAL_ADDRESS BoundaryAddressMultiple)
 {
-   DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
-          "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
-          Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
-
-   if ((*BaseAddress)==0)
-     {
-       *BaseAddress = MmFindGap(AddressSpace,
-                                PAGE_ROUND_UP(Length) +(PAGESIZE*2));
-       if ((*BaseAddress)==0)
-         {
-            DPRINT("No suitable gap\n");
-            return(STATUS_UNSUCCESSFUL);
-         }
-       (*BaseAddress)=(*BaseAddress)+PAGESIZE;
-     }
+   PVOID EndAddress;
+   ULONG Granularity;
+   ULONG tmpLength;
+   PMEMORY_AREA MemoryArea;
+
+   DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
+          "*BaseAddress %p, Length %p, Attributes %x, TopDown: %x, "
+          "FixedAddress %x, Result %p)\n",
+          Type, BaseAddress, *BaseAddress, Length, Attributes, TopDown,
+          FixedAddress, Result);
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
+   if ((*BaseAddress) == 0 && !FixedAddress)
+   {
+      tmpLength = PAGE_ROUND_UP(Length);
+      *BaseAddress = MmFindGap(AddressSpace,
+                               tmpLength,
+                               Granularity,
+                               (AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN);
+      if ((*BaseAddress) == 0)
+      {
+         DPRINT("No suitable gap\n");
+         return STATUS_NO_MEMORY;
+      }
+   }
    else
-     {
-       (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
-       if (MmOpenMemoryAreaByRegion(AddressSpace,
-                                    *BaseAddress,
-                                    Length)!=NULL)
-         {
-            DPRINT("Memory area already occupied\n");
-            return(STATUS_UNSUCCESSFUL);
-         }
-     }
-   
-   *Result = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
-   RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
-   (*Result)->Type = Type;
-   (*Result)->BaseAddress = *BaseAddress;
-   (*Result)->Length = Length;
-   (*Result)->Attributes = Attributes;
-   (*Result)->LockCount = 0;
-   (*Result)->Process = Process;
-   
-   MmInsertMemoryArea(AddressSpace, *Result);
-   
-   DPRINT("MmCreateMemoryArea() succeeded\n");
-   return(STATUS_SUCCESS);
+   {
+      tmpLength = Length + ((ULONG_PTR) *BaseAddress
+                         - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
+      *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
+
+      if (AddressSpace->LowestAddress == MmSystemRangeStart &&
+          *BaseAddress < MmSystemRangeStart)
+      {
+         CHECKPOINT;
+         return STATUS_ACCESS_VIOLATION;
+      }
+
+      if (AddressSpace->LowestAddress < MmSystemRangeStart &&
+          (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
+      {
+         CHECKPOINT;
+         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)
+      {
+         DPRINT("Memory area already occupied\n");
+         return STATUS_CONFLICTING_ADDRESSES;
+      }
+   }
+
+   MemoryArea = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
+                                      TAG_MAREA);
+   RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
+   MemoryArea->Type = Type;
+   MemoryArea->StartingAddress = *BaseAddress;
+   MemoryArea->EndingAddress = (PVOID)((ULONG_PTR)*BaseAddress + tmpLength);
+   MemoryArea->Protect = Protect;
+   MemoryArea->Flags = AllocationFlags;
+   MemoryArea->LockCount = 0;
+   MemoryArea->PageOpCount = 0;
+   MemoryArea->DeleteInProgress = FALSE;
+
+   MmInsertMemoryArea(AddressSpace, MemoryArea);
+
+   *Result = MemoryArea;
+
+   DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress);
+   return STATUS_SUCCESS;
+}
+
+
+VOID STDCALL
+MmReleaseMemoryAreaIfDecommitted(PROS_EPROCESS Process,
+                                 PMADDRESS_SPACE AddressSpace,
+                                 PVOID BaseAddress)
+{
+   PMEMORY_AREA MemoryArea;
+   PLIST_ENTRY Entry;
+   PMM_REGION Region;
+   BOOLEAN Reserved;
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   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;
+      }
+
+      if (Reserved)
+      {
+         MmFreeVirtualMemory(Process, MemoryArea);
+      }
+   }
 }
+
+/* EOF */