- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / mm / marea.c
index 04913eb..a031f64 100644 (file)
@@ -1,28 +1,43 @@
-/*
- *  ReactOS kernel
- *  Copyright (C) 1998, 1999, 2000, 2001, 2003 ReactOS Team
- *
- *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
+/* $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 *****************************************************************/
 #define NDEBUG
 #include <internal/debug.h>
 
-/* GLOBALS *******************************************************************/
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, MmInitMemoryAreas)
+#endif
 
-#define TAG_MAREA   TAG('M', 'A', 'R', 'E')
+/* #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)
 {
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
+   while (Node->LeftChild != NULL)
+      Node = Node->LeftChild;
 
-   DbgPrint("MmDumpMemoryAreas()\n");
+   return Node;
+}
+
+/**
+ * @name MmIterateNextNode
+ *
+ * @param Node
+ *        Current node in the tree.
+ *
+ * @return Next node in the tree (sorted by address).
+ */
 
-   current_entry = ListHead->Flink;
-   while (current_entry!=ListHead)
+static PMEMORY_AREA MmIterateNextNode(PMEMORY_AREA Node)
+{
+   if (Node->RightChild != NULL)
    {
-      current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-      DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
-               current->BaseAddress,current->Length,
-               (char*)current->BaseAddress+current->Length,current->Attributes,
-               current->Entry.Flink);
-      current_entry = current_entry->Flink;
+      Node = Node->RightChild;
+      while (Node->LeftChild != NULL)
+         Node = Node->LeftChild;
    }
-   DbgPrint("Finished MmDumpMemoryAreas()\n");
+   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;
 }
 
-MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
-                                       PVOID Address)
+/**
+ * @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)
 {
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   PLIST_ENTRY previous_entry;
+   while (Node->RightChild != NULL)
+      Node = Node->RightChild;
+
+   return Node;
+}
 
-   DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
-          AddressSpace, Address);
+/**
+ * @name MmIteratePreviousNode
+ *
+ * @param Node
+ *        Current node in the tree.
+ *
+ * @return Previous node in the tree (sorted by address).
+ */
 
-   previous_entry = &AddressSpace->MAreaListHead;
-   current_entry = AddressSpace->MAreaListHead.Flink;
-   while (current_entry != &AddressSpace->MAreaListHead)
+static PMEMORY_AREA MmIteratePrevNode(PMEMORY_AREA Node)
+{
+   if (Node->LeftChild != NULL)
    {
-      current = CONTAINING_RECORD(current_entry,
-                                  MEMORY_AREA,
-                                  Entry);
-      assert(current_entry->Blink->Flink == current_entry);
-      assert(current_entry->Flink->Blink == current_entry);
-      assert(previous_entry->Flink == current_entry);
-      if (current->BaseAddress <= Address &&
-            (PVOID)((char*)current->BaseAddress + current->Length) > Address)
-      {
-         DPRINT("%s() = %x\n",__FUNCTION__,current);
-         return(current);
-      }
-      if (current->BaseAddress > Address)
+      Node = Node->LeftChild;
+      while (Node->RightChild != NULL)
+         Node = Node->RightChild;
+   }
+   else
+   {
+      PMEMORY_AREA TempNode = NULL;
+
+      do
       {
-         DPRINT("%s() = NULL\n",__FUNCTION__);
-         return(NULL);
+         /* Check if we're at the end of tree. */
+         if (Node->Parent == NULL)
+            return NULL;
+
+         TempNode = Node;
+         Node = Node->Parent;
       }
-      previous_entry = current_entry;
-      current_entry = current_entry->Flink;
+      while (TempNode == Node->LeftChild);
    }
-   DPRINT("%s() = NULL\n",__FUNCTION__);
-   return(NULL);
+   return Node;
 }
 
-MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
-                                      PVOID Address,
-                                      ULONG Length)
+#ifdef VALIDATE_MEMORY_AREAS
+static VOID MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace)
 {
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   ULONG Extent;
+   PMEMORY_AREA Node;
 
-   DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
-          AddressSpace, Address, Length);
+   ASSERT(AddressSpace != NULL);
+
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+      return;
 
-   current_entry = AddressSpace->MAreaListHead.Flink;
-   while (current_entry != &AddressSpace->MAreaListHead)
+   /* Traverse the tree from left to right. */
+   for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+        Node != NULL;
+        Node = MmIterateNextNode(Node))
    {
-      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 < (PVOID)((char*)Address+Length))
-      {
-         DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
-                current);
-         return(current);
-      }
-      Extent = (ULONG)current->BaseAddress + current->Length;
-      if (Extent > (ULONG)Address &&
-            Extent < (ULONG)((char*)Address+Length))
-      {
-         DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
-                current);
-         return(current);
-      }
-      if (current->BaseAddress <= Address &&
-            Extent >= (ULONG)((char*)Address+Length))
-      {
-         DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
-                current);
-         return(current);
-      }
-      if (current->BaseAddress >= (PVOID)((char*)Address+Length))
-      {
-         DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
-         return(NULL);
-      }
-      current_entry = current_entry->Flink;
+      /* 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);
    }
-   DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
-   return(NULL);
 }
+#else
+#define MmVerifyMemoryAreas(x)
+#endif
 
-static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
-                               MEMORY_AREA* marea)
+VOID STDCALL
+MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace)
 {
-   PLIST_ENTRY ListHead;
-   PLIST_ENTRY current_entry;
-   PLIST_ENTRY inserted_entry = &marea->Entry;
-   MEMORY_AREA* current;
-   MEMORY_AREA* next;
+   PMEMORY_AREA Node;
 
-   DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
-   DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
-   DPRINT("marea->Length %x\n", marea->Length);
+   DbgPrint("MmDumpMemoryAreas()\n");
 
-   ListHead = &AddressSpace->MAreaListHead;
+   /* Special case for empty tree. */
+   if (AddressSpace->MemoryAreaRoot == NULL)
+      return;
 
-   current_entry = ListHead->Flink;
-   if (IsListEmpty(ListHead))
+   /* Traverse the tree from left to right. */
+   for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+        Node != NULL;
+        Node = MmIterateNextNode(Node))
    {
-      InsertHeadList(ListHead,&marea->Entry);
-      return;
+      DbgPrint("Start %p End %p Protect %x Flags %x\n",
+               Node->StartingAddress, Node->EndingAddress,
+               Node->Protect, Node->Flags);
    }
-   current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-   if (current->BaseAddress > marea->BaseAddress)
+
+   DbgPrint("Finished MmDumpMemoryAreas()\n");
+}
+
+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)
    {
-      InsertHeadList(ListHead,&marea->Entry);
-      return;
+      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;
+      }
    }
-   while (current_entry->Flink!=ListHead)
+
+   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))
    {
-      current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-      next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
-      if (current->BaseAddress < marea->BaseAddress &&
-            current->Entry.Flink==ListHead)
+      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)
       {
-         current_entry->Flink = inserted_entry;
-         inserted_entry->Flink=ListHead;
-         inserted_entry->Blink=current_entry;
-         ListHead->Blink = inserted_entry;
-         return;
+         DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
+                Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
+                Node->EndingAddress);
+         return Node;
       }
-      if (current->BaseAddress < marea->BaseAddress &&
-            next->BaseAddress > marea->BaseAddress)
+      if (Node->StartingAddress <= Address &&
+          Node->EndingAddress >= Extent)
       {
-         inserted_entry->Flink = current_entry->Flink;
-         inserted_entry->Blink = current_entry;
-         inserted_entry->Flink->Blink = inserted_entry;
-         current_entry->Flink=inserted_entry;
-         return;
+         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;
       }
-      current_entry = current_entry->Flink;
    }
