[NTOS][USERSRV] Silence noisy debug output.
[reactos.git] / ntoskrnl / mm / ARM3 / vadnode.c
index 402b4c6..1dab4ef 100644 (file)
 #include <debug.h>
 
 #define MODULE_INVOLVED_IN_ARM3
-#include "../ARM3/miarm.h"
+#include <mm/ARM3/miarm.h>
 
 /* Include Mm version of AVL support */
-#include "../ARM3/miavl.h"
-#include "../../../lib/rtl/avlsupp.c"
+#include "miavl.h"
+#include <sdk/lib/rtl/avlsupp.c>
 
 /* GLOBALS ********************************************************************/
 
@@ -73,22 +73,25 @@ MiLocateAddress(IN PVOID VirtualAddress)
     return FoundVad;
 }
 
-PMMADDRESS_NODE
+TABLE_SEARCH_RESULT
 NTAPI
 MiCheckForConflictingNode(IN ULONG_PTR StartVpn,
                           IN ULONG_PTR EndVpn,
-                          IN PMM_AVL_TABLE Table)
+                          IN PMM_AVL_TABLE Table,
+                          OUT PMMADDRESS_NODE *NodeOrParent)
 {
-    PMMADDRESS_NODE CurrentNode;
+    PMMADDRESS_NODE ParentNode, CurrentNode;
 
     /* If the tree is empty, there is no conflict */
-    if (!Table->NumberGenericTableElements) return NULL;
+    if (Table->NumberGenericTableElements == 0) return TableEmptyTree;
 
-    /* Start looping from the right */
+    /* Start looping from the root node */
     CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
     ASSERT(CurrentNode != NULL);
     while (CurrentNode)
     {
+        ParentNode = CurrentNode;
+
         /* This address comes after */
         if (StartVpn > CurrentNode->EndingVpn)
         {
@@ -103,12 +106,21 @@ MiCheckForConflictingNode(IN ULONG_PTR StartVpn,
         else
         {
             /* This address is part of this node, return it */
-            break;
+            *NodeOrParent = ParentNode;
+            return TableFoundNode;
         }
     }
 
-    /* Return either the conflicting node, or no node at all */
-    return CurrentNode;
+    /* There is no more child, save the current node as parent */
+    *NodeOrParent = ParentNode;
+    if (StartVpn > ParentNode->EndingVpn)
+    {
+        return TableInsertAsRight;
+    }
+    else
+    {
+        return TableInsertAsLeft;
+    }
 }
 
 VOID
@@ -134,13 +146,19 @@ MiInsertNode(IN PMM_AVL_TABLE Table,
         PVOID AllocatedBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT);
 
         Size = ((Vad->EndingVpn + 1) - Vad->StartingVpn) << PAGE_SHIFT;
+
+        if (AllocatedBase == NULL)
+        {
+            AllocatedBase = (PVOID)(ULONG_PTR)1;
+            Size -= 1;
+        }
+
         Status = MmCreateMemoryArea(&Process->Vm,
                                     MEMORY_AREA_OWNED_BY_ARM3,
                                     &AllocatedBase,
                                     Size,
                                     PAGE_READWRITE,
                                     &MemoryArea,
-                                    TRUE,
                                     0,
                                     PAGE_SIZE);
         ASSERT(NT_SUCCESS(Status));
@@ -154,7 +172,7 @@ MiInsertNode(IN PMM_AVL_TABLE Table,
         else
         {
             /* This is a section VAD. Store the MAREA here for now */
-            ASSERT(Vad->u4.Banked == (PVOID)0xDEADBABE);
+            ASSERT(Vad->u4.Banked == (PVOID)(ULONG_PTR)0xDEADBABEDEADBABEULL);
             Vad->u4.Banked = (PVOID)MemoryArea;
         }
     }
@@ -163,22 +181,163 @@ MiInsertNode(IN PMM_AVL_TABLE Table,
 VOID
 NTAPI
 MiInsertVad(IN PMMVAD Vad,
-            IN PEPROCESS Process)
+            IN PMM_AVL_TABLE VadRoot)
 {
     TABLE_SEARCH_RESULT Result;
     PMMADDRESS_NODE Parent = NULL;
 
     /* Validate the VAD and set it as the current hint */
     ASSERT(Vad->EndingVpn >= Vad->StartingVpn);
-    Process->VadRoot.NodeHint = Vad;
+    VadRoot->NodeHint = Vad;
 
     /* Find the parent VAD and where this child should be inserted */
-    Result = RtlpFindAvlTableNodeOrParent(&Process->VadRoot, (PVOID)Vad->StartingVpn, &Parent);
+    Result = RtlpFindAvlTableNodeOrParent(VadRoot, (PVOID)Vad->StartingVpn, &Parent);
     ASSERT(Result != TableFoundNode);
     ASSERT((Parent != NULL) || (Result == TableEmptyTree));
 
     /* Do the actual insert operation */
-    MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
+    MiInsertNode(VadRoot, (PVOID)Vad, Parent, Result);
+}
+
+NTSTATUS
+NTAPI
+MiInsertVadEx(
+    _Inout_ PMMVAD Vad,
+    _In_ ULONG_PTR *BaseAddress,
+    _In_ SIZE_T ViewSize,
+    _In_ ULONG_PTR HighestAddress,
+    _In_ ULONG_PTR Alignment,
+    _In_ ULONG AllocationType)
+{
+    ULONG_PTR StartingAddress, EndingAddress;
+    PEPROCESS CurrentProcess;
+    PETHREAD CurrentThread;
+    TABLE_SEARCH_RESULT Result;
+    PMMADDRESS_NODE Parent;
+
+    /* Align the view size to pages */
+    ViewSize = ALIGN_UP_BY(ViewSize, PAGE_SIZE);
+
+    /* Get the current process */
+    CurrentProcess = PsGetCurrentProcess();
+
+    /* Acquire the address creation lock and make sure the process is alive */
+    KeAcquireGuardedMutex(&CurrentProcess->AddressCreationLock);
+    if (CurrentProcess->VmDeleted)
+    {
+        KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
+        DPRINT1("The process is dying\n");
+        return STATUS_PROCESS_IS_TERMINATING;
+    }
+
+    /* Did the caller specify an address? */
+    if (*BaseAddress == 0)
+    {
+        /* Make sure HighestAddress is not too large */
+        HighestAddress = min(HighestAddress, (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS);
+
+        /* Which way should we search? */
+        if ((AllocationType & MEM_TOP_DOWN) || CurrentProcess->VmTopDown)
+        {
+            /* Find an address top-down */
+            Result = MiFindEmptyAddressRangeDownTree(ViewSize,
+                                                     HighestAddress,
+                                                     Alignment,
+                                                     &CurrentProcess->VadRoot,
+                                                     &StartingAddress,
+                                                     &Parent);
+        }
+        else
+        {
+            /* Find an address bottom-up */
+            Result = MiFindEmptyAddressRangeInTree(ViewSize,
+                                                   Alignment,
+                                                   &CurrentProcess->VadRoot,
+                                                   &Parent,
+                                                   &StartingAddress);
+        }
+
+        /* Get the ending address, which is the last piece we need for the VAD */
+        EndingAddress = StartingAddress + ViewSize - 1;
+
+        /* Check if we found a suitable location */
+        if ((Result == TableFoundNode) || (EndingAddress > HighestAddress))
+        {
+            DPRINT1("Not enough free space to insert this VAD node!\n");
+            KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
+            return STATUS_NO_MEMORY;
+        }
+
+        ASSERT(StartingAddress != 0);
+        ASSERT(StartingAddress < (ULONG_PTR)HighestAddress);
+        ASSERT(EndingAddress > StartingAddress);
+    }
+    else
+    {
+        /* Calculate the starting and ending address */
+        StartingAddress = ALIGN_DOWN_BY(*BaseAddress, Alignment);
+        EndingAddress = StartingAddress + ViewSize - 1;
+
+        /* Make sure it doesn't conflict with an existing allocation */
+        Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
+                                           EndingAddress >> PAGE_SHIFT,
+                                           &CurrentProcess->VadRoot,
+                                           &Parent);
+        if (Result == TableFoundNode)
+        {
+            DPRINT("Given address conflicts with existing node\n");
+            KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
+            return STATUS_CONFLICTING_ADDRESSES;
+        }
+    }
+
+    /* Now set the VAD address */
+    Vad->StartingVpn = StartingAddress >> PAGE_SHIFT;
+    Vad->EndingVpn = EndingAddress >> PAGE_SHIFT;
+
+    /* Check if we already need to charge for the pages */
+    if ((Vad->u.VadFlags.PrivateMemory && Vad->u.VadFlags.MemCommit) ||
+        (!Vad->u.VadFlags.PrivateMemory &&
+         (Vad->u.VadFlags.Protection & PAGE_WRITECOPY)))
+    {
+        /* Set the commit charge */
+        Vad->u.VadFlags.CommitCharge = ViewSize / PAGE_SIZE;
+    }
+
+    /* Check if the VAD is to be secured */
+    if (Vad->u2.VadFlags2.OneSecured)
+    {
+        /* This *must* be a long VAD! */
+        ASSERT(Vad->u2.VadFlags2.LongVad);
+
+        /* Yeah this is retarded, I didn't invent it! */
+        ((PMMVAD_LONG)Vad)->u3.Secured.StartVpn = StartingAddress;
+        ((PMMVAD_LONG)Vad)->u3.Secured.EndVpn = EndingAddress;
+    }
+
+    /* Lock the working set */
+    CurrentThread = PsGetCurrentThread();
+    MiLockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
+
+    /* Insert the VAD */
+    CurrentProcess->VadRoot.NodeHint = Vad;
+    MiInsertNode(&CurrentProcess->VadRoot, (PVOID)Vad, Parent, Result);
+
+    /* Release the working set */
+    MiUnlockProcessWorkingSetUnsafe(CurrentProcess, CurrentThread);
+
+    /* Update the process' virtual size, and peak virtual size */
+    CurrentProcess->VirtualSize += ViewSize;
+    if (CurrentProcess->VirtualSize > CurrentProcess->PeakVirtualSize)
+    {
+        CurrentProcess->PeakVirtualSize = CurrentProcess->VirtualSize;
+    }
+
+    /* Unlock the address space */
+    KeReleaseGuardedMutex(&CurrentProcess->AddressCreationLock);
+
+    *BaseAddress = StartingAddress;
+    return STATUS_SUCCESS;
 }
 
 VOID
@@ -219,7 +378,7 @@ MiRemoveNode(IN PMMADDRESS_NODE Node,
 
     /* Free the node from ReactOS view as well */
     Vad = (PMMVAD_LONG)Node;
-    if (Vad->u.VadFlags.Spare == 0)
+    if ((Table != &MmSectionBasedRoot) && (Vad->u.VadFlags.Spare == 0))
     {
         PMEMORY_AREA MemoryArea;
         PEPROCESS Process;
@@ -240,7 +399,7 @@ MiRemoveNode(IN PMMADDRESS_NODE Node,
         if (MemoryArea)
         {
             /* Make sure we have not already freed it */
-            ASSERT(MemoryArea != (PVOID)0xDEADBAB1);
+            ASSERT(MemoryArea != (PVOID)(ULONG_PTR)0xDEADBAB1DEADBAB1ULL);
 
             /* Get the process */
             Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot);
@@ -256,12 +415,12 @@ MiRemoveNode(IN PMMADDRESS_NODE Node,
             if (Vad->ControlArea == NULL)
             {
                 /* Delete the pointer to it */
-                Vad->FirstPrototypePte = (PVOID)0xDEADBAB1;
+                Vad->FirstPrototypePte = (PVOID)(ULONG_PTR)0xDEADBAB1DEADBAB1ULL;
             }
             else
             {
                 /* Delete the pointer to it */
-                Vad->u4.Banked = (PVOID)0xDEADBAB1;
+                Vad->u4.Banked = (PVOID)(ULONG_PTR)0xDEADBAB1DEADBAB1ULL;
             }
         }
     }
@@ -338,7 +497,7 @@ MiGetNextNode(IN PMMADDRESS_NODE Node)
     return NULL;
 }
 
-NTSTATUS
+TABLE_SEARCH_RESULT
 NTAPI
 MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
                               IN ULONG_PTR Alignment,
@@ -346,67 +505,91 @@ MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
                               OUT PMMADDRESS_NODE *PreviousVad,
                               OUT PULONG_PTR Base)
 {
-    PMMADDRESS_NODE Node;
-    PMMADDRESS_NODE NextNode;
-    ULONG_PTR StartingVpn, HighestVpn, AlignmentVpn, LengthVpn, LowVpn;
+    PMMADDRESS_NODE Node, PreviousNode;
+    ULONG_PTR PageCount, AlignmentVpn, LowVpn, HighestVpn;
     ASSERT(Length != 0);
 
-    /* Precompute page numbers for the length, alignment, and starting address */
-    LengthVpn = (Length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+    /* Calculate page numbers for the length, alignment, and starting address */
+    PageCount = BYTES_TO_PAGES(Length);
     AlignmentVpn = Alignment >> PAGE_SHIFT;
-    StartingVpn = ROUND_UP((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT,
-                           AlignmentVpn);
+    LowVpn = ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT, AlignmentVpn);
+
+    /* Check for kernel mode table (memory areas) */
+    if (Table->Unused == 1)
+    {
+        LowVpn = ALIGN_UP_BY((ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT, AlignmentVpn);
+    }
 
-    /* Check if the table is free, so the lowest possible address is available */
-    if (!Table->NumberGenericTableElements) goto FoundAtBottom;
+    /* Check if the table is empty */
+    if (Table->NumberGenericTableElements == 0)
+    {
+        /* Tree is empty, the candidate address is already the best one */
+        *Base = LowVpn << PAGE_SHIFT;
+        return TableEmptyTree;
+    }
 
     /* Otherwise, follow the leftmost child of the right root node's child */
     Node = RtlRightChildAvl(&Table->BalancedRoot);
     while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node);
 
-    /* This is the node for the remaining gap at the bottom, can it be used? */
-    if ((Node->StartingVpn > StartingVpn) &&
-        (LengthVpn < Node->StartingVpn - StartingVpn))
+    /* Start a search to find a gap */
+    PreviousNode = NULL;
+    while (Node != NULL)
     {
-FoundAtBottom:
-        /* Use this VAD to store the allocation */
-        *PreviousVad = NULL;
-        *Base = StartingVpn << PAGE_SHIFT;
-        return STATUS_SUCCESS;
-    }
+        /* Check if the gap below the current node is suitable */
+        if (Node->StartingVpn >= LowVpn + PageCount)
+        {
+            /* There is enough space to add our node */
+            *Base = LowVpn << PAGE_SHIFT;
 
-    /* Otherwise, we start a search to find a gap */
-    while (TRUE)
-    {
-        /* The last aligned page number in this entry */
-        LowVpn = ROUND_UP(Node->EndingVpn + 1, AlignmentVpn);
+            /* Can we use the current node as parent? */
+            if (RtlLeftChildAvl(Node) == NULL)
+            {
+                /* Node has no left child, so use it as parent */
+                *PreviousVad = Node;
+                return TableInsertAsLeft;
+            }
+            else
+            {
+                /* Node has a left child, this means that the previous node is
+                   the right-most child of it's left child and can be used as
+                   the parent. In case we use the space before the left-most
+                   node, it's left child must be NULL. */
+                ASSERT(PreviousNode != NULL);
+                ASSERT(RtlRightChildAvl(PreviousNode) == NULL);
+                *PreviousVad = PreviousNode;
+                return TableInsertAsRight;
+            }
+        }
 
-        /* Keep going as long as there's still a next node */
-        NextNode = MiGetNextNode(Node);
-        if (!NextNode) break;
+        /* The next candidate is above the current node */
+        if (Node->EndingVpn >= LowVpn)
+            LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
 
-        /* Can this allocation fit in this node? */
-        if ((LengthVpn <= (NextNode->StartingVpn - LowVpn)) &&
-            (NextNode->StartingVpn > LowVpn))
-        {
-Found:
-            /* Yes! Use this VAD to store the allocation */
-            *PreviousVad = Node;
-            *Base = ROUND_UP((Node->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1),
-                             Alignment);
-            return STATUS_SUCCESS;
-        }
+        /* Remember the current node and go to the next node */
+        PreviousNode = Node;
+        Node = MiGetNextNode(Node);
+    }
 
-        /* Try the next node */
-        Node = NextNode;
+    /* We're up to the highest VAD, will this allocation fit above it? */
+    HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) / PAGE_SIZE;
+
+    /* Check for kernel mode table (memory areas) */
+    if (Table->Unused == 1)
+    {
+        HighestVpn = ALIGN_UP_BY((ULONG_PTR)(LONG_PTR)-1 >> PAGE_SHIFT, AlignmentVpn);
     }
 
-    /* We're down to the last (top) VAD, will this allocation fit inside it? */
-    HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) >> PAGE_SHIFT;
-    if ((HighestVpn > LowVpn) && (LengthVpn <= HighestVpn - LowVpn)) goto Found;
+    if (HighestVpn >= LowVpn + PageCount)
+    {
+        /* Yes! Use this VAD to store the allocation */
+        *PreviousVad = PreviousNode;
+        *Base = LowVpn << PAGE_SHIFT;
+        return TableInsertAsRight;
+    }
 
     /* Nyet, there's no free address space for this allocation, so we'll fail */
-    return STATUS_NO_MEMORY;
+    return TableFoundNode;
 }
 
 TABLE_SEARCH_RESULT
@@ -418,55 +601,68 @@ MiFindEmptyAddressRangeDownTree(IN SIZE_T Length,
                                 OUT PULONG_PTR Base,
                                 OUT PMMADDRESS_NODE *Parent)
 {
-    PMMADDRESS_NODE Node, LowestNode, Child;
-    ULONG_PTR LowVpn, HighVpn;
+    PMMADDRESS_NODE Node, OldNode = NULL, Child;
+    ULONG_PTR LowVpn, HighVpn, AlignmentVpn;
     PFN_NUMBER PageCount;
 
     /* Sanity checks */
     ASSERT(BoundaryAddress);
-    ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
+    ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS));
+    ASSERT((Alignment & (PAGE_SIZE - 1)) == 0);
 
