[NTOSKRNL]

Add a tiny hack to MiFindEmptyAddressRangeInTree and MiFindEmptyAddressRangeDownTree to support VADs in the kernel VA range. Make MmFindGap use those functions to look for free space.

svn path=/trunk/; revision=67797
This commit is contained in:
Timo Kreuzer 2015-05-17 00:35:37 +00:00
parent c6d5bbaa74
commit c7d21f63c2
2 changed files with 69 additions and 150 deletions

View file

@ -506,7 +506,7 @@ MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
OUT PULONG_PTR Base) OUT PULONG_PTR Base)
{ {
PMMADDRESS_NODE Node, PreviousNode; PMMADDRESS_NODE Node, PreviousNode;
ULONG_PTR PageCount, AlignmentVpn, LowVpn, HighVpn; ULONG_PTR PageCount, AlignmentVpn, LowVpn, HighestVpn;
ASSERT(Length != 0); ASSERT(Length != 0);
/* Calculate page numbers for the length, alignment, and starting address */ /* Calculate page numbers for the length, alignment, and starting address */
@ -514,6 +514,12 @@ MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
AlignmentVpn = Alignment >> PAGE_SHIFT; AlignmentVpn = Alignment >> PAGE_SHIFT;
LowVpn = ALIGN_UP_BY((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 empty */ /* Check if the table is empty */
if (Table->NumberGenericTableElements == 0) if (Table->NumberGenericTableElements == 0)
{ {
@ -566,8 +572,15 @@ MiFindEmptyAddressRangeInTree(IN SIZE_T Length,
} }
/* We're up to the highest VAD, will this allocation fit above it? */ /* We're up to the highest VAD, will this allocation fit above it? */
HighVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) / PAGE_SIZE; HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) / PAGE_SIZE;
if (HighVpn >= LowVpn + PageCount)
/* Check for kernel mode table (memory areas) */
if (Table->Unused == 1)
{
HighestVpn = ALIGN_UP_BY((ULONG_PTR)(LONG_PTR)-1 >> PAGE_SHIFT, AlignmentVpn);
}
if (HighestVpn >= LowVpn + PageCount)
{ {
/* Yes! Use this VAD to store the allocation */ /* Yes! Use this VAD to store the allocation */
*PreviousVad = PreviousNode; *PreviousVad = PreviousNode;
@ -602,9 +615,18 @@ MiFindEmptyAddressRangeDownTree(IN SIZE_T Length,
PageCount = Length >> PAGE_SHIFT; PageCount = Length >> PAGE_SHIFT;
AlignmentVpn = Alignment / PAGE_SIZE; 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 */ /* Check if there is enough space below the boundary */
if ((ALIGN_UP_BY((ULONG_PTR)MM_LOWEST_USER_ADDRESS, Alignment) + Length) > if ((LowVpn + Length) > (BoundaryAddress + 1))
(BoundaryAddress + 1))
{ {
return TableFoundNode; return TableFoundNode;
} }

View file

@ -455,6 +455,7 @@ MmInsertMemoryArea(
/* Build a lame VAD if this is a user-space allocation */ /* Build a lame VAD if this is a user-space allocation */
if (MA_GetEndingAddress(marea) < (ULONG_PTR)MmSystemRangeStart) if (MA_GetEndingAddress(marea) < (ULONG_PTR)MmSystemRangeStart)
{ {
ASSERT(Process != NULL);
if (marea->Type != MEMORY_AREA_OWNED_BY_ARM3) if (marea->Type != MEMORY_AREA_OWNED_BY_ARM3)
{ {
ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE); ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE);
@ -468,9 +469,12 @@ MmInsertMemoryArea(
} }
else else
{ {
ASSERT(Process == NULL);
if (!MiRosKernelVadRootInitialized) if (!MiRosKernelVadRootInitialized)
{ {
MiRosKernelVadRoot.BalancedRoot.u1.Parent = &MiRosKernelVadRoot.BalancedRoot; MiRosKernelVadRoot.BalancedRoot.u1.Parent = &MiRosKernelVadRoot.BalancedRoot;
MiRosKernelVadRoot.Unused = 1;
MiRosKernelVadRootInitialized = TRUE; MiRosKernelVadRootInitialized = TRUE;
} }
@ -526,148 +530,6 @@ MmInsertMemoryArea(
PreviousNode->RightChild = marea; PreviousNode->RightChild = marea;
} }
static PVOID
MmFindGapBottomUp(
PMMSUPPORT AddressSpace,
ULONG_PTR Length,
ULONG_PTR Granularity)
{
ULONG_PTR LowestAddress, HighestAddress, Candidate;
PMEMORY_AREA Root, Node;
/* Get the margins of the address space */
if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
{
LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
HighestAddress = (ULONG_PTR)MmHighestUserAddress;
}
else
{
LowestAddress = (ULONG_PTR)MmSystemRangeStart;
HighestAddress = MAXULONG_PTR;
}
/* Start with the lowest address */
Candidate = LowestAddress;
/* Check for overflow */
if ((Candidate + Length) < Candidate) return NULL;
/* Get the root of the address space tree */
Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
/* Go to the node with lowest address in the tree. */
Node = Root ? MmIterateFirstNode(Root) : NULL;
while (Node && ((ULONG_PTR)MA_GetEndingAddress(Node) < LowestAddress))
{
Node = MmIterateNextNode(Node);
}
/* Traverse the tree from low to high addresses */
while (Node && ((ULONG_PTR)MA_GetEndingAddress(Node) < HighestAddress))
{
/* Check if the memory area fits before the current node */
if (MA_GetStartingAddress(Node) >= (Candidate + Length))
{
DPRINT("MmFindGapBottomUp: %p\n", Candidate);
ASSERT(Candidate >= LowestAddress);
return (PVOID)Candidate;
}
/* Calculate next possible adress above this node */
Candidate = ALIGN_UP_BY((ULONG_PTR)MA_GetEndingAddress(Node), Granularity);
/* Check for overflow */
if ((Candidate + Length) < (ULONG_PTR)MA_GetEndingAddress(Node)) return NULL;
/* Go to the next higher node */
Node = MmIterateNextNode(Node);
}
/* Check if there is enough space after the last memory area. */
if ((Candidate + Length) <= HighestAddress)
{
DPRINT("MmFindGapBottomUp: %p\n", Candidate);
ASSERT(Candidate >= LowestAddress);
return (PVOID)Candidate;
}
DPRINT("MmFindGapBottomUp: 0\n");
return NULL;
}
static PVOID
MmFindGapTopDown(
PMMSUPPORT AddressSpace,
ULONG_PTR Length,
ULONG_PTR Granularity)
{
ULONG_PTR LowestAddress, HighestAddress, Candidate;
PMEMORY_AREA Root, Node;
/* Get the margins of the address space */
if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
{
LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
HighestAddress = (ULONG_PTR)MmHighestUserAddress;
}
else
{
LowestAddress = (ULONG_PTR)MmSystemRangeStart;
HighestAddress = MAXULONG_PTR;
}
/* Calculate the highest candidate */
Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity);
/* Check for overflow. */
if (Candidate > HighestAddress) return NULL;
/* Get the root of the address space tree */
Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
/* Go to the node with highest address in the tree. */
Node = Root ? MmIterateLastNode(Root) : NULL;
while (Node && (MA_GetStartingAddress(Node) > HighestAddress))
{
Node = MmIteratePrevNode(Node);
}
/* Traverse the tree from high to low addresses */
while (Node && (MA_GetStartingAddress(Node) > LowestAddress))
{
/* Check if the memory area fits after the current node */
if ((ULONG_PTR)MA_GetEndingAddress(Node) <= Candidate)
{
DPRINT("MmFindGapTopDown: %p\n", Candidate);
return (PVOID)Candidate;
}
/* Calculate next possible adress below this node */
Candidate = ALIGN_DOWN_BY(MA_GetStartingAddress(Node) - Length,
Granularity);
/* Check for overflow. */
if (Candidate > MA_GetStartingAddress(Node))
return NULL;
/* Go to the next lower node */
Node = MmIteratePrevNode(Node);
}
/* Check if the last candidate is inside the given range */
if (Candidate >= LowestAddress)
{
DPRINT("MmFindGapTopDown: %p\n", Candidate);
return (PVOID)Candidate;
}
DPRINT("MmFindGapTopDown: 0\n");
return NULL;
}
PVOID NTAPI PVOID NTAPI
MmFindGap( MmFindGap(
PMMSUPPORT AddressSpace, PMMSUPPORT AddressSpace,
@ -675,10 +537,45 @@ MmFindGap(
ULONG_PTR Granularity, ULONG_PTR Granularity,
BOOLEAN TopDown) BOOLEAN TopDown)
{ {
if (TopDown) PEPROCESS Process;
return MmFindGapTopDown(AddressSpace, Length, Granularity); PMM_AVL_TABLE VadRoot;
TABLE_SEARCH_RESULT Result;
PMMADDRESS_NODE Parent;
ULONG_PTR StartingAddress, HighestAddress;
return MmFindGapBottomUp(AddressSpace, Length, Granularity); Process = MmGetAddressSpaceOwner(AddressSpace);
VadRoot = Process ? &Process->VadRoot : &MiRosKernelVadRoot;
if (TopDown)
{
/* Find an address top-down */
HighestAddress = Process ? (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS : (LONG_PTR)-1;
Result = MiFindEmptyAddressRangeDownTree(Length,
HighestAddress,
Granularity,
VadRoot,
&StartingAddress,
&Parent);
if (Result == TableFoundNode)
{
return NULL;
}
return (PVOID)StartingAddress;
}
else
{
Result = MiFindEmptyAddressRangeInTree(Length,
Granularity,
VadRoot,
&Parent,
&StartingAddress);
if (Result == TableFoundNode)
{
return NULL;
}
return (PVOID)StartingAddress;
}
} }
VOID VOID