-   InsertTailList(ListHead,inserted_entry);
+
+   return NULL;
 }
 
+/**
+ * @name MmCompressHelper
+ *
+ * This is helper of MmRebalanceTree. Performs a compression transformation
+ * count times, starting at root.
+ */
 
-PVOID MmFindGapBottomUp(PMADDRESS_SPACE AddressSpace, ULONG Length)
+static VOID
+MmCompressHelper(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG Count)
 {
-   PLIST_ENTRY ListHead;
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   MEMORY_AREA* next;
-   ULONG Gap;
-   PVOID Address;
+   PMEMORY_AREA Root = NULL;
+   PMEMORY_AREA Red = AddressSpace->MemoryAreaRoot;
+   PMEMORY_AREA Black = Red->LeftChild;
 
-   DPRINT("MmFindGapBottomUp(Length %x)\n",Length);
+   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;
+      }
+   }
+}
 
-   ListHead = &AddressSpace->MAreaListHead;
+/**
+ * @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/)
+ */
 
-   current_entry = ListHead->Flink;
-   while (current_entry->Flink!=ListHead)
+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)
    {
-      current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-      next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
-      Gap = (char*)next->BaseAddress - ((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
-      if (Gap >= Length)
+      if (CurrentNode->RightChild == NULL)
+      {
+         PreviousNode = CurrentNode;
+         CurrentNode = CurrentNode->LeftChild;
+         NodeCount++;
+      }
+      else
       {
-         return((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
+         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;
       }
-      current_entry = current_entry->Flink;
    }
 
-   if (current_entry == ListHead)
+   /* Transform Vine back into a balanced tree. */
+
+   Leaves = NodeCount + 1;
+   for (;;)
    {
-      Address = (PVOID)AddressSpace->LowestAddress;
+      ULONG Next = Leaves & (Leaves - 1);
+      if (Next == 0)
+         break;
+      Leaves = Next;
    }
-   else
+   Leaves = NodeCount + 1 - Leaves;
+
+   MmCompressHelper(AddressSpace, Leaves);
+
+   Vine = NodeCount - Leaves;
+   Height = 1 + (Leaves > 0);
+   while (Vine > 1)
    {
-      current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-      Address = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
+      MmCompressHelper(AddressSpace, Vine / 2);
+      Vine /= 2;
+      Height++;
    }
-   /* Check if enough space for the block */
-   if (AddressSpace->LowestAddress < KERNEL_BASE)
+}
+
+static VOID
+MmInsertMemoryArea(
+   PMADDRESS_SPACE AddressSpace,
+   PMEMORY_AREA marea)
+{
+   PMEMORY_AREA Node;
+   PMEMORY_AREA PreviousNode;
+   ULONG Depth = 0;
+
+   MmVerifyMemoryAreas(AddressSpace);
+
+   if (AddressSpace->MemoryAreaRoot == NULL)
    {
-      if ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
-      {
-         return NULL;
-      }
+      AddressSpace->MemoryAreaRoot = marea;
+      marea->LeftChild = marea->RightChild = marea->Parent = NULL;
+      return;
    }
-   else
+
+   Node = AddressSpace->MemoryAreaRoot;
+   do
    {
-      if (Length >= 0xFFFFFFFF - (ULONG)Address)
+      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)
       {
-         return NULL;
+         Depth++;
+         if (Depth == 22)
+         {
+            MmRebalanceTree(AddressSpace);
+            PreviousNode = Node->Parent;
+         }
       }
    }
-   return Address;
-}
+   while (Node != NULL);
 
+   marea->LeftChild = marea->RightChild = NULL;
+   marea->Parent = PreviousNode;
+   if (marea->StartingAddress < PreviousNode->StartingAddress)
+      PreviousNode->LeftChild = marea;
+   else
+      PreviousNode->RightChild = marea;
+}
 
-PVOID MmFindGapTopDown(PMADDRESS_SPACE AddressSpace, ULONG Length)
+static PVOID
+MmFindGapBottomUp(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG_PTR Length,
+   ULONG_PTR Granularity)
 {
-   PLIST_ENTRY ListHead;
-   PLIST_ENTRY current_entry;
-   MEMORY_AREA* current;
-   ULONG Gap;
-   PVOID Address;
-   PVOID TopAddress;
-   PVOID BottomAddress;
-   PVOID HighestAddress;
+   PVOID HighestAddress = AddressSpace->LowestAddress < MmSystemRangeStart ?
+                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
+   PVOID AlignedAddress;
+   PMEMORY_AREA Node;
+   PMEMORY_AREA FirstNode;
+   PMEMORY_AREA PreviousNode;
 
-   DPRINT("MmFindGapTopDown(Length %lx)\n",Length);
+   MmVerifyMemoryAreas(AddressSpace);
 
-   if (AddressSpace->LowestAddress < KERNEL_BASE) //(ULONG_PTR)MmSystemRangeStart)
-   {
-      HighestAddress = MmHighestUserAddress;
-   }
-   else
+   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)
    {
-      HighestAddress = (PVOID)0xFFFFFFFF;
+      if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
+      {
+         DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
+         return AlignedAddress;
+      }
+      DPRINT("MmFindGapBottomUp: 0\n");
+      return 0;
    }
 
-   TopAddress = HighestAddress;
+   /* Go to the node with lowest address in the tree. */
+   FirstNode = Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
 
-   ListHead = &AddressSpace->MAreaListHead;
-   current_entry = ListHead->Blink;
-   while (current_entry->Blink != ListHead)
+   /* Traverse the tree from left to right. */
+   PreviousNode = Node;
+   for (;;)
    {
-      current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-      BottomAddress = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
-      DPRINT("Base %p  Length %lx\n", current->BaseAddress, PAGE_ROUND_UP(current->Length));
+      Node = MmIterateNextNode(Node);
+      if (Node == NULL)
+         break;
 
-      if (BottomAddress < HighestAddress)
+      AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
+      if (Node->StartingAddress > AlignedAddress &&
+          (ULONG_PTR)Node->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
       {
-         Gap = (char*)TopAddress - (char*)BottomAddress + 1;
-         DPRINT("Bottom %p  Top %p  Gap %lx\n", BottomAddress, TopAddress, Gap);
-         if (Gap >= Length)
-         {
-            DPRINT("Found gap at %p\n", (char*)TopAddress - Length);
-            return((char*)TopAddress - Length + 1);
-         }
-         TopAddress = (char*)current->BaseAddress - 1;
+         DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
+         return AlignedAddress;
       }
-      current_entry = current_entry->Blink;
+
+      PreviousNode = Node;
    }
 
-   if (current_entry == ListHead)
+   /* 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)
    {
-      Address = (char*)HighestAddress - Length + 1;
+      DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
+      return AlignedAddress;
    }
-   else
+
+   /* 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)
    {
-      Address = (char*)TopAddress - Length + 1;
+      DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
+      return AlignedAddress;
    }
 
-   /* Check if enough space for the block */
-   if (AddressSpace->LowestAddress < KERNEL_BASE)
+   DPRINT("MmFindGapBottomUp: 0\n");
+   return 0;
+}
+
+
+static PVOID
+MmFindGapTopDown(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG_PTR Length,
+   ULONG_PTR Granularity)
+{
+   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 ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
+      if (AlignedAddress >= (PVOID)AddressSpace->LowestAddress)
       {
-         DPRINT("Failed to find gap\n");
-         return NULL;
+         DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
+         return AlignedAddress;
       }
+      DPRINT("MmFindGapTopDown: 0\n");
+      return 0;
    }
-   else
+
+   /* 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)
    {
-      if (Length >= 0xFFFFFFFF - (ULONG)Address)
-      {
-         DPRINT("Failed to find gap\n");
+      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;
    }
 
-   DPRINT("Found gap at %p\n", Address);
-   return Address;
+   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;
 }
 
 
-PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length, BOOL TopDown)
+PVOID STDCALL
+MmFindGap(
+   PMADDRESS_SPACE AddressSpace,
+   ULONG_PTR Length,
+   ULONG_PTR Granularity,
+   BOOLEAN TopDown)
 {
    if (TopDown)
-      return MmFindGapTopDown(AddressSpace, Length);
+      return MmFindGapTopDown(AddressSpace, Length, Granularity);
 
-   return MmFindGapBottomUp(AddressSpace, Length);
+   return MmFindGapBottomUp(AddressSpace, Length, Granularity);
 }
 
-ULONG MmFindGapAtAddress(PMADDRESS_SPACE AddressSpace, PVOID Address)
+ULONG_PTR STDCALL
+MmFindGapAtAddress(
+   PMADDRESS_SPACE AddressSpace,
+   PVOID Address)
 {
-   PLIST_ENTRY current_entry, ListHead;
-   PMEMORY_AREA current;
+   PMEMORY_AREA Node = AddressSpace->MemoryAreaRoot;
+   PMEMORY_AREA RightNeighbour = NULL;
+   PVOID HighestAddress = AddressSpace->LowestAddress < MmSystemRangeStart ?
+                          (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
 
-   Address = (PVOID)PAGE_ROUND_DOWN(Address);
+   MmVerifyMemoryAreas(AddressSpace);
 
-   if (AddressSpace->LowestAddress < KERNEL_BASE)
+   Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
+
+   if (AddressSpace->LowestAddress < MmSystemRangeStart)
    {
-      if (Address >= (PVOID)KERNEL_BASE)
+      if (Address >= MmSystemRangeStart)
       {
          return 0;
       }
    }
    else
    {
-      if ((ULONG_PTR)Address < AddressSpace->LowestAddress)
+      if (Address < AddressSpace->LowestAddress)
       {
          return 0;
       }
    }
 
-   ListHead = &AddressSpace->MAreaListHead;
-
-   current_entry = ListHead->Flink;
-   while (current_entry != ListHead)
+   while (Node != NULL)
    {
-      current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
-      if (current->BaseAddress <= Address && (char*)Address < (char*)current->BaseAddress + current->Length)
+      if (Address < Node->StartingAddress)
       {
-         return 0;
+         RightNeighbour = Node;
+         Node = Node->LeftChild;
+      }
+      else if (Address >= Node->EndingAddress)
+      {
+         Node = Node->RightChild;
       }
-      else if (current->BaseAddress > Address)
+      else
       {
-         return (ULONG_PTR)current->BaseAddress - (ULONG_PTR)Address;
+         DPRINT("MmFindGapAtAddress: 0\n");
+         return 0;
       }
-      current_entry = current_entry->Flink;
    }
-   if (AddressSpace->LowestAddress < KERNEL_BASE)
+
+   if (RightNeighbour)
    {
-      return KERNEL_BASE - (ULONG_PTR)Address;
+      DPRINT("MmFindGapAtAddress: %p [%p]\n", Address,
+             (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address);
+      return (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address;
    }
    else
    {
-      return 0 - (ULONG_PTR)Address;
+      DPRINT("MmFindGapAtAddress: %p [%p]\n", Address,
+             (ULONG_PTR)HighestAddress - (ULONG_PTR)Address);
+      return (ULONG_PTR)HighestAddress - (ULONG_PTR)Address;
    }
 }
 
-NTSTATUS INIT_FUNCTION
-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, MEMORY_AREA* MemoryArea,
-                                  PVOID Address, PFN_TYPE Page,
-                                  SWAPENTRY SwapEntry, BOOLEAN Dirty),
-                 PVOID FreePageContext)
-{
-   MEMORY_AREA* MemoryArea;
-   char* Address;
-   char* EndAddress;
-   PEPROCESS CurrentProcess = PsGetCurrentProcess();
 
-   DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
-          "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
-          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)
+{
+   PMEMORY_AREA *ParentReplace;
+   ULONG_PTR Address;
+   PVOID EndAddress;
+   PROS_EPROCESS CurrentProcess = (PROS_EPROCESS)PsGetCurrentProcess();
 
-   MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
-                                          BaseAddress);
-   if (MemoryArea == NULL)
-   {
-      KEBUGCHECK(0);
-      return(STATUS_UNSUCCESSFUL);
-   }
    if (AddressSpace->Process != NULL &&
-         AddressSpace->Process != CurrentProcess)
+       AddressSpace->Process != CurrentProcess)
    {
-      KeAttachProcess(AddressSpace->Process);
+      KeAttachProcess(&AddressSpace->Process->Pcb);
    }
-   EndAddress = (char*)MemoryArea->BaseAddress + PAGE_ROUND_UP(MemoryArea->Length); 
-   for (Address = MemoryArea->BaseAddress; Address < EndAddress; Address += PAGE_SIZE)
-   {
 
+   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(Address);
+         MmRawDeleteVirtualMapping((PVOID)Address);
       }
       else
       {
-        BOOL Dirty = FALSE;
+         BOOLEAN Dirty = FALSE;
          SWAPENTRY SwapEntry = 0;
-        PFN_TYPE Page = 0;
-
+         PFN_TYPE Page = 0;
 
-         if (MmIsPageSwapEntry(AddressSpace->Process, Address))
+         if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)Address))
          {
-            MmDeletePageFileMapping(AddressSpace->Process, Address, &SwapEntry);
+            MmDeletePageFileMapping(AddressSpace->Process, (PVOID)Address, &SwapEntry);
          }
          else
          {
-            MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, &Dirty, &Page);
+            MmDeleteVirtualMapping(AddressSpace->Process, (PVOID)Address, FALSE, &Dirty, &Page);
          }
          if (FreePage != NULL)
          {
-            FreePage(FreePageContext, MemoryArea, Address, 
-                    Page, SwapEntry, (BOOLEAN)Dirty);
+            FreePage(FreePageContext, MemoryArea, (PVOID)Address,
+                     Page, SwapEntry, (BOOLEAN)Dirty);
          }
       }
    }
+
    if (AddressSpace->Process != NULL &&
-         AddressSpace->Process != CurrentProcess)
+       AddressSpace->Process != CurrentProcess)
    {
       KeDetachProcess();
    }
-   RemoveEntryList(&MemoryArea->Entry);
-   ExFreePool(MemoryArea);
 
-   DPRINT("MmFreeMemoryArea() succeeded\n");
+   /* 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);
 
-   return(STATUS_SUCCESS);
+   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;
+   PMEMORY_AREA MemoryArea;
 
-   Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
-                                  TAG_MAREA);
-   RtlZeroMemory(Result,sizeof(MEMORY_AREA));
-   Result->Type = NewType;
-   Result->BaseAddress = BaseAddress;
-   Result->Length = Length;
-   Result->Attributes = NewAttributes;
-   Result->LockCount = 0;
-   Result->Process = Process;
+   DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
+          "FreePageContext %p)\n", AddressSpace, BaseAddress,
+          FreePageContext);
 
-   if (BaseAddress == OriginalMemoryArea->BaseAddress)
-   {
-      OriginalMemoryArea->BaseAddress = (char*)BaseAddress + Length;
-      OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
-      MmInsertMemoryArea(AddressSpace, Result);
-      return(Result);
-   }
-   if (((char*)BaseAddress + Length) ==
-         ((char*)OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
-   {
-      OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
-      MmInsertMemoryArea(AddressSpace, Result);
+   MmVerifyMemoryAreas(AddressSpace);
 
-      return(Result);
+   MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
+                                            BaseAddress);
+   if (MemoryArea == NULL)
+   {
+      KEBUGCHECK(0);
+      return(STATUS_UNSUCCESSFUL);
    }
 
-   Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
-                                 TAG_MAREA);
-   RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
-   Split->BaseAddress = (char*)BaseAddress + Length;
-   Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
-                   + Length);
-
-   OriginalMemoryArea->Length = (char*)BaseAddress - (char*)OriginalMemoryArea->BaseAddress;
-
-   return(Split);
+   return MmFreeMemoryArea(AddressSpace, MemoryArea, FreePage, FreePageContext);
 }
 
-NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
-                            PMADDRESS_SPACE AddressSpace,
-                            ULONG Type,
-                            PVOID* BaseAddress,
-                            ULONG Length,
-                            ULONG Attributes,
-                            MEMORY_AREA** Result,
-                            BOOL FixedAddress,
-                            BOOL TopDown,
-                            PHYSICAL_ADDRESS BoundaryAddressMultiple)
-/*
- * 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)
 {
    PVOID EndAddress;
+   ULONG Granularity;
    ULONG tmpLength;
-   DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
-          "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
-          Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
+   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,
-                               PAGE_ROUND_UP(Length) +(PAGE_SIZE*2),
-                               TopDown);
+                               tmpLength,
+                               Granularity,
+                               (AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN);
       if ((*BaseAddress) == 0)
       {
          DPRINT("No suitable gap\n");
-         return(STATUS_NO_MEMORY);
-      }
-#if defined(__GNUC__)
-      (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
-#else
-
-      {
-         char* pTemp = *BaseAddress;
-         pTemp += PAGE_SIZE;
-         *BaseAddress = pTemp;
+         return STATUS_NO_MEMORY;
       }
-#endif
-
    }
    else
    {
-      tmpLength = (ULONG)*BaseAddress + Length - PAGE_ROUND_DOWN((*BaseAddress));
-      (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
+      tmpLength = Length + ((ULONG_PTR) *BaseAddress
+                         - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
+      *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
 
-      if (AddressSpace->LowestAddress == KERNEL_BASE &&
-            (*BaseAddress) < (PVOID)KERNEL_BASE)
+      if (AddressSpace->LowestAddress == MmSystemRangeStart &&
+          *BaseAddress < MmSystemRangeStart)
       {
+         CHECKPOINT;
          return STATUS_ACCESS_VIOLATION;
       }
 
-      if (AddressSpace->LowestAddress < KERNEL_BASE &&
-            (PVOID)((char*)(*BaseAddress) + tmpLength) > (PVOID)KERNEL_BASE)
+      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(((DWORD_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
+         ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
       }
 
-      if (MmOpenMemoryAreaByRegion(AddressSpace,
-                                   *BaseAddress,
-                                   tmpLength)!=NULL)
+      if (MmLocateMemoryAreaByRegion(AddressSpace,
+                                     *BaseAddress,
+                                     tmpLength) != NULL)
       {
          DPRINT("Memory area already occupied\n");
-         return(STATUS_CONFLICTING_ADDRESSES);
+         return STATUS_CONFLICTING_ADDRESSES;
       }
    }
 
-   *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
-                                   TAG_MAREA);
-   RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
-   (*Result)->Type = Type;
-   (*Result)->BaseAddress = *BaseAddress;
-   (*Result)->Length = tmpLength;
-   (*Result)->Attributes = Attributes;
-   (*Result)->LockCount = 0;
-   (*Result)->Process = Process;
-   (*Result)->PageOpCount = 0;
-   (*Result)->DeleteInProgress = FALSE;
+   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, *Result);
+   MmInsertMemoryArea(AddressSpace, MemoryArea);
 
-   DPRINT("MmCreateMemoryArea() succeeded\n");
-   return(STATUS_SUCCESS);
+   *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 */