-    /* Compute page length, make sure the boundary address is valid */
+    /* Calculate page numbers for the length and alignment */
     Length = ROUND_TO_PAGES(Length);
     PageCount = Length >> PAGE_SHIFT;
-    if ((BoundaryAddress + 1) < Length) return TableFoundNode;
+    AlignmentVpn = Alignment / PAGE_SIZE;
+
+    /* Check for kernel mode table (memory areas) */
+    if (Table->Unused == 1)
+    {
+        LowVpn = ALIGN_UP_BY((ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT, AlignmentVpn);
+    }
+    else
+    {
+        LowVpn = ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS, Alignment);
+    }
+
+    /* Check if there is enough space below the boundary */
+    if ((LowVpn + Length) > (BoundaryAddress + 1))
+    {
+        return TableFoundNode;
+    }
 
     /* Check if the table is empty */
     if (Table->NumberGenericTableElements == 0)
     {
         /* Tree is empty, the candidate address is already the best one */
-        *Base = ROUND_UP(BoundaryAddress + 1 - Length, Alignment);
+        *Base = ALIGN_DOWN_BY(BoundaryAddress + 1 - Length, Alignment);
         return TableEmptyTree;
     }
 
     /* Calculate the initial upper margin */
-    HighVpn = BoundaryAddress >> PAGE_SHIFT;
+    HighVpn = (BoundaryAddress + 1) >> PAGE_SHIFT;
 
