Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2638 lines
71 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. addrsup.c
  5. Abstract:
  6. This module implements a new version of the generic table package
  7. based on balanced binary trees (later named AVL), as described in
  8. Knuth, "The Art of Computer Programming, Volume 3, Sorting and Searching",
  9. and refers directly to algorithms as they are presented in the second
  10. edition Copyrighted in 1973.
  11. Used rtl\avltable.c as a starting point, adding the following:
  12. - Use less memory for structures as these are nonpaged & heavily used.
  13. - Caller allocates the pool to reduce mutex hold times.
  14. - Various VAD-specific customizations/optimizations.
  15. - Hints.
  16. Author:
  17. Landy Wang (landyw) 20-Aug-2001
  18. Environment:
  19. Kernel mode only, working set mutex held, APCs disabled.
  20. Revision History:
  21. --*/
  22. #include "mi.h"
  23. #if !defined (_USERMODE)
  24. #define PRINT
  25. #define COUNT_BALANCE_MAX(a)
  26. #else
  27. extern MM_AVL_TABLE MmSectionBasedRoot;
  28. #endif
  29. #if (_MSC_VER >= 800)
  30. #pragma warning(disable:4010) // Allow pretty pictures without the noise
  31. #endif
  32. TABLE_SEARCH_RESULT
  33. MiFindNodeOrParent (
  34. IN PMM_AVL_TABLE Table,
  35. IN ULONG_PTR StartingVpn,
  36. OUT PMMADDRESS_NODE *NodeOrParent
  37. );
  38. VOID
  39. MiPromoteNode (
  40. IN PMMADDRESS_NODE C
  41. );
  42. ULONG
  43. MiRebalanceNode (
  44. IN PMMADDRESS_NODE S
  45. );
  46. PMMADDRESS_NODE
  47. MiRealSuccessor (
  48. IN PMMADDRESS_NODE Links
  49. );
  50. PMMADDRESS_NODE
  51. MiRealPredecessor (
  52. IN PMMADDRESS_NODE Links
  53. );
  54. VOID
  55. MiInitializeVadTableAvl (
  56. IN PMM_AVL_TABLE Table
  57. );
  58. PVOID
  59. MiEnumerateGenericTableWithoutSplayingAvl (
  60. IN PMM_AVL_TABLE Table,
  61. IN PVOID *RestartKey
  62. );
  63. #ifdef ALLOC_PRAGMA
  64. #pragma alloc_text(PAGE,MiCheckForConflictingNode)
  65. #pragma alloc_text(PAGE,MiGetFirstNode)
  66. #pragma alloc_text(PAGE,MiRealSuccessor)
  67. #pragma alloc_text(PAGE,MiRealPredecessor)
  68. #pragma alloc_text(PAGE,MiInitializeVadTableAvl)
  69. #if 0
  70. //
  71. // These routines are called with the PFN lock held but would otherwise be
  72. // pagable.
  73. //
  74. #pragma alloc_text(PAGE,MiPromoteNode)
  75. #pragma alloc_text(PAGE,MiInsertNode)
  76. #pragma alloc_text(PAGE,MiRebalanceNode)
  77. #pragma alloc_text(PAGE,MiRemoveNode)
  78. #endif
  79. #pragma alloc_text(PAGE,MiEnumerateGenericTableWithoutSplayingAvl)
  80. #pragma alloc_text(PAGE,MiGetNextNode)
  81. #pragma alloc_text(PAGE,MiGetPreviousNode)
  82. #pragma alloc_text(PAGE,MiFindEmptyAddressRangeInTree)
  83. #pragma alloc_text(PAGE,MiFindEmptyAddressRangeDownTree)
  84. #pragma alloc_text(PAGE,MiFindEmptyAddressRangeDownBasedTree)
  85. #endif
  86. //
  87. // Various Rtl macros that reference Parent use private versions here since
  88. // Parent is overloaded with Balance.
  89. //
  90. //
  91. // The macro function Parent takes as input a pointer to a splay link in a
  92. // tree and returns a pointer to the splay link of the parent of the input
  93. // node. If the input node is the root of the tree the return value is
  94. // equal to the input value.
  95. //
  96. // PRTL_SPLAY_LINKS
  97. // MiParent (
  98. // PRTL_SPLAY_LINKS Links
  99. // );
  100. //
  101. #define MiParent(Links) ( \
  102. (PRTL_SPLAY_LINKS)(SANITIZE_PARENT_NODE((Links)->u1.Parent)) \
  103. )
  104. //
  105. // The macro function IsLeftChild takes as input a pointer to a splay link
  106. // in a tree and returns TRUE if the input node is the left child of its
  107. // parent, otherwise it returns FALSE.
  108. //
  109. // BOOLEAN
  110. // MiIsLeftChild (
  111. // PRTL_SPLAY_LINKS Links
  112. // );
  113. //
  114. #define MiIsLeftChild(Links) ( \
  115. (RtlLeftChild(MiParent(Links)) == (PRTL_SPLAY_LINKS)(Links)) \
  116. )
  117. //
  118. // The macro function IsRightChild takes as input a pointer to a splay link
  119. // in a tree and returns TRUE if the input node is the right child of its
  120. // parent, otherwise it returns FALSE.
  121. //
  122. // BOOLEAN
  123. // MiIsRightChild (
  124. // PRTL_SPLAY_LINKS Links
  125. // );
  126. //
  127. #define MiIsRightChild(Links) ( \
  128. (RtlRightChild(MiParent(Links)) == (PRTL_SPLAY_LINKS)(Links)) \
  129. )
  130. #if DBG
  131. //
  132. // Build a table of the best case efficiency of a balanced binary tree,
  133. // holding the most possible nodes that can possibly be held in a binary
  134. // tree with a given number of levels. The answer is always (2**n) - 1.
  135. //
  136. // (Used for debug only.)
  137. //
  138. ULONG MiBestCaseFill[33] = {
  139. 0, 1, 3, 7,
  140. 0xf, 0x1f, 0x3f, 0x7f,
  141. 0xff, 0x1ff, 0x3ff, 0x7ff,
  142. 0xfff, 0x1fff, 0x3fff, 0x7fff,
  143. 0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
  144. 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
  145. 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
  146. 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
  147. 0xffffffff
  148. };
  149. //
  150. // Build a table of the worst case efficiency of a balanced binary tree,
  151. // holding the fewest possible nodes that can possibly be contained in a
  152. // balanced binary tree with the given number of levels. After the first
  153. // two levels, each level n is obviously occupied by a root node, plus
  154. // one subtree the size of level n-1, and another subtree which is the
  155. // size of n-2, i.e.:
  156. //
  157. // MiWorstCaseFill[n] = 1 + MiWorstCaseFill[n-1] + MiWorstCaseFill[n-2]
  158. //
  159. // The efficiency of a typical balanced binary tree will normally fall
  160. // between the two extremes, typically closer to the best case. Note
  161. // however that even with the worst case, it only takes 32 compares to
  162. // find an element in a worst case tree populated with ~3.5M nodes.
  163. //
  164. // Unbalanced trees and splay trees, on the other hand, can and will sometimes
  165. // degenerate to a straight line, requiring on average n/2 compares to
  166. // find a node.
  167. //
  168. // A specific case is one where the nodes are inserted in collated order.
  169. // In this case an unbalanced or a splay tree will generate a straight
  170. // line, yet the balanced binary tree will always create a perfectly
  171. // balanced tree (best-case fill) in this situation.
  172. //
  173. // (Used for debug only.)
  174. //
  175. ULONG MiWorstCaseFill[33] = {
  176. 0, 1, 2, 4,
  177. 7, 12, 20, 33,
  178. 54, 88, 143, 232,
  179. 376, 609, 986, 1596,
  180. 2583, 4180, 6764, 10945,
  181. 17710, 28656, 46367, 75024,
  182. 121392, 196417, 317810, 514228,
  183. 832039, 1346268, 2178308, 3524577,
  184. 5702886
  185. };
  186. #endif
  187. TABLE_SEARCH_RESULT
  188. MiFindNodeOrParent (
  189. IN PMM_AVL_TABLE Table,
  190. IN ULONG_PTR StartingVpn,
  191. OUT PMMADDRESS_NODE *NodeOrParent
  192. )
  193. /*++
  194. Routine Description:
  195. This routine is used by all of the routines of the generic
  196. table package to locate the a node in the tree. It will
  197. find and return (via the NodeOrParent parameter) the node
  198. with the given key, or if that node is not in the tree it
  199. will return (via the NodeOrParent parameter) a pointer to
  200. the parent.
  201. Arguments:
  202. Table - The generic table to search for the key.
  203. StartingVpn - The starting virtual page number.
  204. NodeOrParent - Will be set to point to the node containing the
  205. the key or what should be the parent of the node
  206. if it were in the tree. Note that this will *NOT*
  207. be set if the search result is TableEmptyTree.
  208. Return Value:
  209. TABLE_SEARCH_RESULT - TableEmptyTree: The tree was empty. NodeOrParent
  210. is *not* altered.
  211. TableFoundNode: A node with the key is in the tree.
  212. NodeOrParent points to that node.
  213. TableInsertAsLeft: Node with key was not found.
  214. NodeOrParent points to what would
  215. be parent. The node would be the
  216. left child.
  217. TableInsertAsRight: Node with key was not found.
  218. NodeOrParent points to what would
  219. be parent. The node would be
  220. the right child.
  221. Environment:
  222. Kernel mode. The PFN lock is held for some of the tables.
  223. --*/
  224. {
  225. #if DBG
  226. ULONG NumberCompares = 0;
  227. #endif
  228. PMMADDRESS_NODE Child;
  229. PMMADDRESS_NODE NodeToExamine;
  230. if (Table->NumberGenericTableElements == 0) {
  231. return TableEmptyTree;
  232. }
  233. NodeToExamine = (PMMADDRESS_NODE) Table->BalancedRoot.RightChild;
  234. do {
  235. //
  236. // Make sure the depth of tree is correct.
  237. //
  238. ASSERT(++NumberCompares <= Table->DepthOfTree);
  239. //
  240. // Compare the buffer with the key in the tree element.
  241. //
  242. if (StartingVpn < NodeToExamine->StartingVpn) {
  243. Child = NodeToExamine->LeftChild;
  244. if (Child != NULL) {
  245. NodeToExamine = Child;
  246. }
  247. else {
  248. //
  249. // Node is not in the tree. Set the output
  250. // parameter to point to what would be its
  251. // parent and return which child it would be.
  252. //
  253. *NodeOrParent = NodeToExamine;
  254. return TableInsertAsLeft;
  255. }
  256. }
  257. else if (StartingVpn <= NodeToExamine->EndingVpn) {
  258. //
  259. // This is the node.
  260. //
  261. *NodeOrParent = NodeToExamine;
  262. return TableFoundNode;
  263. }
  264. else {
  265. Child = NodeToExamine->RightChild;
  266. if (Child != NULL) {
  267. NodeToExamine = Child;
  268. }
  269. else {
  270. //
  271. // Node is not in the tree. Set the output
  272. // parameter to point to what would be its
  273. // parent and return which child it would be.
  274. //
  275. *NodeOrParent = NodeToExamine;
  276. return TableInsertAsRight;
  277. }
  278. }
  279. } while (TRUE);
  280. }
  281. PMMADDRESS_NODE
  282. MiCheckForConflictingNode (
  283. IN ULONG_PTR StartVpn,
  284. IN ULONG_PTR EndVpn,
  285. IN PMM_AVL_TABLE Table
  286. )
  287. /*++
  288. Routine Description:
  289. The function determines if any addresses between a given starting and
  290. ending address is contained within a virtual address descriptor.
  291. Arguments:
  292. StartVpn - Supplies the virtual address to locate a containing
  293. descriptor.
  294. EndVpn - Supplies the virtual address to locate a containing
  295. descriptor.
  296. Return Value:
  297. Returns a pointer to the first conflicting virtual address descriptor
  298. if one is found, otherwise a NULL value is returned.
  299. --*/
  300. {
  301. PMMADDRESS_NODE Node;
  302. if (Table->NumberGenericTableElements == 0) {
  303. return NULL;
  304. }
  305. Node = (PMMADDRESS_NODE) Table->BalancedRoot.RightChild;
  306. ASSERT (Node != NULL);
  307. do {
  308. if (Node == NULL) {
  309. return NULL;
  310. }
  311. if (StartVpn > Node->EndingVpn) {
  312. Node = Node->RightChild;
  313. }
  314. else if (EndVpn < Node->StartingVpn) {
  315. Node = Node->LeftChild;
  316. }
  317. else {
  318. //
  319. // The starting address is less than or equal to the end VA
  320. // and the ending address is greater than or equal to the
  321. // start va. Return this node.
  322. //
  323. return Node;
  324. }
  325. } while (TRUE);
  326. }
  327. PMMADDRESS_NODE
  328. FASTCALL
  329. MiGetFirstNode (
  330. IN PMM_AVL_TABLE Table
  331. )
  332. /*++
  333. Routine Description:
  334. This function locates the virtual address descriptor which contains
  335. the address range which logically is first within the address space.
  336. Arguments:
  337. None.
  338. Return Value:
  339. Returns a pointer to the virtual address descriptor containing the
  340. first address range, NULL if none.
  341. --*/
  342. {
  343. PMMADDRESS_NODE First;
  344. if (Table->NumberGenericTableElements == 0) {
  345. return NULL;
  346. }
  347. First = (PMMADDRESS_NODE) Table->BalancedRoot.RightChild;
  348. ASSERT (First != NULL);
  349. while (First->LeftChild != NULL) {
  350. First = First->LeftChild;
  351. }
  352. return First;
  353. }
  354. VOID
  355. MiPromoteNode (
  356. IN PMMADDRESS_NODE C
  357. )
  358. /*++
  359. Routine Description:
  360. This routine performs the fundamental adjustment required for balancing
  361. the binary tree during insert and delete operations. Simply put, the
  362. designated node is promoted in such a way that it rises one level in
  363. the tree and its parent drops one level in the tree, becoming now the
  364. child of the designated node. Generally the path length to the subtree
  365. "opposite" the original parent. Balancing occurs as the caller chooses
  366. which nodes to promote according to the balanced tree algorithms from
  367. Knuth.
  368. This is not the same as a splay operation, typically a splay "promotes"
  369. a designated node twice.
  370. Note that the pointer to the root node of the tree is assumed to be
  371. contained in a MMADDRESS_NODE structure itself, to allow the
  372. algorithms below to change the root of the tree without checking
  373. for special cases. Note also that this is an internal routine,
  374. and the caller guarantees that it never requests to promote the
  375. root itself.
  376. This routine only updates the tree links; the caller must update
  377. the balance factors as appropriate.
  378. Arguments:
  379. C - pointer to the child node to be promoted in the tree.
  380. Return Value:
  381. None.
  382. --*/
  383. {
  384. PMMADDRESS_NODE P;
  385. PMMADDRESS_NODE G;
  386. //
  387. // Capture the current parent and grandparent (may be the root).
  388. //
  389. P = SANITIZE_PARENT_NODE (C->u1.Parent);
  390. G = SANITIZE_PARENT_NODE (P->u1.Parent);
  391. //
  392. // Break down the promotion into two cases based upon whether C
  393. // is a left or right child.
  394. //
  395. if (P->LeftChild == C) {
  396. //
  397. // This promotion looks like this:
  398. //
  399. // G G
  400. // | |
  401. // P C
  402. // / \ => / \
  403. // C z x P
  404. // / \ / \
  405. // x y y z
  406. //
  407. P->LeftChild = C->RightChild;
  408. if (P->LeftChild != NULL) {
  409. P->LeftChild->u1.Parent = MI_MAKE_PARENT (P, P->LeftChild->u1.Balance);
  410. }
  411. C->RightChild = P;
  412. //
  413. // Fall through to update parent and G <-> C relationship in
  414. // common code.
  415. //
  416. }
  417. else {
  418. ASSERT(P->RightChild == C);
  419. //
  420. // This promotion looks like this:
  421. //
  422. // G G
  423. // | |
  424. // P C
  425. // / \ => / \
  426. // x C P z
  427. // / \ / \
  428. // y z x y
  429. //
  430. P->RightChild = C->LeftChild;
  431. if (P->RightChild != NULL) {
  432. P->RightChild->u1.Parent = MI_MAKE_PARENT (P, P->RightChild->u1.Balance);
  433. }
  434. C->LeftChild = P;
  435. }
  436. //
  437. // Update parent of P, for either case above.
  438. //
  439. P->u1.Parent = MI_MAKE_PARENT (C, P->u1.Balance);
  440. //
  441. // Finally update G <-> C links for either case above.
  442. //
  443. if (G->LeftChild == P) {
  444. G->LeftChild = C;
  445. }
  446. else {
  447. ASSERT(G->RightChild == P);
  448. G->RightChild = C;
  449. }
  450. C->u1.Parent = MI_MAKE_PARENT (G, C->u1.Balance);
  451. }
  452. ULONG
  453. MiRebalanceNode (
  454. IN PMMADDRESS_NODE S
  455. )
  456. /*++
  457. Routine Description:
  458. This routine performs a rebalance around the input node S, for which the
  459. Balance factor has just effectively become +2 or -2. When called, the
  460. Balance factor still has a value of +1 or -1, but the respective longer
  461. side has just become one longer as the result of an insert or delete
  462. operation.
  463. This routine effectively implements steps A7.iii (test for Case 1 or
  464. Case 2) and steps A8 and A9 of Knuth's balanced insertion algorithm,
  465. plus it handles Case 3 identified in the delete section, which can
  466. only happen on deletes.
  467. The trick is, to convince yourself that while traveling from the
  468. insertion point at the bottom of the tree up, that there are only
  469. these two cases, and that when traveling up from the deletion point,
  470. that there are just these three cases. Knuth says it is obvious!
  471. Arguments:
  472. S - pointer to the node which has just become unbalanced.
  473. Return Value:
  474. TRUE if Case 3 was detected (causes delete algorithm to terminate).
  475. Environment:
  476. Kernel mode. The PFN lock is held for some of the tables.
  477. --*/
  478. {
  479. PMMADDRESS_NODE R, P;
  480. SCHAR a;
  481. PRINT("rebalancing node %p bal=%x start=%x end=%x\n",
  482. S,
  483. S->u1.Balance,
  484. S->StartingVpn,
  485. S->EndingVpn);
  486. //
  487. // The parent node is never the argument node.
  488. //
  489. ASSERT (SANITIZE_PARENT_NODE(S->u1.Parent) != S);
  490. //
  491. // Capture which side is unbalanced.
  492. //
  493. a = (SCHAR) S->u1.Balance;
  494. if (a == +1) {
  495. R = S->RightChild;
  496. }
  497. else {
  498. R = S->LeftChild;
  499. }
  500. //
  501. // If the balance of R and S are the same (Case 1 in Knuth) then a single
  502. // promotion of R will do the single rotation. (Step A8, A10)
  503. //
  504. // Here is a diagram of the Case 1 transformation, for a == +1 (a mirror
  505. // image transformation occurs when a == -1), and where the subtree
  506. // heights are h and h+1 as shown (++ indicates the node out of balance):
  507. //
  508. // | |
  509. // S++ R
  510. // / \ / \
  511. // (h) R+ ==> S (h+1)
  512. // / \ / \
  513. // (h) (h+1) (h) (h)
  514. //
  515. // Note that on an insert we can hit this case by inserting an item in the
  516. // right subtree of R. The original height of the subtree before the insert
  517. // was h+2, and it is still h+2 after the rebalance, so insert rebalancing
  518. // may terminate.
  519. //
  520. // On a delete we can hit this case by deleting a node from the left subtree
  521. // of S. The height of the subtree before the delete was h+3, and after the
  522. // rebalance it is h+2, so rebalancing must continue up the tree.
  523. //
  524. if ((SCHAR) R->u1.Balance == a) {
  525. MiPromoteNode (R);
  526. R->u1.Balance = 0;
  527. S->u1.Balance = 0;
  528. return FALSE;
  529. }
  530. //
  531. // Otherwise, we have to promote the appropriate child of R twice (Case 2
  532. // in Knuth). (Step A9, A10)
  533. //
  534. // Here is a diagram of the Case 2 transformation, for a == +1 (a mirror
  535. // image transformation occurs when a == -1), and where the subtree
  536. // heights are h and h-1 as shown. There are actually two minor subcases,
  537. // differing only in the original balance of P (++ indicates the node out
  538. // of balance).
  539. //
  540. // | |
  541. // S++ P
  542. // / \ / \
  543. // / \ / \
  544. // / \ / \
  545. // (h) R- ==> S- R
  546. // / \ / \ / \
  547. // P+ (h) (h)(h-1)(h) (h)
  548. // / \
  549. // (h-1) (h)
  550. //
  551. //
  552. // | |
  553. // S++ P
  554. // / \ / \
  555. // / \ / \
  556. // / \ / \
  557. // (h) R- ==> S R+
  558. // / \ / \ / \
  559. // P- (h) (h) (h)(h-1)(h)
  560. // / \
  561. // (h) (h-1)
  562. //
  563. // Note that on an insert we can hit this case by inserting an item in the
  564. // left subtree of R. The original height of the subtree before the insert
  565. // was h+2, and it is still h+2 after the rebalance, so insert rebalancing
  566. // may terminate.
  567. //
  568. // On a delete we can hit this case by deleting a node from the left subtree
  569. // of S. The height of the subtree before the delete was h+3, and after the
  570. // rebalance it is h+2, so rebalancing must continue up the tree.
  571. //
  572. if ((SCHAR) R->u1.Balance == -a) {
  573. //
  574. // Pick up the appropriate child P for the double rotation (Link(-a,R)).
  575. //
  576. if (a == 1) {
  577. P = R->LeftChild;
  578. }
  579. else {
  580. P = R->RightChild;
  581. }
  582. //
  583. // Promote him twice to implement the double rotation.
  584. //
  585. MiPromoteNode (P);
  586. MiPromoteNode (P);
  587. //
  588. // Now adjust the balance factors.
  589. //
  590. S->u1.Balance = 0;
  591. R->u1.Balance = 0;
  592. if ((SCHAR) P->u1.Balance == a) {
  593. PRINT("REBADJ A: Node %p, Bal %x -> %x\n", S, S->u1.Balance, -a);
  594. COUNT_BALANCE_MAX ((SCHAR)-a);
  595. S->u1.Balance = (ULONG_PTR) -a;
  596. }
  597. else if ((SCHAR) P->u1.Balance == -a) {
  598. PRINT("REBADJ B: Node %p, Bal %x -> %x\n", R, R->u1.Balance, a);
  599. COUNT_BALANCE_MAX ((SCHAR)a);
  600. R->u1.Balance = (ULONG_PTR) a;
  601. }
  602. P->u1.Balance = 0;
  603. return FALSE;
  604. }
  605. //
  606. // Otherwise this is Case 3 which can only happen on Delete (identical
  607. // to Case 1 except R->u1.Balance == 0). We do a single rotation, adjust
  608. // the balance factors appropriately, and return TRUE. Note that the
  609. // balance of S stays the same.
  610. //
  611. // Here is a diagram of the Case 3 transformation, for a == +1 (a mirror
  612. // image transformation occurs when a == -1), and where the subtree
  613. // heights are h and h+1 as shown (++ indicates the node out of balance):
  614. //
  615. // | |
  616. // S++ R-
  617. // / \ / \
  618. // (h) R ==> S+ (h+1)
  619. // / \ / \
  620. // (h+1)(h+1) (h) (h+1)
  621. //
  622. // This case can not occur on an insert, because it is impossible for
  623. // a single insert to balance R, yet somehow grow the right subtree of
  624. // S at the same time. As we move up the tree adjusting balance factors
  625. // after an insert, we terminate the algorithm if a node becomes balanced,
  626. // because that means the subtree length did not change!
  627. //
  628. // On a delete we can hit this case by deleting a node from the left
  629. // subtree of S. The height of the subtree before the delete was h+3,
  630. // and after the rebalance it is still h+3, so rebalancing may terminate
  631. // in the delete path.
  632. //
  633. MiPromoteNode (R);
  634. PRINT("REBADJ C: Node %p, Bal %x -> %x\n", R, R->u1.Balance, -a);
  635. COUNT_BALANCE_MAX ((SCHAR)-a);
  636. R->u1.Balance = -a;
  637. return TRUE;
  638. }
  639. VOID
  640. FASTCALL
  641. MiRemoveNode (
  642. IN PMMADDRESS_NODE NodeToDelete,
  643. IN PMM_AVL_TABLE Table
  644. )
  645. /*++
  646. Routine Description:
  647. This routine deletes the specified node from the balanced tree, rebalancing
  648. as necessary. If the NodeToDelete has at least one NULL child pointers,
  649. then it is chosen as the EasyDelete, otherwise a subtree predecessor or
  650. successor is found as the EasyDelete. In either case the EasyDelete is
  651. deleted and the tree is rebalanced. Finally if the NodeToDelete was
  652. different than the EasyDelete, then the EasyDelete is linked back into the
  653. tree in place of the NodeToDelete.
  654. Arguments:
  655. NodeToDelete - Pointer to the node which the caller wishes to delete.
  656. Table - The generic table in which the delete is to occur.
  657. Return Value:
  658. None.
  659. Environment:
  660. Kernel mode. The PFN lock is held for some of the tables.
  661. --*/
  662. {
  663. PMMADDRESS_NODE Parent;
  664. PMMADDRESS_NODE EasyDelete;
  665. PMMADDRESS_NODE P;
  666. SCHAR a;
  667. //
  668. // If the NodeToDelete has at least one NULL child pointer, then we can
  669. // delete it directly.
  670. //
  671. if ((NodeToDelete->LeftChild == NULL) ||
  672. (NodeToDelete->RightChild == NULL)) {
  673. EasyDelete = NodeToDelete;
  674. }
  675. //
  676. // Otherwise, we may as well pick the longest side to delete from (if one is
  677. // is longer), as that reduces the probability that we will have to
  678. // rebalance.
  679. //
  680. else if ((SCHAR) NodeToDelete->u1.Balance >= 0) {
  681. //
  682. // Pick up the subtree successor.
  683. //
  684. EasyDelete = NodeToDelete->RightChild;
  685. while (EasyDelete->LeftChild != NULL) {
  686. EasyDelete = EasyDelete->LeftChild;
  687. }
  688. }
  689. else {
  690. //
  691. // Pick up the subtree predecessor.
  692. //
  693. EasyDelete = NodeToDelete->LeftChild;
  694. while (EasyDelete->RightChild != NULL) {
  695. EasyDelete = EasyDelete->RightChild;
  696. }
  697. }
  698. //
  699. // Rebalancing must know which side of the first parent the delete occurred
  700. // on. Assume it is the left side and otherwise correct below.
  701. //
  702. a = -1;
  703. //
  704. // Now we can do the simple deletion for the no left child case.
  705. //
  706. if (EasyDelete->LeftChild == NULL) {
  707. Parent = SANITIZE_PARENT_NODE (EasyDelete->u1.Parent);
  708. if (MiIsLeftChild(EasyDelete)) {
  709. Parent->LeftChild = EasyDelete->RightChild;
  710. }
  711. else {
  712. Parent->RightChild = EasyDelete->RightChild;
  713. a = 1;
  714. }
  715. if (EasyDelete->RightChild != NULL) {
  716. EasyDelete->RightChild->u1.Parent = MI_MAKE_PARENT (Parent, EasyDelete->RightChild->u1.Balance);
  717. }
  718. //
  719. // Now we can do the simple deletion for the no right child case,
  720. // plus we know there is a left child.
  721. //
  722. }
  723. else {
  724. Parent = SANITIZE_PARENT_NODE (EasyDelete->u1.Parent);
  725. if (MiIsLeftChild(EasyDelete)) {
  726. Parent->LeftChild = EasyDelete->LeftChild;
  727. }
  728. else {
  729. Parent->RightChild = EasyDelete->LeftChild;
  730. a = 1;
  731. }
  732. EasyDelete->LeftChild->u1.Parent = MI_MAKE_PARENT (Parent,
  733. EasyDelete->LeftChild->u1.Balance);
  734. }
  735. //
  736. // For delete rebalancing, set the balance at the root to 0 to properly
  737. // terminate the rebalance without special tests, and to be able to detect
  738. // if the depth of the tree actually decreased.
  739. //
  740. Table->BalancedRoot.u1.Balance = 0;
  741. P = SANITIZE_PARENT_NODE (EasyDelete->u1.Parent);
  742. //
  743. // Loop until the tree is balanced.
  744. //
  745. while (TRUE) {
  746. //
  747. // First handle the case where the tree became more balanced. Zero
  748. // the balance factor, calculate a for the next loop and move on to
  749. // the parent.
  750. //
  751. if ((SCHAR) P->u1.Balance == a) {
  752. P->u1.Balance = 0;
  753. //
  754. // If this node is curently balanced, we can show it is now unbalanced
  755. // and terminate the scan since the subtree length has not changed.
  756. // (This may be the root, since we set Balance to 0 above!)
  757. //
  758. }
  759. else if (P->u1.Balance == 0) {
  760. PRINT("REBADJ D: Node %p, Bal %x -> %x\n", P, P->u1.Balance, -a);
  761. COUNT_BALANCE_MAX ((SCHAR)-a);
  762. P->u1.Balance = -a;
  763. //
  764. // If we shortened the depth all the way back to the root, then
  765. // the tree really has one less level.
  766. //
  767. if (Table->BalancedRoot.u1.Balance != 0) {
  768. Table->DepthOfTree -= 1;
  769. }
  770. break;
  771. //
  772. // Otherwise we made the short side 2 levels less than the long side,
  773. // and rebalancing is required. On return, some node has been promoted
  774. // to above node P. If Case 3 from Knuth was not encountered, then we
  775. // want to effectively resume rebalancing from P's original parent which
  776. // is effectively its grandparent now.
  777. //
  778. }
  779. else {
  780. //
  781. // We are done if Case 3 was hit, i.e., the depth of this subtree is
  782. // now the same as before the delete.
  783. //
  784. if (MiRebalanceNode(P)) {
  785. break;
  786. }
  787. P = SANITIZE_PARENT_NODE (P->u1.Parent);
  788. }
  789. a = -1;
  790. if (MiIsRightChild(P)) {
  791. a = 1;
  792. }
  793. P = SANITIZE_PARENT_NODE (P->u1.Parent);
  794. }
  795. //
  796. // Finally, if we actually deleted a predecessor/successor of the
  797. // NodeToDelete, we will link him back into the tree to replace
  798. // NodeToDelete before returning. Note that NodeToDelete did have
  799. // both child links filled in, but that may no longer be the case
  800. // at this point.
  801. //
  802. if (NodeToDelete != EasyDelete) {
  803. //
  804. // Note carefully - VADs are of differing sizes therefore it is not safe
  805. // to just overlay the EasyDelete node with the NodeToDelete like the
  806. // rtl avl code does.
  807. //
  808. // Copy just the links, preserving the rest of the original EasyDelete
  809. // VAD.
  810. //
  811. EasyDelete->u1.Parent = NodeToDelete->u1.Parent;
  812. EasyDelete->LeftChild = NodeToDelete->LeftChild;
  813. EasyDelete->RightChild = NodeToDelete->RightChild;
  814. if (MiIsLeftChild(NodeToDelete)) {
  815. Parent = SANITIZE_PARENT_NODE (EasyDelete->u1.Parent);
  816. Parent->LeftChild = EasyDelete;
  817. }
  818. else {
  819. ASSERT(MiIsRightChild(NodeToDelete));
  820. Parent = SANITIZE_PARENT_NODE (EasyDelete->u1.Parent);
  821. Parent->RightChild = EasyDelete;
  822. }
  823. if (EasyDelete->LeftChild != NULL) {
  824. EasyDelete->LeftChild->u1.Parent = MI_MAKE_PARENT (EasyDelete,
  825. EasyDelete->LeftChild->u1.Balance);
  826. }
  827. if (EasyDelete->RightChild != NULL) {
  828. EasyDelete->RightChild->u1.Parent = MI_MAKE_PARENT (EasyDelete,
  829. EasyDelete->RightChild->u1.Balance);
  830. }
  831. }
  832. Table->NumberGenericTableElements -= 1;
  833. //
  834. // Sanity check tree size and depth.
  835. //
  836. ASSERT((Table->NumberGenericTableElements >= MiWorstCaseFill[Table->DepthOfTree]) &&
  837. (Table->NumberGenericTableElements <= MiBestCaseFill[Table->DepthOfTree]));
  838. return;
  839. }
  840. PMMADDRESS_NODE
  841. MiRealSuccessor (
  842. IN PMMADDRESS_NODE Links
  843. )
  844. /*++
  845. Routine Description:
  846. This function takes as input a pointer to a balanced link
  847. in a tree and returns a pointer to the successor of the input node within
  848. the entire tree. If there is not a successor, the return value is NULL.
  849. Arguments:
  850. Links - Supplies a pointer to a balanced link in a tree.
  851. Return Value:
  852. PMMADDRESS_NODE - returns a pointer to the successor in the entire tree
  853. --*/
  854. {
  855. PMMADDRESS_NODE Ptr;
  856. /*
  857. First check to see if there is a right subtree to the input link
  858. if there is then the real successor is the left most node in
  859. the right subtree. That is find and return S in the following diagram
  860. Links
  861. \
  862. .
  863. .
  864. .
  865. /
  866. S
  867. \
  868. */
  869. if ((Ptr = Links->RightChild) != NULL) {
  870. while (Ptr->LeftChild != NULL) {
  871. Ptr = Ptr->LeftChild;
  872. }
  873. return Ptr;
  874. }
  875. /*
  876. We do not have a right child so check to see if have a parent and if
  877. so find the first ancestor that we are a left decendant of. That
  878. is find and return S in the following diagram
  879. S
  880. /
  881. .
  882. .
  883. .
  884. Links
  885. Note that this code depends on how the BalancedRoot is initialized,
  886. which is Parent points to self, and the RightChild points to an
  887. actual node which is the root of the tree, and LeftChild does not
  888. point to self.
  889. */
  890. Ptr = Links;
  891. while (MiIsRightChild(Ptr)) {
  892. Ptr = SANITIZE_PARENT_NODE (Ptr->u1.Parent);
  893. }
  894. if (MiIsLeftChild(Ptr)) {
  895. return SANITIZE_PARENT_NODE (Ptr->u1.Parent);
  896. }
  897. //
  898. // Otherwise we are do not have a real successor so we simply return NULL.
  899. //
  900. // This can only occur when we get back to the root, and we can tell
  901. // that since the Root is its own parent.
  902. //
  903. ASSERT (SANITIZE_PARENT_NODE(Ptr->u1.Parent) == Ptr);
  904. return NULL;
  905. }
  906. PMMADDRESS_NODE
  907. MiRealPredecessor (
  908. IN PMMADDRESS_NODE Links
  909. )
  910. /*++
  911. Routine Description:
  912. The RealPredecessor function takes as input a pointer to a balanced link
  913. in a tree and returns a pointer to the predecessor of the input node
  914. within the entire tree. If there is not a predecessor, the return value
  915. is NULL.
  916. Arguments:
  917. Links - Supplies a pointer to a balanced link in a tree.
  918. Return Value:
  919. PMMADDRESS_NODE - returns a pointer to the predecessor in the entire tree
  920. --*/
  921. {
  922. PMMADDRESS_NODE Ptr;
  923. PMMADDRESS_NODE Parent;
  924. PMMADDRESS_NODE GrandParent;
  925. /*
  926. First check to see if there is a left subtree to the input link
  927. if there is then the real predecessor is the right most node in
  928. the left subtree. That is find and return P in the following diagram
  929. Links
  930. /
  931. .
  932. .
  933. .
  934. P
  935. /
  936. */
  937. if ((Ptr = Links->LeftChild) != NULL) {
  938. while (Ptr->RightChild != NULL) {
  939. Ptr = Ptr->RightChild;
  940. }
  941. return Ptr;
  942. }
  943. /*
  944. We do not have a left child so check to see if have a parent and if
  945. so find the first ancestor that we are a right decendant of. That
  946. is find and return P in the following diagram
  947. P
  948. \
  949. .
  950. .
  951. .
  952. Links
  953. Note that this code depends on how the BalancedRoot is initialized,
  954. which is Parent points to self, and the RightChild points to an
  955. actual node which is the root of the tree.
  956. */
  957. Ptr = Links;
  958. while (MiIsLeftChild(Ptr)) {
  959. Ptr = SANITIZE_PARENT_NODE (Ptr->u1.Parent);
  960. }
  961. if (MiIsRightChild(Ptr)) {
  962. Parent = SANITIZE_PARENT_NODE (Ptr->u1.Parent);
  963. GrandParent = SANITIZE_PARENT_NODE (Parent->u1.Parent);
  964. if (GrandParent != Parent) {
  965. return Parent;
  966. }
  967. }
  968. //
  969. // Otherwise we are do not have a real predecessor so we simply return
  970. // NULL.
  971. //
  972. return NULL;
  973. }
  974. VOID
  975. MiInitializeVadTableAvl (
  976. IN PMM_AVL_TABLE Table
  977. )
  978. /*++
  979. Routine Description:
  980. This routine initializes a table.
  981. Arguments:
  982. Table - Pointer to the generic table to be initialized.
  983. Return Value:
  984. None.
  985. --*/
  986. {
  987. #if DBG
  988. ULONG i;
  989. for (i = 2; i < 33; i += 1) {
  990. ASSERT(MiWorstCaseFill[i] == (1 + MiWorstCaseFill[i - 1] + MiWorstCaseFill[i - 2]));
  991. }
  992. #endif
  993. //
  994. // Initialize each field in the argument Table.
  995. //
  996. RtlZeroMemory (Table, sizeof(MM_AVL_TABLE));
  997. Table->BalancedRoot.u1.Parent = MI_MAKE_PARENT (&Table->BalancedRoot, 0);
  998. }
  999. VOID
  1000. FASTCALL
  1001. MiInsertNode (
  1002. IN PMMADDRESS_NODE NodeToInsert,
  1003. IN PMM_AVL_TABLE Table
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This function inserts a new element in a table.
  1008. Arguments:
  1009. NodeToInsert - The initialized address node to insert.
  1010. Table - Pointer to the table in which to insert the new node.
  1011. Return Value:
  1012. None.
  1013. Environment:
  1014. Kernel mode. The PFN lock is held for some of the tables.
  1015. --*/
  1016. {
  1017. //
  1018. // Holds a pointer to the node in the table or what would be the
  1019. // parent of the node.
  1020. //
  1021. PMMADDRESS_NODE NodeOrParent;
  1022. TABLE_SEARCH_RESULT SearchResult;
  1023. ASSERT((Table->NumberGenericTableElements >= MiWorstCaseFill[Table->DepthOfTree]) &&
  1024. (Table->NumberGenericTableElements <= MiBestCaseFill[Table->DepthOfTree]));
  1025. SearchResult = MiFindNodeOrParent (Table,
  1026. NodeToInsert->StartingVpn,
  1027. &NodeOrParent);
  1028. ASSERT (SearchResult != TableFoundNode);
  1029. //
  1030. // The node wasn't in the (possibly empty) tree.
  1031. //
  1032. // We just check that the table isn't getting too big.
  1033. //
  1034. ASSERT (Table->NumberGenericTableElements != (MAXULONG-1));
  1035. NodeToInsert->LeftChild = NULL;
  1036. NodeToInsert->RightChild = NULL;
  1037. Table->NumberGenericTableElements += 1;
  1038. //
  1039. // Insert the new node in the tree.
  1040. //
  1041. if (SearchResult == TableEmptyTree) {
  1042. Table->BalancedRoot.RightChild = NodeToInsert;
  1043. NodeToInsert->u1.Parent = &Table->BalancedRoot;
  1044. ASSERT (NodeToInsert->u1.Balance == 0);
  1045. ASSERT(Table->DepthOfTree == 0);
  1046. Table->DepthOfTree = 1;
  1047. ASSERT((Table->NumberGenericTableElements >= MiWorstCaseFill[Table->DepthOfTree]) &&
  1048. (Table->NumberGenericTableElements <= MiBestCaseFill[Table->DepthOfTree]));
  1049. }
  1050. else {
  1051. PMMADDRESS_NODE R = NodeToInsert;
  1052. PMMADDRESS_NODE S = NodeOrParent;
  1053. if (SearchResult == TableInsertAsLeft) {
  1054. NodeOrParent->LeftChild = NodeToInsert;
  1055. }
  1056. else {
  1057. NodeOrParent->RightChild = NodeToInsert;
  1058. }
  1059. NodeToInsert->u1.Parent = NodeOrParent;
  1060. ASSERT (NodeToInsert->u1.Balance == 0);
  1061. //
  1062. // The above completes the standard binary tree insertion, which
  1063. // happens to correspond to steps A1-A5 of Knuth's "balanced tree
  1064. // search and insertion" algorithm. Now comes the time to adjust
  1065. // balance factors and possibly do a single or double rotation as
  1066. // in steps A6-A10.
  1067. //
  1068. // Set the Balance factor in the root to a convenient value
  1069. // to simplify loop control.
  1070. //
  1071. PRINT("REBADJ E: Table %p, Bal %x -> %x\n", Table, Table->BalancedRoot.u1.Balance, -1);
  1072. COUNT_BALANCE_MAX ((SCHAR)-1);
  1073. Table->BalancedRoot.u1.Balance = (ULONG_PTR) -1;
  1074. //
  1075. // Now loop to adjust balance factors and see if any balance operations
  1076. // must be performed, using NodeOrParent to ascend the tree.
  1077. //
  1078. do {
  1079. SCHAR a;
  1080. //
  1081. // Calculate the next adjustment.
  1082. //
  1083. a = 1;
  1084. if (MiIsLeftChild (R)) {
  1085. a = -1;
  1086. }
  1087. PRINT("LW 0: Table %p, Bal %x, %x\n", Table, Table->BalancedRoot.u1.Balance, a);
  1088. PRINT("LW 0: R Node %p, Bal %x, %x\n", R, R->u1.Balance, 1);
  1089. PRINT("LW 0: S Node %p, Bal %x, %x\n", S, S->u1.Balance, 1);
  1090. //
  1091. // If this node was balanced, show that it is no longer and
  1092. // keep looping. This is essentially A6 of Knuth's algorithm,
  1093. // where he updates all of the intermediate nodes on the
  1094. // insertion path which previously had balance factors of 0.
  1095. // We are looping up the tree via Parent pointers rather than
  1096. // down the tree as in Knuth.
  1097. //
  1098. if (S->u1.Balance == 0) {
  1099. PRINT("REBADJ F: Node %p, Bal %x -> %x\n", S, S->u1.Balance, a);
  1100. COUNT_BALANCE_MAX ((SCHAR)a);
  1101. S->u1.Balance = a;
  1102. R = S;
  1103. S = SANITIZE_PARENT_NODE (S->u1.Parent);
  1104. }
  1105. else if ((SCHAR) S->u1.Balance != a) {
  1106. PRINT("LW 1: Table %p, Bal %x, %x\n", Table, Table->BalancedRoot.u1.Balance, -1);
  1107. //
  1108. // If this node has the opposite balance, then the tree got
  1109. // more balanced (or we hit the root) and we are done.
  1110. //
  1111. // Step A7.ii
  1112. //
  1113. S->u1.Balance = 0;
  1114. //
  1115. // If S is actually the root, then this means the depth
  1116. // of the tree just increased by 1! (This is essentially
  1117. // A7.i, but we just initialized the root balance to force
  1118. // it through here.)
  1119. //
  1120. if (Table->BalancedRoot.u1.Balance == 0) {
  1121. Table->DepthOfTree += 1;
  1122. }
  1123. break;
  1124. }
  1125. else {
  1126. PRINT("LW 2: Table %p, Bal %x, %x\n", Table, Table->BalancedRoot.u1.Balance, -1);
  1127. //
  1128. // The tree became unbalanced (path length differs
  1129. // by 2 below us) and we need to do one of the balancing
  1130. // operations, and then we are done. The RebalanceNode routine
  1131. // does steps A7.iii, A8 and A9.
  1132. //
  1133. MiRebalanceNode (S);
  1134. break;
  1135. }
  1136. PRINT("LW 3: Table %p, Bal %x, %x\n", Table, Table->BalancedRoot.u1.Balance, -1);
  1137. } while (TRUE);
  1138. PRINT("LW 4: Table %p, Bal %x, %x\n", Table, Table->BalancedRoot.u1.Balance, -1);
  1139. }
  1140. //
  1141. // Sanity check tree size and depth.
  1142. //
  1143. ASSERT((Table->NumberGenericTableElements >= MiWorstCaseFill[Table->DepthOfTree]) &&
  1144. (Table->NumberGenericTableElements <= MiBestCaseFill[Table->DepthOfTree]));
  1145. return;
  1146. }
  1147. PVOID
  1148. MiEnumerateGenericTableWithoutSplayingAvl (
  1149. IN PMM_AVL_TABLE Table,
  1150. IN PVOID *RestartKey
  1151. )
  1152. /*++
  1153. Routine Description:
  1154. The function EnumerateGenericTableWithoutSplayingAvl will return to the
  1155. caller one-by-one the elements of of a table. The return value is a
  1156. pointer to the user defined structure associated with the element.
  1157. The input parameter RestartKey indicates if the enumeration should
  1158. start from the beginning or should return the next element. If the
  1159. are no more new elements to return the return value is NULL. As an
  1160. example of its use, to enumerate all of the elements in a table the
  1161. user would write:
  1162. *RestartKey = NULL;
  1163. for (ptr = EnumerateGenericTableWithoutSplayingAvl(Table, &RestartKey);
  1164. ptr != NULL;
  1165. ptr = EnumerateGenericTableWithoutSplayingAvl(Table, &RestartKey)) {
  1166. :
  1167. }
  1168. Arguments:
  1169. Table - Pointer to the generic table to enumerate.
  1170. RestartKey - Pointer that indicates if we should restart or return the next
  1171. element. If the contents of RestartKey is NULL, the search
  1172. will be started from the beginning.
  1173. Return Value:
  1174. PVOID - Pointer to the user data.
  1175. --*/
  1176. {
  1177. PMMADDRESS_NODE NodeToReturn;
  1178. if (Table->NumberGenericTableElements == 0) {
  1179. //
  1180. // Nothing to do if the table is empty.
  1181. //
  1182. return NULL;
  1183. }
  1184. //
  1185. // If the restart flag is true then go to the least element
  1186. // in the tree.
  1187. //
  1188. if (*RestartKey == NULL) {
  1189. //
  1190. // Loop until we find the leftmost child of the root.
  1191. //
  1192. for (NodeToReturn = Table->BalancedRoot.RightChild;
  1193. NodeToReturn->LeftChild;
  1194. NodeToReturn = NodeToReturn->LeftChild) {
  1195. NOTHING;
  1196. }
  1197. *RestartKey = NodeToReturn;
  1198. }
  1199. else {
  1200. //
  1201. // The caller has passed in the previous entry found
  1202. // in the table to enable us to continue the search. We call
  1203. // RealSuccessor to step to the next element in the tree.
  1204. //
  1205. NodeToReturn = MiRealSuccessor (*RestartKey);
  1206. if (NodeToReturn) {
  1207. *RestartKey = NodeToReturn;
  1208. }
  1209. }
  1210. //
  1211. // Return the found element.
  1212. //
  1213. return NodeToReturn;
  1214. }
  1215. PMMADDRESS_NODE
  1216. FASTCALL
  1217. MiGetNextNode (
  1218. IN PMMADDRESS_NODE Node
  1219. )
  1220. /*++
  1221. Routine Description:
  1222. This function locates the virtual address descriptor which contains
  1223. the address range which logically follows the specified address range.
  1224. Arguments:
  1225. Node - Supplies a pointer to a virtual address descriptor.
  1226. Return Value:
  1227. Returns a pointer to the virtual address descriptor containing the
  1228. next address range, NULL if none.
  1229. --*/
  1230. {
  1231. PMMADDRESS_NODE Next;
  1232. PMMADDRESS_NODE Parent;
  1233. PMMADDRESS_NODE Left;
  1234. Next = Node;
  1235. if (Next->RightChild == NULL) {
  1236. do {
  1237. Parent = SANITIZE_PARENT_NODE (Next->u1.Parent);
  1238. ASSERT (Parent != NULL);
  1239. if (Parent == Next) {
  1240. return NULL;
  1241. }
  1242. //
  1243. // Locate the first ancestor of this node of which this
  1244. // node is the left child of and return that node as the
  1245. // next element.
  1246. //
  1247. if (Parent->LeftChild == Next) {
  1248. return Parent;
  1249. }
  1250. Next = Parent;
  1251. } while (TRUE);
  1252. }
  1253. //
  1254. // A right child exists, locate the left most child of that right child.
  1255. //
  1256. Next = Next->RightChild;
  1257. do {
  1258. Left = Next->LeftChild;
  1259. if (Left == NULL) {
  1260. break;
  1261. }
  1262. Next = Left;
  1263. } while (TRUE);
  1264. return Next;
  1265. }
  1266. PMMADDRESS_NODE
  1267. FASTCALL
  1268. MiGetPreviousNode (
  1269. IN PMMADDRESS_NODE Node
  1270. )
  1271. /*++
  1272. Routine Description:
  1273. This function locates the virtual address descriptor which contains
  1274. the address range which logically precedes the specified virtual
  1275. address descriptor.
  1276. Arguments:
  1277. Node - Supplies a pointer to a virtual address descriptor.
  1278. Return Value:
  1279. Returns a pointer to the virtual address descriptor containing the
  1280. next address range, NULL if none.
  1281. --*/
  1282. {
  1283. PMMADDRESS_NODE Previous;
  1284. PMMADDRESS_NODE Parent;
  1285. Previous = Node;
  1286. if (Previous->LeftChild == NULL) {
  1287. ASSERT (Previous->u1.Parent != NULL);
  1288. Parent = SANITIZE_PARENT_NODE (Previous->u1.Parent);
  1289. while (Parent != Previous) {
  1290. //
  1291. // Locate the first ancestor of this node of which this
  1292. // node is the right child of and return that node as the
  1293. // Previous element.
  1294. //
  1295. if (Parent->RightChild == Previous) {
  1296. if (Parent == SANITIZE_PARENT_NODE (Parent->u1.Parent)) {
  1297. return NULL;
  1298. }
  1299. return Parent;
  1300. }
  1301. Previous = Parent;
  1302. Parent = SANITIZE_PARENT_NODE (Previous->u1.Parent);
  1303. }
  1304. return NULL;
  1305. }
  1306. //
  1307. // A left child exists, locate the right most child of that left child.
  1308. //
  1309. Previous = Previous->LeftChild;
  1310. while (Previous->RightChild != NULL) {
  1311. Previous = Previous->RightChild;
  1312. }
  1313. return Previous;
  1314. }
  1315. PMMADDRESS_NODE
  1316. FASTCALL
  1317. MiLocateAddressInTree (
  1318. IN ULONG_PTR Vpn,
  1319. IN PMM_AVL_TABLE Table
  1320. )
  1321. /*++
  1322. Routine Description:
  1323. The function locates the virtual address descriptor which describes
  1324. a given address.
  1325. Arguments:
  1326. Vpn - Supplies the virtual page number to locate a descriptor for.
  1327. Return Value:
  1328. Returns a pointer to the virtual address descriptor which contains
  1329. the supplied virtual address or NULL if none was located.
  1330. --*/
  1331. {
  1332. PVOID NodeOrParent;
  1333. TABLE_SEARCH_RESULT SearchResult;
  1334. //
  1335. // Lookup the element and save the result.
  1336. //
  1337. SearchResult = MiFindNodeOrParent (Table,
  1338. Vpn,
  1339. (PMMADDRESS_NODE *) &NodeOrParent);
  1340. if (SearchResult == TableFoundNode) {
  1341. //
  1342. // Return the VAD.
  1343. //
  1344. return (PMMADDRESS_NODE) NodeOrParent;
  1345. }
  1346. return NULL;
  1347. }
  1348. NTSTATUS
  1349. MiFindEmptyAddressRangeInTree (
  1350. IN SIZE_T SizeOfRange,
  1351. IN ULONG_PTR Alignment,
  1352. IN PMM_AVL_TABLE Table,
  1353. OUT PMMADDRESS_NODE *PreviousVad,
  1354. OUT PVOID *Base
  1355. )
  1356. /*++
  1357. Routine Description:
  1358. The function examines the virtual address descriptors to locate
  1359. an unused range of the specified size and returns the starting
  1360. address of the range.
  1361. Arguments:
  1362. SizeOfRange - Supplies the size in bytes of the range to locate.
  1363. Alignment - Supplies the alignment for the address. Must be
  1364. a power of 2 and greater than the page_size.
  1365. Table - Supplies the root of the tree to search through.
  1366. PreviousVad - Supplies the Vad which is before this the found
  1367. address range.
  1368. Base - Receives the starting address of a suitable range on success.
  1369. Return Value:
  1370. NTSTATUS.
  1371. --*/
  1372. {
  1373. PMMADDRESS_NODE Node;
  1374. PMMADDRESS_NODE NextNode;
  1375. ULONG_PTR AlignmentVpn;
  1376. ULONG_PTR SizeOfRangeVpn;
  1377. AlignmentVpn = Alignment >> PAGE_SHIFT;
  1378. //
  1379. // Locate the node with the lowest starting address.
  1380. //
  1381. ASSERT (SizeOfRange != 0);
  1382. SizeOfRangeVpn = (SizeOfRange + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  1383. ASSERT (SizeOfRangeVpn != 0);
  1384. if (Table->NumberGenericTableElements == 0) {
  1385. *Base = MM_LOWEST_USER_ADDRESS;
  1386. return STATUS_SUCCESS;
  1387. }
  1388. Node = Table->BalancedRoot.RightChild;
  1389. while (Node->LeftChild != NULL) {
  1390. Node = Node->LeftChild;
  1391. }
  1392. //
  1393. // Check to see if a range exists between the lowest address VAD
  1394. // and lowest user address.
  1395. //
  1396. if (Node->StartingVpn > MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS)) {
  1397. if (SizeOfRangeVpn <
  1398. (Node->StartingVpn - MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS))) {
  1399. *PreviousVad = NULL;
  1400. *Base = MM_LOWEST_USER_ADDRESS;
  1401. return STATUS_SUCCESS;
  1402. }
  1403. }
  1404. do {
  1405. NextNode = MiGetNextNode (Node);
  1406. if (NextNode != NULL) {
  1407. if (SizeOfRangeVpn <=
  1408. ((ULONG_PTR)NextNode->StartingVpn -
  1409. MI_ROUND_TO_SIZE(1 + Node->EndingVpn,
  1410. AlignmentVpn))) {
  1411. //
  1412. // Check to ensure that the ending address aligned upwards
  1413. // is not greater than the starting address.
  1414. //
  1415. if ((ULONG_PTR)NextNode->StartingVpn >
  1416. MI_ROUND_TO_SIZE(1 + Node->EndingVpn,
  1417. AlignmentVpn)) {
  1418. *PreviousVad = Node;
  1419. *Base = (PVOID) MI_ROUND_TO_SIZE(
  1420. (ULONG_PTR)MI_VPN_TO_VA_ENDING(Node->EndingVpn),
  1421. Alignment);
  1422. return STATUS_SUCCESS;
  1423. }
  1424. }
  1425. } else {
  1426. //
  1427. // No more descriptors, check to see if this fits into the remainder
  1428. // of the address space.
  1429. //
  1430. if ((((ULONG_PTR)Node->EndingVpn + MI_VA_TO_VPN(X64K)) <
  1431. MI_VA_TO_VPN (MM_HIGHEST_VAD_ADDRESS))
  1432. &&
  1433. (SizeOfRange <=
  1434. ((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS -
  1435. (ULONG_PTR)MI_ROUND_TO_SIZE(
  1436. (ULONG_PTR)MI_VPN_TO_VA(Node->EndingVpn), Alignment)))) {
  1437. *PreviousVad = Node;
  1438. *Base = (PVOID) MI_ROUND_TO_SIZE(
  1439. (ULONG_PTR)MI_VPN_TO_VA_ENDING(Node->EndingVpn),
  1440. Alignment);
  1441. return STATUS_SUCCESS;
  1442. }
  1443. return STATUS_NO_MEMORY;
  1444. }
  1445. Node = NextNode;
  1446. } while (TRUE);
  1447. }
  1448. NTSTATUS
  1449. MiFindEmptyAddressRangeDownTree (
  1450. IN SIZE_T SizeOfRange,
  1451. IN PVOID HighestAddressToEndAt,
  1452. IN ULONG_PTR Alignment,
  1453. IN PMM_AVL_TABLE Table,
  1454. OUT PVOID *Base
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. The function examines the virtual address descriptors to locate
  1459. an unused range of the specified size and returns the starting
  1460. address of the range. The function examines from the high
  1461. addresses down and ensures that starting address is less than
  1462. the specified address.
  1463. Note this cannot be used for the based section tree because only
  1464. the nodes in that tree are stored as VAs instead of VPNs.
  1465. Arguments:
  1466. SizeOfRange - Supplies the size in bytes of the range to locate.
  1467. HighestAddressToEndAt - Supplies the virtual address that limits
  1468. the value of the ending address. The ending
  1469. address of the located range must be less
  1470. than this address.
  1471. Alignment - Supplies the alignment for the address. Must be
  1472. a power of 2 and greater than the page_size.
  1473. Table - Supplies the root of the tree to search through.
  1474. Base - Receives the starting address of a suitable range on success.
  1475. Return Value:
  1476. NTSTATUS.
  1477. --*/
  1478. {
  1479. PMMADDRESS_NODE Node;
  1480. PMMADDRESS_NODE PreviousNode;
  1481. ULONG_PTR AlignedEndingVa;
  1482. PVOID OptimalStart;
  1483. ULONG_PTR OptimalStartVpn;
  1484. ULONG_PTR HighestVpn;
  1485. ULONG_PTR AlignmentVpn;
  1486. //
  1487. // Note this cannot be used for the based section tree because only
  1488. // the nodes in that tree are stored as VAs instead of VPNs.
  1489. //
  1490. ASSERT (Table != &MmSectionBasedRoot);
  1491. SizeOfRange = MI_ROUND_TO_SIZE (SizeOfRange, PAGE_SIZE);
  1492. if (((ULONG_PTR)HighestAddressToEndAt + 1) < SizeOfRange) {
  1493. return STATUS_NO_MEMORY;
  1494. }
  1495. ASSERT (HighestAddressToEndAt != NULL);
  1496. ASSERT (HighestAddressToEndAt <= (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
  1497. HighestVpn = MI_VA_TO_VPN (HighestAddressToEndAt);
  1498. //
  1499. // Locate the Node with the highest starting address.
  1500. //
  1501. OptimalStart = (PVOID)(MI_ALIGN_TO_SIZE(
  1502. (((ULONG_PTR)HighestAddressToEndAt + 1) - SizeOfRange),
  1503. Alignment));
  1504. if (Table->NumberGenericTableElements == 0) {
  1505. //
  1506. // The tree is empty, any range is okay.
  1507. //
  1508. *Base = OptimalStart;
  1509. return STATUS_SUCCESS;
  1510. }
  1511. Node = (PMMADDRESS_NODE) Table->BalancedRoot.RightChild;
  1512. //
  1513. // See if an empty slot exists to hold this range, locate the largest
  1514. // element in the tree.
  1515. //
  1516. while (Node->RightChild != NULL) {
  1517. Node = Node->RightChild;
  1518. }
  1519. //
  1520. // Check to see if a range exists between the highest address VAD
  1521. // and the highest address to end at.
  1522. //
  1523. AlignedEndingVa = (ULONG_PTR)MI_ROUND_TO_SIZE ((ULONG_PTR)MI_VPN_TO_VA_ENDING (Node->EndingVpn),
  1524. Alignment);
  1525. if (AlignedEndingVa < (ULONG_PTR)HighestAddressToEndAt) {
  1526. if ( SizeOfRange < ((ULONG_PTR)HighestAddressToEndAt - AlignedEndingVa)) {
  1527. *Base = MI_ALIGN_TO_SIZE(
  1528. ((ULONG_PTR)HighestAddressToEndAt - SizeOfRange),
  1529. Alignment);
  1530. return STATUS_SUCCESS;
  1531. }
  1532. }
  1533. //
  1534. // Walk the tree backwards looking for a fit.
  1535. //
  1536. OptimalStartVpn = MI_VA_TO_VPN (OptimalStart);
  1537. AlignmentVpn = MI_VA_TO_VPN (Alignment);
  1538. do {
  1539. PreviousNode = MiGetPreviousNode (Node);
  1540. if (PreviousNode != NULL) {
  1541. //
  1542. // Is the ending Va below the top of the address to end at.
  1543. //
  1544. if (PreviousNode->EndingVpn < OptimalStartVpn) {
  1545. if ((SizeOfRange >> PAGE_SHIFT) <=
  1546. ((ULONG_PTR)Node->StartingVpn -
  1547. (ULONG_PTR)MI_ROUND_TO_SIZE(1 + PreviousNode->EndingVpn,
  1548. AlignmentVpn))) {
  1549. //
  1550. // See if the optimal start will fit between these
  1551. // two VADs.
  1552. //
  1553. if ((OptimalStartVpn > PreviousNode->EndingVpn) &&
  1554. (HighestVpn < Node->StartingVpn)) {
  1555. *Base = OptimalStart;
  1556. return STATUS_SUCCESS;
  1557. }
  1558. //
  1559. // Check to ensure that the ending address aligned upwards
  1560. // is not greater than the starting address.
  1561. //
  1562. if ((ULONG_PTR)Node->StartingVpn >
  1563. (ULONG_PTR)MI_ROUND_TO_SIZE(1 + PreviousNode->EndingVpn,
  1564. AlignmentVpn)) {
  1565. *Base = MI_ALIGN_TO_SIZE(
  1566. (ULONG_PTR)MI_VPN_TO_VA (Node->StartingVpn) - SizeOfRange,
  1567. Alignment);
  1568. return STATUS_SUCCESS;
  1569. }
  1570. }
  1571. }
  1572. } else {
  1573. //
  1574. // No more descriptors, check to see if this fits into the remainder
  1575. // of the address space.
  1576. //
  1577. if (Node->StartingVpn > MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS)) {
  1578. if ((SizeOfRange >> PAGE_SHIFT) <=
  1579. ((ULONG_PTR)Node->StartingVpn - MI_VA_TO_VPN (MM_LOWEST_USER_ADDRESS))) {
  1580. //
  1581. // See if the optimal start will fit between these
  1582. // two VADs.
  1583. //
  1584. if (HighestVpn < Node->StartingVpn) {
  1585. *Base = OptimalStart;
  1586. return STATUS_SUCCESS;
  1587. }
  1588. *Base = MI_ALIGN_TO_SIZE(
  1589. (ULONG_PTR)MI_VPN_TO_VA (Node->StartingVpn) - SizeOfRange,
  1590. Alignment);
  1591. return STATUS_SUCCESS;
  1592. }
  1593. }
  1594. return STATUS_NO_MEMORY;
  1595. }
  1596. Node = PreviousNode;
  1597. } while (TRUE);
  1598. }
  1599. NTSTATUS
  1600. MiFindEmptyAddressRangeDownBasedTree (
  1601. IN SIZE_T SizeOfRange,
  1602. IN PVOID HighestAddressToEndAt,
  1603. IN ULONG_PTR Alignment,
  1604. IN PMM_AVL_TABLE Table,
  1605. OUT PVOID *Base
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. The function examines the virtual address descriptors to locate
  1610. an unused range of the specified size and returns the starting
  1611. address of the range. The function examines from the high
  1612. addresses down and ensures that starting address is less than
  1613. the specified address.
  1614. Note this is only used for the based section tree because only
  1615. the nodes in that tree are stored as VAs instead of VPNs.
  1616. Arguments:
  1617. SizeOfRange - Supplies the size in bytes of the range to locate.
  1618. HighestAddressToEndAt - Supplies the virtual address that limits
  1619. the value of the ending address. The ending
  1620. address of the located range must be less
  1621. than this address.
  1622. Alignment - Supplies the alignment for the address. Must be
  1623. a power of 2 and greater than the page_size.
  1624. Table - Supplies the root of the tree to search through.
  1625. Base - Receives the starting address of a suitable range on success.
  1626. Return Value:
  1627. NTSTATUS.
  1628. --*/
  1629. {
  1630. PMMADDRESS_NODE Node;
  1631. PMMADDRESS_NODE PreviousNode;
  1632. ULONG_PTR AlignedEndingVa;
  1633. ULONG_PTR OptimalStart;
  1634. //
  1635. // Note this is only used for the based section tree because only
  1636. // the nodes in that tree are stored as VAs instead of VPNs.
  1637. //
  1638. ASSERT (Table == &MmSectionBasedRoot);
  1639. SizeOfRange = MI_ROUND_TO_SIZE (SizeOfRange, PAGE_SIZE);
  1640. if (((ULONG_PTR)HighestAddressToEndAt + 1) < SizeOfRange) {
  1641. return STATUS_NO_MEMORY;
  1642. }
  1643. ASSERT (HighestAddressToEndAt != NULL);
  1644. ASSERT (HighestAddressToEndAt <= (PVOID)((ULONG_PTR)MM_HIGHEST_VAD_ADDRESS + 1));
  1645. //
  1646. // Locate the node with the highest starting address.
  1647. //
  1648. OptimalStart = (ULONG_PTR) MI_ALIGN_TO_SIZE (
  1649. (((ULONG_PTR)HighestAddressToEndAt + 1) - SizeOfRange),
  1650. Alignment);
  1651. if (Table->NumberGenericTableElements == 0) {
  1652. //
  1653. // The tree is empty, any range is okay.
  1654. //
  1655. *Base = (PVOID) OptimalStart;
  1656. return STATUS_SUCCESS;
  1657. }
  1658. Node = (PMMADDRESS_NODE) Table->BalancedRoot.RightChild;
  1659. //
  1660. // See if an empty slot exists to hold this range, locate the largest
  1661. // element in the tree.
  1662. //
  1663. while (Node->RightChild != NULL) {
  1664. Node = Node->RightChild;
  1665. }
  1666. //
  1667. // Check to see if a range exists between the highest address VAD
  1668. // and the highest address to end at.
  1669. //
  1670. AlignedEndingVa = MI_ROUND_TO_SIZE (Node->EndingVpn, Alignment);
  1671. PRINT("search down0: %p %p %p\n", AlignedEndingVa, HighestAddressToEndAt, SizeOfRange);
  1672. if ((AlignedEndingVa < (ULONG_PTR)HighestAddressToEndAt) &&
  1673. (SizeOfRange < ((ULONG_PTR)HighestAddressToEndAt - AlignedEndingVa))) {
  1674. *Base = MI_ALIGN_TO_SIZE(
  1675. ((ULONG_PTR)HighestAddressToEndAt - SizeOfRange),
  1676. Alignment);
  1677. return STATUS_SUCCESS;
  1678. }
  1679. //
  1680. // Walk the tree backwards looking for a fit.
  1681. //
  1682. do {
  1683. PreviousNode = MiGetPreviousNode (Node);
  1684. PRINT("search down1: %p %p %p %p\n", PreviousNode, Node, OptimalStart, Alignment);
  1685. if (PreviousNode == NULL) {
  1686. break;
  1687. }
  1688. //
  1689. // Is the ending Va below the top of the address to end at.
  1690. //
  1691. if (PreviousNode->EndingVpn < OptimalStart) {
  1692. if (SizeOfRange <= (Node->StartingVpn -
  1693. MI_ROUND_TO_SIZE(1 + PreviousNode->EndingVpn, Alignment))) {
  1694. //
  1695. // See if the optimal start will fit between these two VADs.
  1696. //
  1697. if ((OptimalStart > PreviousNode->EndingVpn) &&
  1698. ((ULONG_PTR) HighestAddressToEndAt < Node->StartingVpn)) {
  1699. *Base = (PVOID) OptimalStart;
  1700. return STATUS_SUCCESS;
  1701. }
  1702. //
  1703. // Check to ensure that the ending address aligned upwards
  1704. // is not greater than the starting address.
  1705. //
  1706. if (Node->StartingVpn >
  1707. MI_ROUND_TO_SIZE(1 + PreviousNode->EndingVpn, Alignment)) {
  1708. *Base = MI_ALIGN_TO_SIZE (Node->StartingVpn - SizeOfRange,
  1709. Alignment);
  1710. return STATUS_SUCCESS;
  1711. }
  1712. }
  1713. }
  1714. Node = PreviousNode;
  1715. } while (TRUE);
  1716. //
  1717. // No more descriptors, check to see if this fits into the remainder
  1718. // of the address space.
  1719. //
  1720. if (Node->StartingVpn > (ULONG_PTR) MM_LOWEST_USER_ADDRESS) {
  1721. if (SizeOfRange <= (Node->StartingVpn - (ULONG_PTR) MM_LOWEST_USER_ADDRESS)) {
  1722. //
  1723. // See if the optimal start will fit between these two VADs.
  1724. //
  1725. if ((ULONG_PTR) HighestAddressToEndAt < Node->StartingVpn) {
  1726. *Base = (PVOID) OptimalStart;
  1727. return STATUS_SUCCESS;
  1728. }
  1729. *Base = MI_ALIGN_TO_SIZE (Node->StartingVpn - SizeOfRange,
  1730. Alignment);
  1731. return STATUS_SUCCESS;
  1732. }
  1733. }
  1734. return STATUS_NO_MEMORY;
  1735. }
  1736. #if !defined (_USERMODE)
  1737. PMMVAD
  1738. FASTCALL
  1739. MiLocateAddress (
  1740. IN PVOID VirtualAddress
  1741. )
  1742. /*++
  1743. Routine Description:
  1744. The function locates the virtual address descriptor which describes
  1745. a given address.
  1746. Arguments:
  1747. VirtualAddress - Supplies the virtual address to locate a descriptor for.
  1748. Table - Supplies the table describing the tree.
  1749. Return Value:
  1750. Returns a pointer to the virtual address descriptor which contains
  1751. the supplied virtual address or NULL if none was located.
  1752. --*/
  1753. {
  1754. PMMVAD FoundVad;
  1755. ULONG_PTR Vpn;
  1756. PMM_AVL_TABLE Table;
  1757. TABLE_SEARCH_RESULT SearchResult;
  1758. Table = &PsGetCurrentProcess ()->VadRoot;
  1759. //
  1760. // Note the NodeHint *MUST* be captured locally - see the synchronization
  1761. // comment below for details.
  1762. //
  1763. FoundVad = (PMMVAD) Table->NodeHint;
  1764. if (FoundVad == NULL) {
  1765. return NULL;
  1766. }
  1767. Vpn = MI_VA_TO_VPN (VirtualAddress);
  1768. if ((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn)) {
  1769. return FoundVad;
  1770. }
  1771. //
  1772. // Lookup the element and save the result.
  1773. //
  1774. SearchResult = MiFindNodeOrParent (Table,
  1775. Vpn,
  1776. (PMMADDRESS_NODE *) &FoundVad);
  1777. if (SearchResult != TableFoundNode) {
  1778. return NULL;
  1779. }
  1780. ASSERT (FoundVad != NULL);
  1781. ASSERT ((Vpn >= FoundVad->StartingVpn) && (Vpn <= FoundVad->EndingVpn));
  1782. //
  1783. // Note the NodeHint field update is not synchronized in all cases, ie:
  1784. // some callers hold the address space mutex and others hold the working
  1785. // set pushlock. It is ok that the update is not synchronized - as long
  1786. // as care is taken above that it is read into a local variable and then
  1787. // referenced. Because no VAD can be removed from the tree without holding
  1788. // both the address space & working set.
  1789. //
  1790. Table->NodeHint = (PVOID) FoundVad;
  1791. //
  1792. // Return the VAD.
  1793. //
  1794. return FoundVad;
  1795. }
  1796. #endif
  1797. #if DBG
  1798. VOID
  1799. MiNodeTreeWalk (
  1800. IN PMM_AVL_TABLE Table
  1801. )
  1802. {
  1803. PVOID RestartKey;
  1804. PMMADDRESS_NODE NewNode;
  1805. PMMADDRESS_NODE PrevNode;
  1806. PMMADDRESS_NODE NextNode;
  1807. RestartKey = NULL;
  1808. do {
  1809. NewNode = MiEnumerateGenericTableWithoutSplayingAvl (Table,
  1810. &RestartKey);
  1811. if (NewNode == NULL) {
  1812. break;
  1813. }
  1814. PrevNode = MiGetPreviousNode (NewNode);
  1815. NextNode = MiGetNextNode (NewNode);
  1816. PRINT ("Node %p %x %x\n",
  1817. NewNode,
  1818. NewNode->StartingVpn,
  1819. NewNode->EndingVpn);
  1820. if (PrevNode != NULL) {
  1821. PRINT ("\tPrevNode %p %x %x\n",
  1822. PrevNode,
  1823. PrevNode->StartingVpn,
  1824. PrevNode->EndingVpn);
  1825. }
  1826. if (NextNode != NULL) {
  1827. PRINT ("\tNextNode %p %x %x\n",
  1828. NextNode,
  1829. NextNode->StartingVpn,
  1830. NextNode->EndingVpn);
  1831. }
  1832. } while (TRUE);
  1833. PRINT ("NumberGenericTableElements = 0x%x, Depth = 0x%x\n",
  1834. Table->NumberGenericTableElements,
  1835. Table->DepthOfTree);
  1836. return;
  1837. }
  1838. #endif
  1839. #if defined (_USERMODE)
  1840. MMADDRESS_NODE MiBalancedLinks;
  1841. MM_AVL_TABLE MiAvlTable;
  1842. MM_AVL_TABLE MmSectionBasedRoot;
  1843. ULONG DeleteRandom = 1;
  1844. #if RANDOM
  1845. #define NUMBER_OF_VADS 32
  1846. #else
  1847. #define NUMBER_OF_VADS 4
  1848. #endif
  1849. int __cdecl
  1850. main(
  1851. int argc,
  1852. PCHAR argv[]
  1853. )
  1854. {
  1855. ULONG i;
  1856. PVOID StartingAddress;
  1857. PVOID EndingAddress;
  1858. NTSTATUS Status;
  1859. PMMADDRESS_NODE NewNode;
  1860. #if RANDOM
  1861. PMMADDRESS_NODE PrevNode;
  1862. ULONG RandomNumber = 0x99887766;
  1863. ULONG_PTR DeleteVpn = 0;
  1864. #endif
  1865. PMM_AVL_TABLE Table;
  1866. SIZE_T CapturedRegionSize;
  1867. UNREFERENCED_PARAMETER (argc);
  1868. UNREFERENCED_PARAMETER (argv);
  1869. #if RANDOM
  1870. Table = &MiAvlTable;
  1871. #else
  1872. Table = &MmSectionBasedRoot;
  1873. #endif
  1874. MiInitializeVadTableAvl (Table);
  1875. for (i = 0; i < NUMBER_OF_VADS; i += 1) {
  1876. NewNode = malloc (sizeof (MMADDRESS_NODE));
  1877. ASSERT (((ULONG_PTR)NewNode & 0x3) == 0);
  1878. if (NewNode == NULL) {
  1879. PRINT ("Malloc failed\n");
  1880. exit (1);
  1881. }
  1882. NewNode->u1.Parent = NULL;
  1883. NewNode->LeftChild = NULL;
  1884. NewNode->RightChild = NULL;
  1885. NewNode->u1.Balance = 0;
  1886. #if RANDOM
  1887. RandomNumber = RtlRandom (&RandomNumber);
  1888. CapturedRegionSize = (SIZE_T) (RandomNumber & 0x1FFFFF);
  1889. Status = MiFindEmptyAddressRangeInTree (CapturedRegionSize,
  1890. 64 * 1024, // align
  1891. Table,
  1892. &PrevNode,
  1893. &StartingAddress);
  1894. #else
  1895. CapturedRegionSize = 0x800000;
  1896. Status = MiFindEmptyAddressRangeDownBasedTree (CapturedRegionSize,
  1897. (PVOID) 0x7f7effff, // highest addr
  1898. 64 * 1024, // align
  1899. Table,
  1900. &StartingAddress);
  1901. #endif
  1902. if (!NT_SUCCESS (Status)) {
  1903. PRINT ("Could not find empty addr range in tree for size %p\n", CapturedRegionSize);
  1904. free (NewNode);
  1905. continue;
  1906. }
  1907. #if RANDOM
  1908. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1909. CapturedRegionSize - 1L) | (PAGE_SIZE - 1L));
  1910. #else
  1911. EndingAddress = (PVOID)(((ULONG_PTR)StartingAddress +
  1912. CapturedRegionSize - 1L));
  1913. #endif
  1914. printf ("Inserting addr range in tree @ %p %p\n", StartingAddress, EndingAddress);
  1915. #if RANDOM
  1916. NewNode->StartingVpn = MI_VA_TO_VPN (StartingAddress);
  1917. NewNode->EndingVpn = MI_VA_TO_VPN (EndingAddress);
  1918. #else
  1919. NewNode->StartingVpn = (ULONG_PTR) StartingAddress;
  1920. NewNode->EndingVpn = (ULONG_PTR) EndingAddress;
  1921. #endif
  1922. MiInsertNode (NewNode, Table);
  1923. #if RANDOM
  1924. RandomNumber = RtlRandom (&RandomNumber);
  1925. if (RandomNumber & 0x3) {
  1926. DeleteVpn = NewNode->StartingVpn;
  1927. }
  1928. if (DeleteRandom && ((i & 0x3) == 0)) {
  1929. NewNode = MiLocateAddressInTree (DeleteVpn, Table);
  1930. printf ("Located node for random deletion - vpn %p @ %p\n", DeleteVpn, NewNode);
  1931. if (NewNode != NULL) {
  1932. MiRemoveNode (NewNode, Table);
  1933. printf ("Removed random node for vpn %p @ %p %p %p\n",
  1934. DeleteVpn, NewNode, NewNode->StartingVpn, NewNode->EndingVpn);
  1935. }
  1936. }
  1937. #endif
  1938. printf ("\n");
  1939. }
  1940. MiNodeTreeWalk (Table);
  1941. NewNode = MiLocateAddressInTree (5, Table);
  1942. printf ("Located node for vpn 5 @ %p\n", NewNode);
  1943. if (NewNode != NULL) {
  1944. MiRemoveNode (NewNode, Table);
  1945. printf ("Removed node for vpn 5 @ %p\n", NewNode);
  1946. }
  1947. NewNode = MiLocateAddressInTree (5, Table);
  1948. printf("Located node for vpn 5 @ %p\n", NewNode);
  1949. printf("all done, balmin=%x, balmax=%x\n", BalMin, BalMax);
  1950. return 0;
  1951. }
  1952. #endif