Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenvadnode.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/vadnode.c 00005 * PURPOSE: ARM Memory Manager VAD Node Algorithms 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 * Timo Kreuzer (timo.kreuzer@reactos.org) 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define MODULE_INVOLVED_IN_ARM3 00017 #include "../ARM3/miarm.h" 00018 00019 /* Include Mm version of AVL support */ 00020 #include "../ARM3/miavl.h" 00021 #include "../../../lib/rtl/avlsupp.c" 00022 00023 /* FUNCTIONS ******************************************************************/ 00024 00025 PMMVAD 00026 NTAPI 00027 MiLocateAddress(IN PVOID VirtualAddress) 00028 { 00029 PMMVAD FoundVad; 00030 ULONG_PTR Vpn; 00031 PMM_AVL_TABLE Table = &PsGetCurrentProcess()->VadRoot; 00032 TABLE_SEARCH_RESULT SearchResult; 00033 00034 /* Start with the the hint */ 00035 FoundVad = (PMMVAD)Table->NodeHint; 00036 if (!FoundVad) return NULL; 00037 00038 /* Check if this VPN is in the hint, if so, use it */ 00039 Vpn = (ULONG_PTR)VirtualAddress >> PAGE_SHIFT; 00040 if ((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn)) return FoundVad; 00041 00042 /* VAD hint didn't work, go look for it */ 00043 SearchResult = RtlpFindAvlTableNodeOrParent(Table, 00044 (PVOID)Vpn, 00045 (PMMADDRESS_NODE*)&FoundVad); 00046 if (SearchResult != TableFoundNode) return NULL; 00047 00048 /* We found it, update the hint */ 00049 ASSERT(FoundVad != NULL); 00050 ASSERT((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn)); 00051 Table->NodeHint = FoundVad; 00052 return FoundVad; 00053 } 00054 00055 PMMADDRESS_NODE 00056 NTAPI 00057 MiCheckForConflictingNode(IN ULONG_PTR StartVpn, 00058 IN ULONG_PTR EndVpn, 00059 IN PMM_AVL_TABLE Table) 00060 { 00061 PMMADDRESS_NODE CurrentNode; 00062 00063 /* If the tree is empty, there is no conflict */ 00064 if (!Table->NumberGenericTableElements) return NULL; 00065 00066 /* Start looping from the right */ 00067 CurrentNode = RtlRightChildAvl(&Table->BalancedRoot); 00068 ASSERT(CurrentNode != NULL); 00069 while (CurrentNode) 00070 { 00071 /* This address comes after */ 00072 if (StartVpn > CurrentNode->EndingVpn) 00073 { 00074 /* Keep searching on the right */ 00075 CurrentNode = RtlRightChildAvl(CurrentNode); 00076 } 00077 else if (EndVpn < CurrentNode->StartingVpn) 00078 { 00079 /* This address ends before the node starts, search on the left */ 00080 CurrentNode = RtlLeftChildAvl(CurrentNode); 00081 } 00082 else 00083 { 00084 /* This address is part of this node, return it */ 00085 break; 00086 } 00087 } 00088 00089 /* Return either the conflicting node, or no node at all */ 00090 return CurrentNode; 00091 } 00092 00093 VOID 00094 NTAPI 00095 MiInsertNode(IN PMM_AVL_TABLE Table, 00096 IN PMMADDRESS_NODE NewNode, 00097 IN PMMADDRESS_NODE Parent, 00098 IN TABLE_SEARCH_RESULT Result) 00099 { 00100 PMMVAD_LONG Vad; 00101 00102 /* Insert it into the tree */ 00103 RtlpInsertAvlTreeNode(Table, NewNode, Parent, Result); 00104 00105 /* Now insert an ARM3 MEMORY_AREA for this node, unless the insert was already from the MEMORY_AREA code */ 00106 Vad = (PMMVAD_LONG)NewNode; 00107 if (Vad->u.VadFlags.Spare == 0) 00108 { 00109 NTSTATUS Status; 00110 PMEMORY_AREA MemoryArea; 00111 PHYSICAL_ADDRESS BoundaryAddressMultiple; 00112 SIZE_T Size; 00113 PEPROCESS Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot); 00114 PVOID AllocatedBase = (PVOID)(Vad->StartingVpn << PAGE_SHIFT); 00115 BoundaryAddressMultiple.QuadPart = 0; 00116 Size = ((Vad->EndingVpn + 1) - Vad->StartingVpn) << PAGE_SHIFT; 00117 Status = MmCreateMemoryArea(&Process->Vm, 00118 MEMORY_AREA_OWNED_BY_ARM3, 00119 &AllocatedBase, 00120 Size, 00121 PAGE_READWRITE, 00122 &MemoryArea, 00123 TRUE, 00124 0, 00125 BoundaryAddressMultiple); 00126 ASSERT(NT_SUCCESS(Status)); 00127 00128 /* Check if this is VM VAD */ 00129 if (Vad->ControlArea == NULL) 00130 { 00131 /* We store the reactos MEMORY_AREA here */ 00132 Vad->FirstPrototypePte = (PMMPTE)MemoryArea; 00133 } 00134 else 00135 { 00136 /* This is a section VAD. Store the MAREA here for now */ 00137 ASSERT(Vad->u4.Banked == (PVOID)0xDEADBABE); 00138 Vad->u4.Banked = (PVOID)MemoryArea; 00139 } 00140 } 00141 } 00142 00143 VOID 00144 NTAPI 00145 MiInsertVad(IN PMMVAD Vad, 00146 IN PEPROCESS Process) 00147 { 00148 TABLE_SEARCH_RESULT Result; 00149 PMMADDRESS_NODE Parent = NULL; 00150 00151 /* Validate the VAD and set it as the current hint */ 00152 ASSERT(Vad->EndingVpn >= Vad->StartingVpn); 00153 Process->VadRoot.NodeHint = Vad; 00154 00155 /* Find the parent VAD and where this child should be inserted */ 00156 Result = RtlpFindAvlTableNodeOrParent(&Process->VadRoot, (PVOID)Vad->StartingVpn, &Parent); 00157 ASSERT(Result != TableFoundNode); 00158 ASSERT((Parent != NULL) || (Result == TableEmptyTree)); 00159 00160 /* Do the actual insert operation */ 00161 MiInsertNode(&Process->VadRoot, (PVOID)Vad, Parent, Result); 00162 } 00163 00164 VOID 00165 NTAPI 00166 MiInsertBasedSection(IN PSECTION Section) 00167 { 00168 TABLE_SEARCH_RESULT Result; 00169 PMMADDRESS_NODE Parent = NULL; 00170 ASSERT(Section->Address.EndingVpn >= Section->Address.StartingVpn); 00171 00172 /* Find the parent VAD and where this child should be inserted */ 00173 Result = RtlpFindAvlTableNodeOrParent(&MmSectionBasedRoot, (PVOID)Section->Address.StartingVpn, &Parent); 00174 ASSERT(Result != TableFoundNode); 00175 ASSERT((Parent != NULL) || (Result == TableEmptyTree)); 00176 MiInsertNode(&MmSectionBasedRoot, &Section->Address, Parent, Result); 00177 } 00178 00179 VOID 00180 NTAPI 00181 MiRemoveNode(IN PMMADDRESS_NODE Node, 00182 IN PMM_AVL_TABLE Table) 00183 { 00184 PMMVAD_LONG Vad; 00185 00186 /* Call the AVL code */ 00187 RtlpDeleteAvlTreeNode(Table, Node); 00188 00189 /* Decrease element count */ 00190 Table->NumberGenericTableElements--; 00191 00192 /* Check if this node was the hint */ 00193 if (Table->NodeHint == Node) 00194 { 00195 /* Get a new hint, unless we're empty now, in which case nothing */ 00196 if (!Table->NumberGenericTableElements) Table->NodeHint = NULL; 00197 else Table->NodeHint = Table->BalancedRoot.RightChild; 00198 } 00199 00200 /* Free the node from ReactOS view as well */ 00201 Vad = (PMMVAD_LONG)Node; 00202 if (Vad->u.VadFlags.Spare == 0) 00203 { 00204 PMEMORY_AREA MemoryArea; 00205 PEPROCESS Process; 00206 00207 /* Check if this is VM VAD */ 00208 if (Vad->ControlArea == NULL) 00209 { 00210 /* We store the ReactOS MEMORY_AREA here */ 00211 MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte; 00212 } 00213 else 00214 { 00215 /* This is a section VAD. We store the ReactOS MEMORY_AREA here */ 00216 MemoryArea = (PMEMORY_AREA)Vad->u4.Banked; 00217 } 00218 00219 /* Make sure one actually still exists */ 00220 if (MemoryArea) 00221 { 00222 /* Make sure we have not already freed it */ 00223 ASSERT(MemoryArea != (PVOID)0xDEADBAB1); 00224 00225 /* Get the process */ 00226 Process = CONTAINING_RECORD(Table, EPROCESS, VadRoot); 00227 00228 /* We only create fake memory-areas for ARM3 VADs */ 00229 ASSERT(MemoryArea->Type == MEMORY_AREA_OWNED_BY_ARM3); 00230 ASSERT(MemoryArea->Vad == NULL); 00231 00232 /* Free it */ 00233 MmFreeMemoryArea(&Process->Vm, MemoryArea, NULL, NULL); 00234 00235 /* Check if this is VM VAD */ 00236 if (Vad->ControlArea == NULL) 00237 { 00238 /* Delete the pointer to it */ 00239 Vad->FirstPrototypePte = (PVOID)0xDEADBAB1; 00240 } 00241 else 00242 { 00243 /* Delete the pointer to it */ 00244 Vad->u4.Banked = (PVOID)0xDEADBAB1; 00245 } 00246 } 00247 } 00248 } 00249 00250 PMMADDRESS_NODE 00251 NTAPI 00252 MiGetPreviousNode(IN PMMADDRESS_NODE Node) 00253 { 00254 PMMADDRESS_NODE Parent; 00255 00256 /* Get the left child */ 00257 if (RtlLeftChildAvl(Node)) 00258 { 00259 /* Get right-most child */ 00260 Node = RtlLeftChildAvl(Node); 00261 while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node); 00262 return Node; 00263 } 00264 00265 Parent = RtlParentAvl(Node); 00266 ASSERT(Parent != NULL); 00267 while (Parent != Node) 00268 { 00269 /* The parent should be a right child, return the real predecessor */ 00270 if (RtlIsRightChildAvl(Node)) 00271 { 00272 /* Return it unless it's the root */ 00273 if (Parent == RtlParentAvl(Parent)) Parent = NULL; 00274 return Parent; 00275 } 00276 00277 /* Keep lopping until we find our parent */ 00278 Node = Parent; 00279 Parent = RtlParentAvl(Node); 00280 } 00281 00282 /* Nothing found */ 00283 return NULL; 00284 } 00285 00286 PMMADDRESS_NODE 00287 NTAPI 00288 MiGetNextNode(IN PMMADDRESS_NODE Node) 00289 { 00290 PMMADDRESS_NODE Parent; 00291 00292 /* Get the right child */ 00293 if (RtlRightChildAvl(Node)) 00294 { 00295 /* Get left-most child */ 00296 Node = RtlRightChildAvl(Node); 00297 while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node); 00298 return Node; 00299 } 00300 00301 Parent = RtlParentAvl(Node); 00302 ASSERT(Parent != NULL); 00303 while (Parent != Node) 00304 { 00305 /* The parent should be a left child, return the real predecessor */ 00306 if (RtlIsLeftChildAvl(Node)) 00307 { 00308 /* Return it */ 00309 return Parent; 00310 } 00311 00312 /* Keep lopping until we find our parent */ 00313 Node = Parent; 00314 Parent = RtlParentAvl(Node); 00315 } 00316 00317 /* Nothing found */ 00318 return NULL; 00319 } 00320 00321 NTSTATUS 00322 NTAPI 00323 MiFindEmptyAddressRangeInTree(IN SIZE_T Length, 00324 IN ULONG_PTR Alignment, 00325 IN PMM_AVL_TABLE Table, 00326 OUT PMMADDRESS_NODE *PreviousVad, 00327 OUT PULONG_PTR Base) 00328 { 00329 PMMADDRESS_NODE Node; 00330 PMMADDRESS_NODE NextNode; 00331 ULONG_PTR StartingVpn, HighestVpn, AlignmentVpn, LengthVpn, LowVpn; 00332 ASSERT(Length != 0); 00333 00334 /* Precompute page numbers for the length, alignment, and starting address */ 00335 LengthVpn = (Length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 00336 AlignmentVpn = Alignment >> PAGE_SHIFT; 00337 StartingVpn = ROUND_UP((ULONG_PTR)MM_LOWEST_USER_ADDRESS >> PAGE_SHIFT, 00338 AlignmentVpn); 00339 00340 /* Check if the table is free, so the lowest possible address is available */ 00341 if (!Table->NumberGenericTableElements) goto FoundAtBottom; 00342 00343 /* Otherwise, follow the leftmost child of the right root node's child */ 00344 Node = RtlRightChildAvl(&Table->BalancedRoot); 00345 while (RtlLeftChildAvl(Node)) Node = RtlLeftChildAvl(Node); 00346 00347 /* This is the node for the remaining gap at the bottom, can it be used? */ 00348 if ((Node->StartingVpn > StartingVpn) && 00349 (LengthVpn < Node->StartingVpn - StartingVpn)) 00350 { 00351 FoundAtBottom: 00352 /* Use this VAD to store the allocation */ 00353 *PreviousVad = NULL; 00354 *Base = StartingVpn << PAGE_SHIFT; 00355 return STATUS_SUCCESS; 00356 } 00357 00358 /* Otherwise, we start a search to find a gap */ 00359 while (TRUE) 00360 { 00361 /* The last aligned page number in this entry */ 00362 LowVpn = ROUND_UP(Node->EndingVpn + 1, AlignmentVpn); 00363 00364 /* Keep going as long as there's still a next node */ 00365 NextNode = MiGetNextNode(Node); 00366 if (!NextNode) break; 00367 00368 /* Can this allocation fit in this node? */ 00369 if ((LengthVpn <= (NextNode->StartingVpn - LowVpn)) && 00370 (NextNode->StartingVpn > LowVpn)) 00371 { 00372 Found: 00373 /* Yes! Use this VAD to store the allocation */ 00374 *PreviousVad = Node; 00375 *Base = ROUND_UP((Node->EndingVpn << PAGE_SHIFT) | (PAGE_SIZE - 1), 00376 Alignment); 00377 return STATUS_SUCCESS; 00378 } 00379 00380 /* Try the next node */ 00381 Node = NextNode; 00382 } 00383 00384 /* We're down to the last (top) VAD, will this allocation fit inside it? */ 00385 HighestVpn = ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1) >> PAGE_SHIFT; 00386 if ((HighestVpn > LowVpn) && (LengthVpn <= HighestVpn - LowVpn)) goto Found; 00387 00388 /* Nyet, there's no free address space for this allocation, so we'll fail */ 00389 return STATUS_NO_MEMORY; 00390 } 00391 00392 TABLE_SEARCH_RESULT 00393 NTAPI 00394 MiFindEmptyAddressRangeDownTree(IN SIZE_T Length, 00395 IN ULONG_PTR BoundaryAddress, 00396 IN ULONG_PTR Alignment, 00397 IN PMM_AVL_TABLE Table, 00398 OUT PULONG_PTR Base, 00399 OUT PMMADDRESS_NODE *Parent) 00400 { 00401 PMMADDRESS_NODE Node, LowestNode, Child; 00402 ULONG_PTR LowVpn, HighVpn; 00403 PFN_NUMBER PageCount; 00404 00405 /* Sanity checks */ 00406 ASSERT(BoundaryAddress); 00407 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1)); 00408 00409 /* Compute page length, make sure the boundary address is valid */ 00410 Length = ROUND_TO_PAGES(Length); 00411 PageCount = Length >> PAGE_SHIFT; 00412 if ((BoundaryAddress + 1) < Length) return TableFoundNode; 00413 00414 /* Check if the table is empty */ 00415 if (Table->NumberGenericTableElements == 0) 00416 { 00417 /* Tree is empty, the candidate address is already the best one */ 00418 *Base = ROUND_UP(BoundaryAddress + 1 - Length, Alignment); 00419 return TableEmptyTree; 00420 } 00421 00422 /* Calculate the initial upper margin */ 00423 HighVpn = BoundaryAddress >> PAGE_SHIFT; 00424 00425 /* Starting from the root, go down until the right-most child 00426 * which is just behind the boundary*/ 00427 LowestNode = Node = RtlRightChildAvl(&Table->BalancedRoot); 00428 while (((Child = RtlRightChildAvl(Node)) != 0 ) 00429 && (Node->EndingVpn < HighVpn )) Node = Child; 00430 00431 /* Now loop the Vad nodes */ 00432 while (Node) 00433 { 00434 /* Keep track of the lowest node */ 00435 LowestNode = Node; 00436 00437 /* Calculate the lower margin */ 00438 LowVpn = ROUND_UP(Node->EndingVpn + 1, Alignment >> PAGE_SHIFT); 00439 00440 /* Check if the current bounds are suitable */ 00441 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount)) 00442 { 00443 /* There is enough space to add our node */ 00444 LowVpn = HighVpn - PageCount; 00445 *Base = LowVpn << PAGE_SHIFT; 00446 00447 /* Can we use the current node as parent? */ 00448 Child = RtlRightChildAvl(Node); 00449 if (!Child) 00450 { 00451 /* Node has no right child, so use it as parent */ 00452 *Parent = Node; 00453 return TableInsertAsRight; 00454 } 00455 else 00456 { 00457 /* Node has a right child, find most left grand child */ 00458 Node = Child; 00459 while ((Child = RtlLeftChildAvl(Node))) Node = Child; 00460 *Parent = Node; 00461 return TableInsertAsLeft; 00462 } 00463 } 00464 00465 /* Update the upper margin if neccessary */ 00466 if (Node->StartingVpn < HighVpn) HighVpn = Node->StartingVpn; 00467 00468 /* Go to the next lower node */ 00469 Node = MiGetPreviousNode(Node); 00470 } 00471 00472 /* Check if there's enough space before the lowest Vad */ 00473 LowVpn = ROUND_UP((ULONG_PTR)MI_LOWEST_VAD_ADDRESS, Alignment) >> PAGE_SHIFT; 00474 if ((HighVpn > LowVpn) && ((HighVpn - LowVpn) >= PageCount)) 00475 { 00476 /* There is enough space to add our address */ 00477 LowVpn = HighVpn - PageCount; 00478 *Base = LowVpn << PAGE_SHIFT; 00479 *Parent = LowestNode; 00480 return TableInsertAsLeft; 00481 } 00482 00483 /* No address space left at all */ 00484 *Base = 0; 00485 *Parent = NULL; 00486 return TableFoundNode; 00487 } 00488 00489 NTSTATUS 00490 NTAPI 00491 MiFindEmptyAddressRangeDownBasedTree(IN SIZE_T Length, 00492 IN ULONG_PTR BoundaryAddress, 00493 IN ULONG_PTR Alignment, 00494 IN PMM_AVL_TABLE Table, 00495 OUT PULONG_PTR Base) 00496 { 00497 PMMADDRESS_NODE Node, LowestNode; 00498 ULONG_PTR LowVpn, BestVpn; 00499 00500 /* Sanity checks */ 00501 ASSERT(Table == &MmSectionBasedRoot); 00502 ASSERT(BoundaryAddress); 00503 ASSERT(BoundaryAddress <= ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1)); 00504 00505 /* Compute page length, make sure the boundary address is valid */ 00506 Length = ROUND_TO_PAGES(Length); 00507 if ((BoundaryAddress + 1) < Length) return STATUS_NO_MEMORY; 00508 00509 /* Check if the table is empty */ 00510 BestVpn = ROUND_UP(BoundaryAddress + 1 - Length, Alignment); 00511 if (Table->NumberGenericTableElements == 0) 00512 { 00513 /* Tree is empty, the candidate address is already the best one */ 00514 *Base = BestVpn; 00515 return STATUS_SUCCESS; 00516 } 00517 00518 /* Go to the right-most node which should be the biggest address */ 00519 Node = Table->BalancedRoot.RightChild; 00520 while (RtlRightChildAvl(Node)) Node = RtlRightChildAvl(Node); 00521 00522 /* Check if we can fit in here */ 00523 LowVpn = ROUND_UP(Node->EndingVpn, Alignment); 00524 if ((LowVpn < BoundaryAddress) && (Length < (BoundaryAddress - LowVpn))) 00525 { 00526 /* Return the address */ 00527 *Base = ROUND_UP(BoundaryAddress - Length, Alignment); 00528 return STATUS_SUCCESS; 00529 } 00530 00531 /* Now loop the Vad nodes */ 00532 do 00533 { 00534 /* Break out if we've reached the last node */ 00535 LowestNode = MiGetPreviousNode(Node); 00536 if (!LowestNode) break; 00537 00538 /* Check if this node could contain the requested address */ 00539 LowVpn = ROUND_UP(LowestNode->EndingVpn + 1, Alignment); 00540 if ((LowestNode->EndingVpn < BestVpn) && 00541 (Length <= (Node->StartingVpn - LowVpn))) 00542 { 00543 /* Check if it fits in perfectly */ 00544 if ((BestVpn > LowestNode->EndingVpn) && 00545 (BoundaryAddress < Node->StartingVpn)) 00546 { 00547 /* Return the optimal VPN address */ 00548 *Base = BestVpn; 00549 return STATUS_SUCCESS; 00550 } 00551 00552 /* It doesn't, check if it can partly fit */ 00553 if (Node->StartingVpn > LowVpn) 00554 { 00555 /* Return an aligned base address within this node */ 00556 *Base = ROUND_UP(Node->StartingVpn - Length, Alignment); 00557 return STATUS_SUCCESS; 00558 } 00559 } 00560 00561 /* Move to the next node */ 00562 Node = LowestNode; 00563 } while (TRUE); 00564 00565 /* Check if there's enough space before the lowest Vad */ 00566 if ((Node->StartingVpn > (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) && 00567 ((Node->StartingVpn - (ULONG_PTR)MI_LOWEST_VAD_ADDRESS) > Length)) 00568 { 00569 /* Check if it fits in perfectly */ 00570 if (BoundaryAddress < Node->StartingVpn) 00571 { 00572 /* Return the optimal VPN address */ 00573 *Base = BestVpn; 00574 return STATUS_SUCCESS; 00575 } 00576 00577 /* Return an aligned base address within this node */ 00578 *Base = ROUND_UP(Node->StartingVpn - Length, Alignment); 00579 return STATUS_SUCCESS; 00580 } 00581 00582 /* No address space left at all */ 00583 return STATUS_NO_MEMORY; 00584 } 00585 00586 /* EOF */ Generated on Sun May 27 2012 04:37:37 for ReactOS by
1.7.6.1
|