-    /* Starting from the root, go down until the right-most child
-     * which is just behind the boundary*/
-    LowestNode = Node = RtlRightChildAvl(&Table->BalancedRoot);
-    while (((Child = RtlRightChildAvl(Node)) != 0 )
-            && (Node->EndingVpn < HighVpn )) Node = Child;
+    /* Starting from the root, follow the right children until we found a node
+       that ends above the boundary */
+    Node = RtlRightChildAvl(&Table->BalancedRoot);
+    while ((Node->EndingVpn < HighVpn) &&
+           ((Child = RtlRightChildAvl(Node)) != NULL)) Node = Child;
 
     /* Now loop the Vad nodes */
     while (Node)
     {
-        /* Keep track of the lowest node */
-        LowestNode = Node;
-
         /* Calculate the lower margin */
-        LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment >> PAGE_SHIFT);
+        LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
 
         /* Check if the current bounds are suitable */
         if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
         {
             /* There is enough space to add our node */
-            LowVpn = HighVpn - PageCount;
+            LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, AlignmentVpn);
             *Base = LowVpn << PAGE_SHIFT;
 
             /* Can we use the current node as parent? */
-            Child = RtlRightChildAvl(Node);
-            if (!Child)
+            if (!RtlRightChildAvl(Node))
             {
                 /* Node has no right child, so use it as parent */
                 *Parent = Node;
@@ -474,29 +670,35 @@ MiFindEmptyAddressRangeDownTree(IN SIZE_T Length,
             }
             else
             {
-                /* Node has a right child, find most left grand child */
-                Node = Child;
-                while ((Child = RtlLeftChildAvl(Node))) Node = Child;
-                *Parent = Node;
+                /* Node has a right child. This means we must have already
+                   moved one node left from the right-most node we started
+                   with, thus we already have an OldNode! */
+                ASSERT(OldNode != NULL);
+
+                /* The node we had before is the most left grandchild of 
+                   that right child, use it as parent. */
+                ASSERT(RtlLeftChildAvl(OldNode) == NULL);
+                *Parent = OldNode;
                 return TableInsertAsLeft;
             }
         }
 
