[NTOSKRNL]

Modify the VAD node code to return a TABLE_SEARCH_RESULT instead of an NTSTATUS, this allows us to avoid a 2nd tree iteration when inserting VADs. Fix several bugs in MiFindEmptyAddressRangeDownBasedTree. This code now contains a compatibility hack, that emulates a bug in the Windows 2003 kernel. Note that this bug is also present in MiFindEmptyAddressRangeDownTree on Windows 2003, but will not be exposed to the user, since it only affects the region above the top-most VAD, which will always be occupied by the PEB or TEB. Implement MEM_TOPDOWN in NtAllocateVirtualMemory. See CORE-6392

svn path=/trunk/; revision=63336
This commit is contained in:
Timo Kreuzer 2014-05-17 20:34:11 +00:00
parent f88752ba0e
commit bef68d6f6c
5 changed files with 206 additions and 133 deletions

View file

@ -2093,12 +2093,13 @@ MiLocateAddress(
IN PVOID VirtualAddress IN PVOID VirtualAddress
); );
PMMADDRESS_NODE TABLE_SEARCH_RESULT
NTAPI NTAPI
MiCheckForConflictingNode( MiCheckForConflictingNode(
IN ULONG_PTR StartVpn, IN ULONG_PTR StartVpn,
IN ULONG_PTR EndVpn, IN ULONG_PTR EndVpn,
IN PMM_AVL_TABLE Table IN PMM_AVL_TABLE Table,
OUT PMMADDRESS_NODE *NodeOrParent
); );
TABLE_SEARCH_RESULT TABLE_SEARCH_RESULT
@ -2122,7 +2123,7 @@ MiFindEmptyAddressRangeDownBasedTree(
OUT PULONG_PTR Base OUT PULONG_PTR Base
); );
NTSTATUS TABLE_SEARCH_RESULT
NTAPI NTAPI
MiFindEmptyAddressRangeInTree( MiFindEmptyAddressRangeInTree(
IN SIZE_T Length, IN SIZE_T Length,

View file

@ -110,7 +110,7 @@ MiCreatePebOrTeb(IN PEPROCESS Process,
{ {
/* For TEBs, or if a PEB location couldn't be found, scan the VAD root */ /* For TEBs, or if a PEB location couldn't be found, scan the VAD root */
Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size), Result = MiFindEmptyAddressRangeDownTree(ROUND_TO_PAGES(Size),
(ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1, (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
PAGE_SIZE, PAGE_SIZE,
&Process->VadRoot, &Process->VadRoot,
Base, Base,

View file

@ -1214,6 +1214,8 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
ULONG QuotaCharge = 0, QuotaExcess = 0; ULONG QuotaCharge = 0, QuotaExcess = 0;
PMMPTE PointerPte, LastPte; PMMPTE PointerPte, LastPte;
MMPTE TempPte; MMPTE TempPte;
PMMADDRESS_NODE Parent;
TABLE_SEARCH_RESULT Result;
/* Get the segment for this section */ /* Get the segment for this section */
Segment = ControlArea->Segment; Segment = ControlArea->Segment;
@ -1302,23 +1304,29 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
if (AllocationType & MEM_TOP_DOWN) if (AllocationType & MEM_TOP_DOWN)
{ {
/* No, find an address top-down */ /* No, find an address top-down */
Status = MiFindEmptyAddressRangeDownTree(*ViewSize, Result = MiFindEmptyAddressRangeDownTree(*ViewSize,
(ULONG_PTR)MM_HIGHEST_VAD_ADDRESS, (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
_64K, _64K,
&Process->VadRoot, &Process->VadRoot,
&StartAddress, &StartAddress,
(PMMADDRESS_NODE*)&Process->VadFreeHint); &Parent);
ASSERT(NT_SUCCESS(Status));
} }
else else
{ {
/* No, find an address bottom-up */ /* No, find an address bottom-up */
Status = MiFindEmptyAddressRangeInTree(*ViewSize, Result = MiFindEmptyAddressRangeInTree(*ViewSize,
_64K, _64K,
&Process->VadRoot, &Process->VadRoot,
(PMMADDRESS_NODE*)&Process->VadFreeHint, &Parent,
&StartAddress); &StartAddress);
ASSERT(NT_SUCCESS(Status)); }
/* Check if we found a suitable location */
if (Result == TableFoundNode)
{
DPRINT1("Not enough free space to insert this section!\n");
MiDereferenceControlArea(ControlArea);
return STATUS_CONFLICTING_ADDRESSES;
} }
/* Get the ending address, which is the last piece we need for the VAD */ /* Get the ending address, which is the last piece we need for the VAD */
@ -1343,9 +1351,11 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1); EndingAddress = (StartAddress + *ViewSize - 1) | (PAGE_SIZE - 1);
/* Make sure it doesn't conflict with an existing allocation */ /* Make sure it doesn't conflict with an existing allocation */
if (MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT, Result = MiCheckForConflictingNode(StartAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT, EndingAddress >> PAGE_SHIFT,
&Process->VadRoot)) &Process->VadRoot,
&Parent);
if (Result == TableFoundNode)
{ {
DPRINT1("Conflict with SEC_BASED or manually based section!\n"); DPRINT1("Conflict with SEC_BASED or manually based section!\n");
MiDereferenceControlArea(ControlArea); MiDereferenceControlArea(ControlArea);
@ -1395,7 +1405,8 @@ MiMapViewOfDataSection(IN PCONTROL_AREA ControlArea,
MiLockProcessWorkingSetUnsafe(Process, Thread); MiLockProcessWorkingSetUnsafe(Process, Thread);
/* Insert the VAD */ /* Insert the VAD */
MiInsertVad((PMMVAD)Vad, Process); Process->VadRoot.NodeHint = Vad;
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
/* Release the working set */ /* Release the working set */
MiUnlockProcessWorkingSetUnsafe(Process, Thread); MiUnlockProcessWorkingSetUnsafe(Process, Thread);

View file

@ -73,22 +73,25 @@ MiLocateAddress(IN PVOID VirtualAddress)
return FoundVad; return FoundVad;
} }
PMMADDRESS_NODE TABLE_SEARCH_RESULT
NTAPI NTAPI
MiCheckForConflictingNode(IN ULONG_PTR StartVpn, MiCheckForConflictingNode(IN ULONG_PTR StartVpn,
IN ULONG_PTR EndVpn, 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 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); CurrentNode = RtlRightChildAvl(&Table->BalancedRoot);
ASSERT(CurrentNode != NULL); ASSERT(CurrentNode != NULL);
while (CurrentNode) while (CurrentNode)
{ {
ParentNode = CurrentNode;
/* This address comes after */ /* This address comes after */
if (StartVpn > CurrentNode->EndingVpn) if (StartVpn > CurrentNode->EndingVpn)
{ {
@ -103,12 +106,21 @@ MiCheckForConflictingNode(IN ULONG_PTR StartVpn,
else else
{ {
/* This address is part of this node, return it */ /* This address is part of this node, return it */
break; *NodeOrParent = ParentNode;
return TableFoundNode;
} }
} }
/* Return either the conflicting node, or no node at all */ /* There is no more child, save the current node as parent */
return CurrentNode; *NodeOrParent = ParentNode;
if (StartVpn > ParentNode->EndingVpn)
{
return TableInsertAsRight;
}
else
{
return TableInsertAsLeft;
}
} }
VOID VOID
@ -338,7 +350,7 @@ MiGetNextNode(IN PMMADDRESS_NODE Node)
return NULL; return NULL;
} }
NTSTATUS TABLE_SEARCH_RESULT
NTAPI NTAPI
MiFindEmptyAddressRangeInTree(IN SIZE_T Length, MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
IN ULONG_PTR Alignment, IN ULONG_PTR Alignment,
@ -346,67 +358,78 @@ MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
OUT PMMADDRESS_NODE *PreviousVad, OUT PMMADDRESS_NODE *PreviousVad,
OUT PULONG_PTR Base) OUT PULONG_PTR Base)
{ {
PMMADDRESS_NODE Node; PMMADDRESS_NODE Node, PreviousNode;
PMMADDRESS_NODE NextNode; ULONG_PTR PageCount, AlignmentVpn, LowVpn, HighVpn;
ULONG_PTR StartingVpn, HighestVpn, AlignmentVpn, LengthVpn, LowVpn;
ASSERT(Length != 0); ASSERT(Length != 0);
/* Precompute page numbers for the length, alignment, and starting address */ /* Calculate page numbers for the length, alignment, and starting address */
LengthVpn = (Length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; PageCount = BYTES_TO_PAGES(Length);
AlignmentVpn = Alignment >> PAGE_SHIFT; AlignmentVpn = Alignment >> PAGE_SHIFT;
StartingVpn = ROUND_UP((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT, LowVpn = ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT, AlignmentVpn);
AlignmentVpn);
/* Check if the table is free, so the lowest possible address is available */ /* Check if the table is empty */
if (!Table->NumberGenericTableElements) goto FoundAtBottom; 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 */ /* Otherwise, follow the leftmost child of the right root node's child */
Node = RtlRightChildAvl(&Table->BalancedRoot); Node = RtlRightChildAvl(&Table->BalancedRoot);
while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node); while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node);
/* This is the node for the remaining gap at the bottom, can it be used? */ /* Start a search to find a gap */
if ((Node->StartingVpn > StartingVpn) && PreviousNode = NULL;
(LengthVpn < Node->StartingVpn - StartingVpn)) while (Node != NULL)
{ {
FoundAtBottom: /* Check if the gap below the current node is suitable */
/* Use this VAD to store the allocation */ if (Node->StartingVpn >= LowVpn + PageCount)
*PreviousVad = NULL;
*Base = StartingVpn << PAGE_SHIFT;
return STATUS_SUCCESS;
}
/* Otherwise, we start a search to find a gap */
while (TRUE)
{ {
/* The last aligned page number in this entry */ /* There is enough space to add our node */
LowVpn = ROUND_UP(Node->EndingVpn + 1, AlignmentVpn); *Base = LowVpn << PAGE_SHIFT;
/* Keep going as long as there's still a next node */ /* Can we use the current node as parent? */
NextNode = MiGetNextNode(Node); if (RtlLeftChildAvl(Node) == NULL)
if (!NextNode) break;
/* Can this allocation fit in this node? */
if ((LengthVpn <= (NextNode->StartingVpn - LowVpn)) &&
(NextNode->StartingVpn > LowVpn))
{ {
Found: /* Node has no left child, so use it as parent */
/* Yes! Use this VAD to store the allocation */
*PreviousVad = Node; *PreviousVad = Node;
*Base = ROUND_UP((Node->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1), return TableInsertAsLeft;
Alignment); }
return STATUS_SUCCESS; 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;
}
} }
/* Try the next node */ /* The next candidate is above the current node */
Node = NextNode; if (Node->EndingVpn >= LowVpn)
LowVpn = ALIGN_UP_BY(Node->EndingVpn + 1, AlignmentVpn);
/* Remember the current node and go to the next node */
PreviousNode = Node;
Node = MiGetNextNode(Node);
} }
/* We're down to the last (top) VAD, will this allocation fit inside it? */ /* We're up to the highest VAD, will this allocation fit above it? */
HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) >> PAGE_SHIFT; HighVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) / PAGE_SIZE;
if ((HighestVpn > LowVpn) && (LengthVpn <= HighestVpn - LowVpn)) goto Found; if (HighVpn >= 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 */ /* Nyet, there's no free address space for this allocation, so we'll fail */
return STATUS_NO_MEMORY; return TableFoundNode;
} }
TABLE_SEARCH_RESULT TABLE_SEARCH_RESULT
@ -418,55 +441,59 @@ MiFindEmptyAddressRangeDownTree(IN SIZE_T Length,
OUT PULONG_PTR Base, OUT PULONG_PTR Base,
OUT PMMADDRESS_NODE *Parent) OUT PMMADDRESS_NODE *Parent)
{ {
PMMADDRESS_NODE Node, LowestNode, Child; PMMADDRESS_NODE Node, OldNode, Child;
ULONG_PTR LowVpn, HighVpn; ULONG_PTR LowVpn, HighVpn, AlignmentVpn;
PFN_NUMBER PageCount; PFN_NUMBER PageCount;
/* Sanity checks */ /* Sanity checks */
ASSERT(BoundaryAddress); 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); Length = ROUND_TO_PAGES(Length);
PageCount = Length >> PAGE_SHIFT; PageCount = Length >> PAGE_SHIFT;
if ((BoundaryAddress + 1) < Length) return TableFoundNode; AlignmentVpn = Alignment / PAGE_SIZE;
/* Check if there is enough space below the boundary */
if ((ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS, Alignment) + Length) >
(BoundaryAddress + 1))
{
return TableFoundNode;
}
/* Check if the table is empty */ /* Check if the table is empty */
if (Table->NumberGenericTableElements == 0) if (Table->NumberGenericTableElements == 0)
{ {
/* Tree is empty, the candidate address is already the best one */ /* 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; return TableEmptyTree;
} }
/* Calculate the initial upper margin */ /* 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 /* Starting from the root, follow the right children until we found a node
* which is just behind the boundary*/ that ends above the boundary */
LowestNode = Node = RtlRightChildAvl(&Table->BalancedRoot); Node = RtlRightChildAvl(&Table->BalancedRoot);
while (((Child = RtlRightChildAvl(Node)) != 0 ) while ((Node->EndingVpn < HighVpn) &&
&& (Node->EndingVpn < HighVpn )) Node = Child; ((Child = RtlRightChildAvl(Node)) != NULL)) Node = Child;
/* Now loop the Vad nodes */ /* Now loop the Vad nodes */
while (Node) while (Node)
{ {
/* Keep track of the lowest node */
LowestNode = Node;
/* Calculate the lower margin */ /* 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 */ /* Check if the current bounds are suitable */
if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount)) if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
{ {
/* There is enough space to add our node */ /* There is enough space to add our node */
LowVpn = HighVpn - PageCount; LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, AlignmentVpn);
*Base = LowVpn << PAGE_SHIFT; *Base = LowVpn << PAGE_SHIFT;
/* Can we use the current node as parent? */ /* Can we use the current node as parent? */
Child = RtlRightChildAvl(Node); if (!RtlRightChildAvl(Node))
if (!Child)
{ {
/* Node has no right child, so use it as parent */ /* Node has no right child, so use it as parent */
*Parent = Node; *Parent = Node;
@ -474,29 +501,29 @@ MiFindEmptyAddressRangeDownTree(IN SIZE_T Length,
} }
else else
{ {
/* Node has a right child, find most left grand child */ /* Node has a right child, the node we had before is the most
Node = Child; left grandchild of that right child, use it as parent. */
while ((Child = RtlLeftChildAvl(Node))) Node = Child; *Parent = OldNode;
*Parent = Node;
return TableInsertAsLeft; return TableInsertAsLeft;
} }
} }
/* Update the upper margin if neccessary */ /* Update the upper margin if necessary */
if (Node->StartingVpn < HighVpn) HighVpn = Node->StartingVpn; 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); Node = MiGetPreviousNode(Node);
} }
/* Check if there's enough space before the lowest Vad */ /* 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)) if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount))
{ {
/* There is enough space to add our address */ /* There is enough space to add our address */
LowVpn = HighVpn - PageCount; LowVpn = ALIGN_DOWN_BY(HighVpn - PageCount, Alignment >> PAGE_SHIFT);
*Base = LowVpn << PAGE_SHIFT; *Base = LowVpn << PAGE_SHIFT;
*Parent = LowestNode; *Parent = OldNode;
return TableInsertAsLeft; return TableInsertAsLeft;
} }
@ -527,7 +554,7 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY; if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY;
/* Check if the table is empty */ /* Check if the table is empty */
BestVpn = ROUND_UP(BoundaryAddress + 1 - Length, Alignment); BestVpn = ROUND_DOWN(BoundaryAddress + 1 - Length, Alignment);
if (Table->NumberGenericTableElements == 0) if (Table->NumberGenericTableElements == 0)
{ {
/* Tree is empty, the candidate address is already the best one */ /* Tree is empty, the candidate address is already the best one */
@ -540,11 +567,18 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node); while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node);
/* Check if we can fit in here */ /* Check if we can fit in here */
LowVpn = ROUND_UP(Node->EndingVpn, Alignment); LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment);
if ((LowVpn < BoundaryAddress) && (Length < (BoundaryAddress - LowVpn))) if ((LowVpn < BoundaryAddress) && (Length <= (BoundaryAddress - LowVpn)))
{ {
/* Return the address */ #if (NTDDI_VERSION >= NTDDI_VISTA)
*Base = ROUND_UP(BoundaryAddress - Length, Alignment); /* 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; return STATUS_SUCCESS;
} }
@ -558,22 +592,20 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
/* Check if this node could contain the requested address */ /* Check if this node could contain the requested address */
LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment); LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment);
if ((LowestNode->EndingVpn < BestVpn) && if ((LowestNode->EndingVpn < BestVpn) &&
(LowVpn < Node->StartingVpn) &&
(Length <= (Node->StartingVpn - LowVpn))) (Length <= (Node->StartingVpn - LowVpn)))
{ {
/* Check if it fits in perfectly */ /* Check if we need to take BoundaryAddress into account */
if ((BestVpn > LowestNode->EndingVpn) && if (BoundaryAddress < Node->StartingVpn)
(BoundaryAddress < Node->StartingVpn))
{ {
/* Return the optimal VPN address */ /* Return the optimal VPN address */
*Base = BestVpn; *Base = BestVpn;
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
else
/* It doesn't, check if it can partly fit */
if (Node->StartingVpn > LowVpn)
{ {
/* Return an aligned base address within this node */ /* The upper margin is given by the Node's starting address */
*Base = ROUND_UP(Node->StartingVpn - Length, Alignment); *Base = ROUND_DOWN(Node->StartingVpn - Length, Alignment);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
} }
@ -584,7 +616,7 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
/* Check if there's enough space before the lowest Vad */ /* Check if there's enough space before the lowest Vad */
if ((Node->StartingVpn > (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) && 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 */ /* Check if it fits in perfectly */
if (BoundaryAddress < Node->StartingVpn) if (BoundaryAddress < Node->StartingVpn)
@ -595,7 +627,7 @@ MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length,
} }
/* Return an aligned base address within this node */ /* 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; return STATUS_SUCCESS;
} }
@ -669,3 +701,4 @@ MiCheckSecuredVad(IN PMMVAD Vad,
} }
/* EOF */ /* EOF */

View file

@ -1903,6 +1903,7 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
BOOLEAN Committed; BOOLEAN Committed;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PETHREAD Thread = PsGetCurrentThread(); PETHREAD Thread = PsGetCurrentThread();
TABLE_SEARCH_RESULT Result;
/* Calculate base address for the VAD */ /* Calculate base address for the VAD */
StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress)); StartingAddress = (ULONG_PTR)PAGE_ALIGN((*BaseAddress));
@ -1939,10 +1940,11 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
} }
/* Get the VAD for this address range, and make sure it exists */ /* Get the VAD for this address range, and make sure it exists */
Vad = (PMMVAD)MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT, Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT, EndingAddress >> PAGE_SHIFT,
&Process->VadRoot); &Process->VadRoot,
if (!Vad) (PMMADDRESS_NODE*)&Vad);
if (Result != TableFoundNode)
{ {
DPRINT("Could not find a VAD for this allocation\n"); DPRINT("Could not find a VAD for this allocation\n");
Status = STATUS_CONFLICTING_ADDRESSES; Status = STATUS_CONFLICTING_ADDRESSES;
@ -4099,6 +4101,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
BOOLEAN Attached = FALSE, ChangeProtection = FALSE; BOOLEAN Attached = FALSE, ChangeProtection = FALSE;
MMPTE TempPte; MMPTE TempPte;
PMMPTE PointerPte, PointerPde, LastPte; PMMPTE PointerPte, PointerPde, LastPte;
TABLE_SEARCH_RESULT Result;
PMMADDRESS_NODE Parent;
PAGED_CODE(); PAGED_CODE();
/* Check for valid Zero bits */ /* Check for valid Zero bits */
@ -4384,12 +4388,28 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// //
if (!PBaseAddress) if (!PBaseAddress)
{ {
Status = MiFindEmptyAddressRangeInTree(PRegionSize, /* Which way should we search? */
if (AllocationType & MEM_TOP_DOWN)
{
/* Find an address top-down */
Result = MiFindEmptyAddressRangeDownTree(PRegionSize,
(ULONG_PTR)MM_HIGHEST_VAD_ADDRESS,
_64K, _64K,
&Process->VadRoot, &Process->VadRoot,
(PMMADDRESS_NODE*)&Process->VadFreeHint, &StartingAddress,
&Parent);
}
else
{
/* Find an address bottom-up */
Result = MiFindEmptyAddressRangeInTree(PRegionSize,
_64K,
&Process->VadRoot,
&Parent,
&StartingAddress); &StartingAddress);
if (!NT_SUCCESS(Status)) goto FailPath; }
if (Result == TableFoundNode) goto FailPath;
// //
// Now we know where the allocation ends. Make sure it doesn't end up // Now we know where the allocation ends. Make sure it doesn't end up
@ -4402,9 +4422,14 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
goto FailPath; goto FailPath;
} }
} }
else if (MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT, else
{
/* Make sure it doesn't conflict with an existing allocation */
Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT, EndingAddress >> PAGE_SHIFT,
&Process->VadRoot)) &Process->VadRoot,
&Parent);
if (Result == TableFoundNode)
{ {
// //
// The address specified is in conflict! // The address specified is in conflict!
@ -4412,6 +4437,7 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
Status = STATUS_CONFLICTING_ADDRESSES; Status = STATUS_CONFLICTING_ADDRESSES;
goto FailPath; goto FailPath;
} }
}
// //
// Write out the VAD fields for this allocation // Write out the VAD fields for this allocation
@ -4429,7 +4455,8 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// //
MiLockProcessWorkingSetUnsafe(Process, CurrentThread); MiLockProcessWorkingSetUnsafe(Process, CurrentThread);
Vad->ControlArea = NULL; // For Memory-Area hack Vad->ControlArea = NULL; // For Memory-Area hack
MiInsertVad(Vad, Process); Process->VadRoot.NodeHint = Vad;
MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result);
MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread); MiUnlockProcessWorkingSetUnsafe(Process, CurrentThread);
// //
@ -4495,10 +4522,11 @@ NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
// //
// Get the VAD for this address range, and make sure it exists // Get the VAD for this address range, and make sure it exists
// //
FoundVad = (PMMVAD)MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT, Result = MiCheckForConflictingNode(StartingAddress >> PAGE_SHIFT,
EndingAddress >> PAGE_SHIFT, EndingAddress >> PAGE_SHIFT,
&Process->VadRoot); &Process->VadRoot,
if (!FoundVad) (PMMADDRESS_NODE*)&FoundVad);
if (Result != TableFoundNode)
{ {
DPRINT1("Could not find a VAD for this allocation\n"); DPRINT1("Could not find a VAD for this allocation\n");
Status = STATUS_CONFLICTING_ADDRESSES; Status = STATUS_CONFLICTING_ADDRESSES;