ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

vadnode.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.