-        /* Update the upper margin if neccessary */
+        /* Update the upper margin if necessary */
         if (Node->StartingVpn < HighVpn) HighVpn = Node->StartingVpn;
 
-        /* Go to the next lower node */
+        /* Remember the current node and go to the previous node */
+        OldNode = Node;
         Node = MiGetPreviousNode(Node);
     }
 
     /* Check if there's enough space before the lowest Vad */
-    LowVpn = ROUND_UP((ULONG_PTR)MI_LOWEST_VAD_ADDRESS, Alignment) >> PAGE_SHIFT;
+    LowVpn = ALIGN_UP_BY((ULONG_PTR)MI_LOWEST_VAD_ADDRESS, Alignment) / PAGE_SIZE;
     if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
     {
         /* There is enough space to add our address */
-        LowVpn = HighVpn - PageCount;
+        LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, Alignment >> PAGE_SHIFT);
         *Base = LowVpn << PAGE_SHIFT;
-        *Parent = LowestNode;
+        *Parent = OldNode;
         return TableInsertAsLeft;
     }
 
@@ -527,7 +729,7 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
     if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY;
 
     /* Check if the table is empty */
-    BestVpn = ROUND_UP(BoundaryAddress + 1 - Length, Alignment);
+    BestVpn = ROUND_DOWN(BoundaryAddress + 1 - Length, Alignment);
     if (Table->NumberGenericTableElements == 0)
     {
         /* Tree is empty, the candidate address is already the best one */
@@ -540,11 +742,18 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
     while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node);
 
     /* Check if we can fit in here */
