2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/vadnode.c
5 * PURPOSE: ARM Memory Manager VAD Node Algorithms
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
10 /* INCLUDES *******************************************************************/
16 #line 15 "ARMĀ³::VADNODE"
17 #define MODULE_INVOLVED_IN_ARM3
18 #include "../ARM3/miarm.h"
20 /* Include Mm version of AVL support */
21 #include "../ARM3/miavl.h"
22 #include "../../../lib/rtl/avlsupp.c"
24 /* FUNCTIONS ******************************************************************/
28 MiLocateAddress(IN PVOID VirtualAddress
)
32 PMM_AVL_TABLE Table
= &PsGetCurrentProcess()->VadRoot
;
33 TABLE_SEARCH_RESULT SearchResult
;
35 /* Start with the the hint */
36 FoundVad
= (PMMVAD
)Table
->NodeHint
;
37 if (!FoundVad
) return NULL
;
39 /* Check if this VPN is in the hint, if so, use it */
40 Vpn
= (ULONG_PTR
)VirtualAddress
>> PAGE_SHIFT
;
41 if ((Vpn
>= FoundVad
->StartingVpn
) && (Vpn
<= FoundVad
->EndingVpn
)) return FoundVad
;
43 /* VAD hint didn't work, go look for it */
44 SearchResult
= RtlpFindAvlTableNodeOrParent(Table
,
46 (PMMADDRESS_NODE
*)&FoundVad
);
47 if (SearchResult
!= TableFoundNode
) return NULL
;
49 /* We found it, update the hint */
50 ASSERT(FoundVad
!= NULL
);
51 ASSERT((Vpn
>= FoundVad
->StartingVpn
) && (Vpn
<= FoundVad
->EndingVpn
));
52 Table
->NodeHint
= FoundVad
;
58 MiCheckForConflictingNode(IN ULONG_PTR StartVpn
,
60 IN PMM_AVL_TABLE Table
)
62 PMMADDRESS_NODE CurrentNode
;
64 /* If the tree is empty, there is no conflict */
65 if (!Table
->NumberGenericTableElements
) return NULL
;
67 /* Start looping from the right */
68 CurrentNode
= RtlRightChildAvl(&Table
->BalancedRoot
);
69 ASSERT(CurrentNode
!= NULL
);
72 /* This address comes after */
73 if (StartVpn
> CurrentNode
->EndingVpn
)
75 /* Keep searching on the right */
76 CurrentNode
= RtlRightChildAvl(CurrentNode
);
78 else if (EndVpn
< CurrentNode
->StartingVpn
)
80 /* This address ends before the node starts, search on the left */
81 CurrentNode
= RtlLeftChildAvl(CurrentNode
);
85 /* This address is part of this node, return it */
90 /* Return either the conflicting node, or no node at all */
97 IN PMM_AVL_TABLE Table
,
98 IN PMMADDRESS_NODE NewNode
,
99 PMMADDRESS_NODE Parent
,
100 TABLE_SEARCH_RESULT Result
)
102 /* Insert it into the tree */
103 RtlpInsertAvlTreeNode(Table
, NewNode
, Parent
, Result
);
108 MiRemoveNode(IN PMMADDRESS_NODE Node
,
109 IN PMM_AVL_TABLE Table
)
111 DPRINT("Removing address node: %lx %lx\n", Node
->StartingVpn
, Node
->EndingVpn
);
113 /* Call the AVL code */
114 RtlpDeleteAvlTreeNode(Table
, Node
);
116 /* Decrease element count */
117 Table
->NumberGenericTableElements
--;
119 /* Check if this node was the hint */
120 if (Table
->NodeHint
== Node
)
122 /* Get a new hint, unless we're empty now, in which case nothing */
123 if (!Table
->NumberGenericTableElements
) Table
->NodeHint
= NULL
;
124 else Table
->NodeHint
= Table
->BalancedRoot
.RightChild
;
130 MiGetPreviousNode(IN PMMADDRESS_NODE Node
)
132 PMMADDRESS_NODE Parent
;
134 /* Get the left child */
135 if (RtlLeftChildAvl(Node
))
137 /* Get right-most child */
138 Node
= RtlLeftChildAvl(Node
);
139 while (RtlRightChildAvl(Node
)) Node
= RtlRightChildAvl(Node
);
143 Parent
= RtlParentAvl(Node
);
144 ASSERT(Parent
!= NULL
);
145 while (Parent
!= Node
)
147 /* The parent should be a right child, return the real predecessor */
148 if (RtlIsRightChildAvl(Node
))
150 /* Return it unless it's the root */
151 if (Parent
== RtlParentAvl(Parent
)) Parent
= NULL
;
155 /* Keep lopping until we find our parent */
157 Parent
= RtlParentAvl(Node
);
166 MiFindEmptyAddressRangeDownTree(
168 IN ULONG_PTR BoundaryAddress
,
169 IN ULONG_PTR Alignment
,
170 IN PMM_AVL_TABLE Table
,
172 OUT PMMADDRESS_NODE
*Parent
)
174 PMMADDRESS_NODE Node
, LowestNode
, Child
;
175 ULONG LowVpn
, HighVpn
;
176 PFN_NUMBER PageCount
;
179 ASSERT(BoundaryAddress
);
180 ASSERT(BoundaryAddress
<= ((ULONG_PTR
)MM_HIGHEST_VAD_ADDRESS
+ 1));
182 /* Compute page length, make sure the boundary address is valid */
183 Length
= PAGE_ROUND_UP(Length
);
184 PageCount
= Length
>> PAGE_SHIFT
;
185 if ((BoundaryAddress
+ 1) < Length
) return STATUS_NO_MEMORY
;
187 /* Check if the table is empty */
188 if (Table
->NumberGenericTableElements
== 0)
190 /* Tree is empty, the candidate address is already the best one */
191 *Base
= ROUND_DOWN(BoundaryAddress
+ 1 - Length
, Alignment
);
192 return TableEmptyTree
;
195 /* Calculate the initial upper margin */
196 HighVpn
= BoundaryAddress
>> PAGE_SHIFT
;
198 /* Starting from the root, go down until the right-most child,
199 trying to stay below the boundary. */
200 LowestNode
= Node
= RtlRightChildAvl(&Table
->BalancedRoot
);
201 while ( (Child
= RtlRightChildAvl(Node
)) &&
202 Child
->EndingVpn
< HighVpn
) Node
= Child
;
204 /* Now loop the Vad nodes */
207 /* Keep track of the lowest node */
210 /* Calculate the lower margin */
211 LowVpn
= ROUND_UP(Node
->EndingVpn
+ 1, Alignment
>> PAGE_SHIFT
);
213 /* Check if the current bounds are suitable */
214 if ((HighVpn
> LowVpn
) && ((HighVpn
- LowVpn
) >= PageCount
))
216 /* There is enough space to add our node */
217 LowVpn
= HighVpn
- PageCount
;
218 *Base
= LowVpn
<< PAGE_SHIFT
;
220 /* Can we use the current node as parent? */
221 Child
= RtlRightChildAvl(Node
);
224 /* Node has no right child, so use it as parent */
226 return TableInsertAsRight
;
230 /* Node has a right child, find most left grand child */
232 while ((Child
= RtlLeftChildAvl(Node
))) Node
= Child
;
234 return TableInsertAsLeft
;
238 /* Update the upper margin if neccessary */
239 if (Node
->StartingVpn
< HighVpn
) HighVpn
= Node
->StartingVpn
;
241 /* Go to the next lower node */
242 Node
= MiGetPreviousNode(Node
);
245 /* Check if there's enough space before the lowest Vad */
246 LowVpn
= ROUND_UP((ULONG_PTR
)MI_LOWEST_VAD_ADDRESS
, Alignment
) >> PAGE_SHIFT
;
247 if ((HighVpn
> LowVpn
) && ((HighVpn
- LowVpn
) >= PageCount
))
249 /* There is enough space to add our address */
250 LowVpn
= HighVpn
- PageCount
;
251 *Base
= LowVpn
<< PAGE_SHIFT
;
252 *Parent
= LowestNode
;
253 return TableInsertAsLeft
;
256 /* No address space left at all */
259 return TableFoundNode
;