-    LowVpn = ROUND_UP(Node->EndingVpn, Alignment);
-    if ((LowVpn < BoundaryAddress) && (Length < (BoundaryAddress - LowVpn)))
+    LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment);
+    if ((LowVpn < BoundaryAddress) && (Length <= (BoundaryAddress - LowVpn)))
     {
-        /* Return the address */
-        *Base = ROUND_UP(BoundaryAddress - Length, Alignment);
+#if (NTDDI_VERSION >= NTDDI_VISTA)
+        /* Return the address. */
+        *Base = BestVpn;
+#else
+        /* Note: this is a compatibility hack that mimics a bug in the 2k3
+           kernel. It will can waste up to Alignment bytes of memory above
+           the allocation. This bug was fixed in Windows Vista */
+        *Base = ROUND_DOWN(BoundaryAddress - Length, Alignment);
+#endif
         return STATUS_SUCCESS;
     }
 
@@ -558,22 +767,20 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
         /* Check if this node could contain the requested address */
         LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment);
         if ((LowestNode->EndingVpn < BestVpn) &&
+            (LowVpn < Node->StartingVpn) &&
             (Length <= (Node->StartingVpn - LowVpn)))
         {
-            /* Check if it fits in perfectly */
-            if ((BestVpn > LowestNode->EndingVpn) &&
-                (BoundaryAddress < Node->StartingVpn))
+            /* Check if we need to take BoundaryAddress into account */
+            if (BoundaryAddress < Node->StartingVpn)
             {
                 /* Return the optimal VPN address */
                 *Base = BestVpn;
                 return STATUS_SUCCESS;
             }
-
-            /* It doesn't, check if it can partly fit */
-            if (Node->StartingVpn > LowVpn)
+            else
             {
-                /* Return an aligned base address within this node */
-                *Base = ROUND_UP(Node->StartingVpn - Length, Alignment);
+                /* The upper margin is given by the Node's starting address */
+                *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
                 return STATUS_SUCCESS;
             }
         }
@@ -584,7 +791,7 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
 
     /* Check if there's enough space before the lowest Vad */
     if ((Node->StartingVpn > (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) &&
-        ((Node->StartingVpn - (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) > Length))
+        ((Node->StartingVpn - (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) >= Length))
     {
         /* Check if it fits in perfectly */
         if (BoundaryAddress < Node->StartingVpn)
@@ -595,7 +802,7 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
         }
 
         /* Return an aligned base address within this node */
-        *Base = ROUND_UP(Node->StartingVpn - Length, Alignment);
+        *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
         return STATUS_SUCCESS;
     }
 
@@ -669,3 +876,4 @@ MiCheckSecuredVad(IN PMMVAD Vad,
 }
 
 /* EOF */
+