Source code of Windows XP (NT5)
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.

2804 lines
63 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. range.c
  5. Abstract:
  6. Kernel-mode range list support for arbiters
  7. Author:
  8. Andy Thornton (andrewth) 02/17/97
  9. Revision History:
  10. --*/
  11. #include "ntrtlp.h"
  12. #include "range.h"
  13. #if DBG
  14. //
  15. // Debug print level:
  16. // -1 = no messages
  17. // 0 = vital messages only
  18. // 1 = call trace
  19. // 2 = verbose messages
  20. //
  21. LONG RtlRangeDebugLevel = 0;
  22. #endif
  23. NTSTATUS
  24. RtlpAddRange(
  25. IN OUT PLIST_ENTRY ListHead,
  26. IN PRTLP_RANGE_LIST_ENTRY Entry,
  27. IN ULONG AddRangeFlags
  28. );
  29. NTSTATUS
  30. RtlpAddToMergedRange(
  31. IN PRTLP_RANGE_LIST_ENTRY Merged,
  32. IN PRTLP_RANGE_LIST_ENTRY Entry,
  33. IN ULONG AddRangeFlags
  34. );
  35. NTSTATUS
  36. RtlpConvertToMergedRange(
  37. IN PRTLP_RANGE_LIST_ENTRY Entry
  38. );
  39. PRTLP_RANGE_LIST_ENTRY
  40. RtlpCreateRangeListEntry(
  41. IN ULONGLONG Start,
  42. IN ULONGLONG End,
  43. IN UCHAR Attributes,
  44. IN PVOID UserData,
  45. IN PVOID Owner
  46. );
  47. NTSTATUS
  48. RtlpAddIntersectingRanges(
  49. IN PLIST_ENTRY ListHead,
  50. IN PRTLP_RANGE_LIST_ENTRY First,
  51. IN PRTLP_RANGE_LIST_ENTRY Entry,
  52. IN ULONG AddRangeFlags
  53. );
  54. NTSTATUS
  55. RtlpDeleteFromMergedRange(
  56. IN PRTLP_RANGE_LIST_ENTRY Delete,
  57. IN PRTLP_RANGE_LIST_ENTRY Merged
  58. );
  59. PRTLP_RANGE_LIST_ENTRY
  60. RtlpCopyRangeListEntry(
  61. PRTLP_RANGE_LIST_ENTRY Entry
  62. );
  63. VOID
  64. RtlpDeleteRangeListEntry(
  65. IN PRTLP_RANGE_LIST_ENTRY Entry
  66. );
  67. BOOLEAN
  68. RtlpIsRangeAvailable(
  69. IN PRTL_RANGE_LIST_ITERATOR Iterator,
  70. IN ULONGLONG Start,
  71. IN ULONGLONG End,
  72. IN UCHAR AttributeAvailableMask,
  73. IN BOOLEAN SharedOK,
  74. IN BOOLEAN NullConflictOK,
  75. IN BOOLEAN Forward,
  76. IN PVOID Context OPTIONAL,
  77. IN PRTL_CONFLICT_RANGE_CALLBACK Callback OPTIONAL
  78. );
  79. #if DBG
  80. VOID
  81. RtlpDumpRangeListEntry(
  82. LONG Level,
  83. PRTLP_RANGE_LIST_ENTRY Entry,
  84. BOOLEAN Indent
  85. );
  86. VOID
  87. RtlpDumpRangeList(
  88. LONG Level,
  89. PRTL_RANGE_LIST RangeList
  90. );
  91. #else
  92. #define RtlpDumpRangeListEntry(Level, Entry, Indent)
  93. #define RtlpDumpRangeList(Level, RangeList)
  94. #endif // DBG
  95. //
  96. // Make everything pageable or init
  97. //
  98. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  99. #pragma alloc_text(INIT, RtlInitializeRangeListPackage)
  100. #pragma alloc_text(PAGE, RtlpAddRange)
  101. #pragma alloc_text(PAGE, RtlpAddToMergedRange)
  102. #pragma alloc_text(PAGE, RtlpConvertToMergedRange)
  103. #pragma alloc_text(PAGE, RtlpCreateRangeListEntry)
  104. #pragma alloc_text(PAGE, RtlpAddIntersectingRanges)
  105. #pragma alloc_text(PAGE, RtlpDeleteFromMergedRange)
  106. #pragma alloc_text(PAGE, RtlpCopyRangeListEntry)
  107. #pragma alloc_text(PAGE, RtlpDeleteRangeListEntry)
  108. #pragma alloc_text(PAGE, RtlpIsRangeAvailable)
  109. #if DBG
  110. #pragma alloc_text(PAGE, RtlpDumpRangeListEntry)
  111. #pragma alloc_text(PAGE, RtlpDumpRangeList)
  112. #endif
  113. #pragma alloc_text(PAGE, RtlInitializeRangeList)
  114. #pragma alloc_text(PAGE, RtlAddRange)
  115. #pragma alloc_text(PAGE, RtlDeleteRange)
  116. #pragma alloc_text(PAGE, RtlDeleteOwnersRanges)
  117. #pragma alloc_text(PAGE, RtlCopyRangeList)
  118. #pragma alloc_text(PAGE, RtlFreeRangeList)
  119. #pragma alloc_text(PAGE, RtlIsRangeAvailable)
  120. #pragma alloc_text(PAGE, RtlFindRange)
  121. #pragma alloc_text(PAGE, RtlGetFirstRange)
  122. #pragma alloc_text(PAGE, RtlGetLastRange)
  123. #pragma alloc_text(PAGE, RtlGetNextRange)
  124. #pragma alloc_text(PAGE, RtlMergeRangeLists)
  125. #pragma alloc_text(PAGE, RtlInvertRangeList)
  126. #endif // ALLOC_PRAGMA
  127. //
  128. // Range List memory allocation
  129. //
  130. #if defined(NTOS_KERNEL_RUNTIME)
  131. //
  132. // The kernel mode range list API uses a lookaside list to speed allocation
  133. // of range list entries. The PAGED_LOOKASIDE_LIST structure should be non-paged.
  134. //
  135. #define RTLP_RANGE_LIST_ENTRY_LOOKASIDE_DEPTH 16
  136. PAGED_LOOKASIDE_LIST RtlpRangeListEntryLookasideList;
  137. VOID
  138. RtlInitializeRangeListPackage(
  139. VOID
  140. )
  141. /*++
  142. Routine Description:
  143. This routine initializes the stuctures required by the range list
  144. APIs. It is called during system initialization (Phase1Initialization)
  145. and should be before any of the range list apis are called.
  146. Arguments:
  147. None.
  148. Return Value:
  149. None.
  150. --*/
  151. {
  152. ExInitializePagedLookasideList(
  153. &RtlpRangeListEntryLookasideList,
  154. NULL,
  155. NULL,
  156. POOL_COLD_ALLOCATION,
  157. sizeof(RTLP_RANGE_LIST_ENTRY),
  158. RTL_RANGE_LIST_ENTRY_TAG,
  159. RTLP_RANGE_LIST_ENTRY_LOOKASIDE_DEPTH
  160. );
  161. }
  162. //
  163. // PRANGE_LIST_ENTRY
  164. // RtlpAllocateRangeListEntry(
  165. // VOID
  166. // )
  167. //
  168. #define RtlpAllocateRangeListEntry() \
  169. (PRTLP_RANGE_LIST_ENTRY) ExAllocateFromPagedLookasideList( \
  170. &RtlpRangeListEntryLookasideList \
  171. )
  172. //
  173. // VOID
  174. // RtlpFreeRangeListEntry(
  175. // IN PRTLP_RANGE_LIST_ENTRY Entry
  176. // )
  177. //
  178. #define RtlpFreeRangeListEntry(Entry) \
  179. ExFreeToPagedLookasideList(&RtlpRangeListEntryLookasideList, (Entry))
  180. //
  181. // PVOID
  182. // RtlpRangeListAllocatePool(
  183. // IN ULONG Size
  184. // )
  185. //
  186. #define RtlpRangeListAllocatePool(Size) \
  187. ExAllocatePoolWithTag(PagedPool, (Size), RTL_RANGE_LIST_MISC_TAG)
  188. //
  189. // VOID
  190. // RtlpRangeListFreePool(
  191. // IN PVOID Free
  192. // )
  193. //
  194. #define RtlpRangeListFreePool(Free) \
  195. ExFreePool(Free)
  196. #else // defined(NTOS_KERNEL_RUNTIME)
  197. //
  198. // Usermode range lists use the standard Rtl heap for allocations
  199. //
  200. //
  201. // PRANGE_LIST_ENTRY
  202. // RtlpAllocateRangeListEntry(
  203. // VOID
  204. // );
  205. //
  206. #define RtlpAllocateRangeListEntry() \
  207. (PRTLP_RANGE_LIST_ENTRY) RtlAllocateHeap( \
  208. RtlProcessHeap(), \
  209. RTL_RANGE_LIST_ENTRY_TAG, \
  210. sizeof(RTLP_RANGE_LIST_ENTRY) \
  211. )
  212. //
  213. // VOID
  214. // RtlpFreeRangeListEntry(
  215. // IN PRTLP_RANGE_LIST_ENTRY Entry
  216. // )
  217. //
  218. #define RtlpFreeRangeListEntry(Entry) \
  219. RtlFreeHeap( RtlProcessHeap(), 0, (Entry) )
  220. //
  221. // PVOID
  222. // RtlpRangeListAllocatePool(
  223. // IN ULONG Size
  224. // )
  225. //
  226. #define RtlpRangeListAllocatePool(Size) \
  227. RtlAllocateHeap(RtlProcessHeap(), RTL_RANGE_LIST_MISC_TAG, (Size))
  228. //
  229. // VOID
  230. // RtlpRangeListFreePool(
  231. // IN PVOID Free
  232. // )
  233. //
  234. #define RtlpRangeListFreePool(Free) \
  235. RtlFreeHeap( RtlProcessHeap(), 0, (Free) )
  236. #endif // defined(NTOS_KERNEL_RUNTIME)
  237. VOID
  238. RtlInitializeRangeList(
  239. IN OUT PRTL_RANGE_LIST RangeList
  240. )
  241. /*++
  242. Routine Description:
  243. This routine initializes a range list. It must be called before the range
  244. list is passed to any of the other range list functions. Initially the
  245. range list contains no ranges
  246. Arguments:
  247. RangeList - Pointer to a user allocated RTL_RANGE_LIST structre to be
  248. initialized.
  249. Return Value:
  250. None.
  251. --*/
  252. {
  253. RTL_PAGED_CODE();
  254. ASSERT(RangeList);
  255. DEBUG_PRINT(1, ("RtlInitializeRangeList(0x%08x)\n", RangeList));
  256. InitializeListHead(&RangeList->ListHead);
  257. RangeList->Flags = 0;
  258. RangeList->Count = 0;
  259. RangeList->Stamp = 0;
  260. }
  261. NTSTATUS
  262. RtlAddRange(
  263. IN OUT PRTL_RANGE_LIST RangeList,
  264. IN ULONGLONG Start,
  265. IN ULONGLONG End,
  266. IN UCHAR Attributes,
  267. IN ULONG Flags,
  268. IN PVOID UserData, OPTIONAL
  269. IN PVOID Owner OPTIONAL
  270. )
  271. /*++
  272. Routine Description:
  273. This routine adds a new range with the specified properties to a range list.
  274. Arguments:
  275. RangeList - Pointer to the range list to which the new range is to be added.
  276. It must have been previously initialized using RtlInitializeRangeList.
  277. Start - The location of the start of the new range.
  278. End - The location of the end of the new range.
  279. Flags - These determine the range's properties and how it is added:
  280. RTL_RANGE_LIST_ADD_IF_CONFLICT - The range should be added even if it
  281. overlaps another range. In this case the RTL_RANGE_CONFLICT flag
  282. is set.
  283. RTL_RANGE_LIST_ADD_SHARED - The range is marked as an RTL_RANGE_SHARED
  284. and will successfully be added if it overlaps another shared range.
  285. It can be speficied in conjunction with the above ADD_IF_CONFLICT
  286. flag in which case if the range overlaps a non-shared range it will
  287. be marked as both RTL_RANGE_SHARED and RTL_RANGE_CONFLICT.
  288. UserData - Extra data to be stored with the range. The system will not
  289. attempt to interpret it.
  290. Owner - A cookie that represents the entity that owns this range. (A
  291. pointer to some object is the most likley). The system will not
  292. attempt to interpret it, just use it to distinguish the range from
  293. another with the same start and end.
  294. Return Value:
  295. Status code that indicates whether or not the function was successful:
  296. STATUS_INVALID_PARAMETER
  297. STATUS_RANGE_LIST_CONFLICT
  298. STATUS_INSUFFICIENT_RESOURCES
  299. --*/
  300. {
  301. NTSTATUS status;
  302. PRTLP_RANGE_LIST_ENTRY newEntry = NULL;
  303. RTL_PAGED_CODE();
  304. DEBUG_PRINT(1,
  305. ("RtlAddRange(0x%08x, 0x%I64x, 0x%I64x, 0x%08x, 0x%08x, 0x%08x)\n",
  306. RangeList,
  307. Start,
  308. End,
  309. Flags,
  310. UserData,
  311. Owner
  312. ));
  313. //
  314. // Validate parameters
  315. //
  316. if (End < Start) {
  317. return STATUS_INVALID_PARAMETER;
  318. }
  319. //
  320. // Create a new entry
  321. //
  322. if (!(newEntry = RtlpCreateRangeListEntry(Start, End, Attributes, UserData, Owner))) {
  323. return STATUS_INSUFFICIENT_RESOURCES;
  324. }
  325. //
  326. // Mark the new entry as shared if appropriate
  327. //
  328. if (Flags & RTL_RANGE_LIST_ADD_SHARED) {
  329. newEntry->PublicFlags |= RTL_RANGE_SHARED;
  330. }
  331. status = RtlpAddRange(&RangeList->ListHead,
  332. newEntry,
  333. Flags
  334. );
  335. if (NT_SUCCESS(status)) {
  336. //
  337. // We added a range so bump the count
  338. //
  339. RangeList->Count++;
  340. RangeList->Stamp++;
  341. } else {
  342. //
  343. // We didn't add a range so free up the entry
  344. //
  345. RtlpFreeRangeListEntry(newEntry);
  346. }
  347. return status;
  348. }
  349. NTSTATUS
  350. RtlpAddRange(
  351. IN OUT PLIST_ENTRY ListHead,
  352. IN PRTLP_RANGE_LIST_ENTRY Entry,
  353. IN ULONG AddRangeFlags
  354. )
  355. /*++
  356. Routine Description:
  357. This routine implement the AddRange operation adding the range in the
  358. appropriate place in the sorted range list, converting ranges to merged
  359. ranges and setting RTL_RANGE_CONFLICT flags as necessary.
  360. Arguments:
  361. ListHead - The list of the range list to which the range should be added.
  362. Entry - The new entry to be added to the range list
  363. AddRangeFlags - The Flags argument to RtlAddRange, see above.
  364. Return Value:
  365. Status code that indicates whether or not the function was successful:
  366. STATUS_RANGE_LIST_CONFLICT
  367. STATUS_INSUFFICIENT_RESOURCES
  368. --*/
  369. {
  370. NTSTATUS status = STATUS_SUCCESS;
  371. PRTLP_RANGE_LIST_ENTRY previous, current;
  372. ULONGLONG start, end;
  373. DEBUG_PRINT(2,
  374. ("RtlpAddRange(0x%08x, 0x%08x{0x%I64x-0x%I64x}, 0x%08x)\n",
  375. ListHead,
  376. Entry,
  377. Entry->Start,
  378. Entry->End,
  379. AddRangeFlags
  380. ));
  381. RTL_PAGED_CODE();
  382. ASSERT(Entry);
  383. start = Entry->Start;
  384. end = Entry->End;
  385. //
  386. // Clear the conflict flag if it was left around
  387. //
  388. Entry->PublicFlags &= ~RTL_RANGE_CONFLICT;
  389. //
  390. // Iterate through the list and find where to insert the entry
  391. //
  392. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY, ListHead, current) {
  393. if (end < current->Start) {
  394. //
  395. // The new range is completely before this one
  396. //
  397. DEBUG_PRINT(2, ("Completely before\n"));
  398. InsertEntryList(current->ListEntry.Blink,
  399. &Entry->ListEntry
  400. );
  401. goto exit;
  402. } else if (RANGE_INTERSECT(Entry, current)) {
  403. status = RtlpAddIntersectingRanges(ListHead,
  404. current,
  405. Entry,
  406. AddRangeFlags);
  407. goto exit;
  408. }
  409. }
  410. //
  411. // New range is after all existing ranges
  412. //
  413. DEBUG_PRINT(2, ("After all existing ranges\n"));
  414. InsertTailList(ListHead,
  415. &Entry->ListEntry
  416. );
  417. exit:
  418. return status;
  419. }
  420. NTSTATUS
  421. RtlpAddToMergedRange(
  422. IN PRTLP_RANGE_LIST_ENTRY Merged,
  423. IN PRTLP_RANGE_LIST_ENTRY Entry,
  424. IN ULONG AddRangeFlags
  425. )
  426. /*++
  427. Routine Description:
  428. This routine adds a new range to a merged range, setting the
  429. RTL_RANGE_CONFLICT flags if necessary.
  430. Arguments:
  431. Merged - The merged range to which Entry should be added.
  432. Entry - The new entry to be added to the range list
  433. AddRangeFlags - The Flags argument to RtlAddRange, see above.
  434. Return Value:
  435. Status code that indicates whether or not the function was successful:
  436. STATUS_RANGE_LIST_CONFLICT - indictates that the range was not added because
  437. it conflicted with another range and conflicts are not allowed
  438. --*/
  439. {
  440. PRTLP_RANGE_LIST_ENTRY current;
  441. PLIST_ENTRY insert = NULL;
  442. BOOLEAN entryShared;
  443. RTL_PAGED_CODE();
  444. ASSERT(Merged);
  445. ASSERT(Entry);
  446. ASSERT(MERGED(Merged));
  447. entryShared = SHARED(Entry);
  448. //
  449. // Insert it into the merged list, this is sorted in order of start
  450. //
  451. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY, &Merged->Merged.ListHead, current) {
  452. //
  453. // Do we conflict?
  454. //
  455. if (RANGE_INTERSECT(current, Entry)
  456. && !(entryShared && SHARED(current))) {
  457. //
  458. // Are conflicts ok?
  459. //
  460. if (AddRangeFlags & RTL_RANGE_LIST_ADD_IF_CONFLICT) {
  461. //
  462. // Yes - Mark both entries as conflicting
  463. //
  464. current->PublicFlags |= RTL_RANGE_CONFLICT;
  465. Entry->PublicFlags |= RTL_RANGE_CONFLICT;
  466. } else {
  467. //
  468. // No - Fail
  469. //
  470. return STATUS_RANGE_LIST_CONFLICT;
  471. }
  472. }
  473. //
  474. // Have we not yet found the insertion point and just passed it?
  475. //
  476. if (!insert && current->Start > Entry->Start) {
  477. //
  478. // Insert is before current
  479. //
  480. insert = current->ListEntry.Blink;
  481. }
  482. }
  483. //
  484. // Did we find where to insert the new range?
  485. //
  486. if (!insert) {
  487. //
  488. // New range is after all existing ranges
  489. //
  490. InsertTailList(&Merged->Merged.ListHead,
  491. &Entry->ListEntry
  492. );
  493. } else {
  494. //
  495. // Insert in the list
  496. //
  497. InsertEntryList(insert,
  498. &Entry->ListEntry
  499. );
  500. }
  501. //
  502. // Expand the merged range if necessary
  503. //
  504. if (Entry->Start < Merged->Start) {
  505. Merged->Start = Entry->Start;
  506. }
  507. if (Entry->End > Merged->End) {
  508. Merged->End = Entry->End;
  509. }
  510. //
  511. // If we just added a shared range to a completely shared merged
  512. // range then the shared flag can stay otherwise it must go
  513. //
  514. if (SHARED(Merged) && !entryShared) {
  515. DEBUG_PRINT(2,
  516. ("RtlpAddToMergedRange: Merged range no longer completely shared\n"));
  517. Merged->PublicFlags &= ~RTL_RANGE_SHARED;
  518. }
  519. return STATUS_SUCCESS;
  520. }
  521. NTSTATUS
  522. RtlpConvertToMergedRange(
  523. IN PRTLP_RANGE_LIST_ENTRY Entry
  524. )
  525. /*++
  526. Routine Description:
  527. This converts a non-merged range into a merged range with one member, the
  528. range that was just converted.
  529. Arguments:
  530. Entry - The entry to be converted into a merged range.
  531. Return Value:
  532. Status code that indicates whether or not the function was successful:
  533. STATUS_INSUFFICIENT_RESOURCES
  534. --*/
  535. {
  536. PRTLP_RANGE_LIST_ENTRY newEntry;
  537. RTL_PAGED_CODE();
  538. ASSERT(Entry);
  539. ASSERT(!MERGED(Entry));
  540. ASSERT(!CONFLICT(Entry));
  541. //
  542. // Create a new entry
  543. //
  544. if (!(newEntry = RtlpCopyRangeListEntry(Entry))) {
  545. return STATUS_INSUFFICIENT_RESOURCES;
  546. }
  547. //
  548. // Convert the current entry into a merged one NB. Throw away all the
  549. // private flags but leave the public ones as they can only be shared.
  550. //
  551. InitializeListHead(&Entry->Merged.ListHead);
  552. Entry->PrivateFlags = RTLP_RANGE_LIST_ENTRY_MERGED;
  553. ASSERT(Entry->PublicFlags == RTL_RANGE_SHARED || Entry->PublicFlags == 0);
  554. //
  555. // Add the range
  556. //
  557. InsertHeadList(&Entry->Merged.ListHead,
  558. &newEntry->ListEntry
  559. );
  560. return STATUS_SUCCESS;
  561. }
  562. PRTLP_RANGE_LIST_ENTRY
  563. RtlpCreateRangeListEntry(
  564. IN ULONGLONG Start,
  565. IN ULONGLONG End,
  566. IN UCHAR Attributes,
  567. IN PVOID UserData,
  568. IN PVOID Owner
  569. )
  570. /*++
  571. Routine Description:
  572. This routine allocates a new range list entry and fills it in the the data
  573. provided.
  574. Arguments:
  575. Start - The location of the start of the new range.
  576. End - The location of the end of the new range.
  577. Attributes - Extra data (normally flags) to be stored with the range. The
  578. system will not attempt to interpret it.
  579. UserData - Extra data to be stored with the range. The system will not
  580. attempt to interpret it.
  581. Owner - A cookie that represents the entity that owns this range. (A
  582. pointer to some object is the most likley). The system will not
  583. attempt to interpret it, just use it to distinguish the range from
  584. another with the same start and end.
  585. Return Value:
  586. Pointer to the new range list entry or NULL if a new entry could not be
  587. allocated.
  588. --*/
  589. {
  590. PRTLP_RANGE_LIST_ENTRY entry;
  591. RTL_PAGED_CODE();
  592. ASSERT(Start <= End);
  593. //
  594. // Allocate a new entry
  595. //
  596. if (entry = RtlpAllocateRangeListEntry()) {
  597. //
  598. // Fill in the details
  599. //
  600. #if DBG
  601. entry->ListEntry.Flink = NULL;
  602. entry->ListEntry.Blink = NULL;
  603. #endif
  604. entry->PublicFlags = 0;
  605. entry->PrivateFlags = 0;
  606. entry->Start = Start;
  607. entry->End = End;
  608. entry->Allocated.UserData = UserData;
  609. entry->Allocated.Owner = Owner;
  610. entry->Attributes = Attributes;
  611. }
  612. return entry;
  613. }
  614. NTSTATUS
  615. RtlpAddIntersectingRanges(
  616. IN PLIST_ENTRY ListHead,
  617. IN PRTLP_RANGE_LIST_ENTRY First,
  618. IN PRTLP_RANGE_LIST_ENTRY Entry,
  619. IN ULONG AddRangeFlags
  620. )
  621. /*++
  622. Routine Description:
  623. This routine adds a range to a range list when the new range overlaps
  624. an existing range. Ranges are converted to mergedranges and the
  625. RTL_RANGE_CONFLICT flag is set as necessary.
  626. Arguments:
  627. ListHead - The list of the range list to which the range should be added.
  628. First - The first range that intersects
  629. Entry - The new range to be added
  630. AddRangeFlags - The Flags argument to RtlAddRange, see above.
  631. Return Value:
  632. Status code that indicates whether or not the function was successful:
  633. STATUS_INSUFFICIENT_RESOURCES
  634. STATUS_RANGE_LIST_CONFLICT
  635. --*/
  636. {
  637. NTSTATUS status;
  638. PRTLP_RANGE_LIST_ENTRY current, next, currentMerged, nextMerged;
  639. BOOLEAN entryShared;
  640. RTL_PAGED_CODE();
  641. ASSERT(First);
  642. ASSERT(Entry);
  643. entryShared = SHARED(Entry);
  644. //
  645. // If we care about conflicts see if we conflict with anyone
  646. //
  647. if (!(AddRangeFlags & RTL_RANGE_LIST_ADD_IF_CONFLICT)) {
  648. //
  649. // Examine all ranges after the first intersecting one
  650. //
  651. current = First;
  652. FOR_REST_IN_LIST(RTLP_RANGE_LIST_ENTRY, ListHead, current) {
  653. if (Entry->End < current->Start) {
  654. //
  655. // We don't intersect anymore so there arn't any more
  656. // conflicts
  657. //
  658. break;
  659. } else if (MERGED(current)) {
  660. //
  661. // Check if any of the merged ranges conflict
  662. //
  663. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY,
  664. &current->Merged.ListHead,
  665. currentMerged) {
  666. //
  667. // Do we conflict?
  668. //
  669. if (RANGE_INTERSECT(currentMerged, Entry)
  670. && !(entryShared && SHARED(currentMerged))) {
  671. //
  672. // We conflict with one of the merged ranges
  673. //
  674. return STATUS_RANGE_LIST_CONFLICT;
  675. }
  676. }
  677. } else if (!(entryShared && SHARED(current))) {
  678. //
  679. // We conflict with a non shared region in the main list.
  680. //
  681. return STATUS_RANGE_LIST_CONFLICT;
  682. }
  683. }
  684. }
  685. //
  686. // Ok - either we didn't find any conflicts or we don't care about
  687. // them. Now its safe to perform the merge. Make the first
  688. // overlapping range into a header if it is not already one and then
  689. // add the rest of the ranges
  690. //
  691. if (!MERGED(First)) {
  692. status = RtlpConvertToMergedRange(First);
  693. if (!NT_SUCCESS(status)) {
  694. goto cleanup;
  695. }
  696. }
  697. ASSERT(MERGED(First));
  698. current = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(First->ListEntry.Flink);
  699. //
  700. // Consider the entries between the one following first and the last
  701. // intersecting one.
  702. //
  703. FOR_REST_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY, ListHead, current, next) {
  704. if (Entry->End < current->Start) {
  705. //
  706. // We don't intersect any more
  707. //
  708. break;
  709. }
  710. if (MERGED(current)) {
  711. //
  712. // Add all the merged ranges to the new entry
  713. //
  714. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  715. &current->Merged.ListHead,
  716. currentMerged,
  717. nextMerged) {
  718. //
  719. // Remove the entry from the current list
  720. //
  721. RemoveEntryList(&currentMerged->ListEntry);
  722. //
  723. // Add the entry to the new merged range
  724. //
  725. status = RtlpAddToMergedRange(First,
  726. currentMerged,
  727. AddRangeFlags
  728. );
  729. //
  730. // We should not be able to fail the add but just to be
  731. // on the safe side...
  732. //
  733. ASSERT(NT_SUCCESS(status));
  734. }
  735. //
  736. // Remove and free the now empty header
  737. //
  738. ASSERT(IsListEmpty(&current->Merged.ListHead));
  739. RemoveEntryList(&current->ListEntry);
  740. RtlpFreeRangeListEntry(current);
  741. } else {
  742. //
  743. // Remove the entry from the main list
  744. //
  745. RemoveEntryList(&current->ListEntry);
  746. //
  747. // Add the entry to the new merged range
  748. //
  749. status = RtlpAddToMergedRange(First,
  750. current,
  751. AddRangeFlags
  752. );
  753. //
  754. // We should not be able to fail the add but just to be
  755. // on the safe side...
  756. //
  757. ASSERT(NT_SUCCESS(status));
  758. }
  759. }
  760. //
  761. // Finally add the entry that did the overlapping
  762. //
  763. status = RtlpAddToMergedRange(First,
  764. Entry,
  765. AddRangeFlags
  766. );
  767. ASSERT(NT_SUCCESS(status));
  768. cleanup:
  769. return status;
  770. }
  771. NTSTATUS
  772. RtlDeleteRange(
  773. IN OUT PRTL_RANGE_LIST RangeList,
  774. IN ULONGLONG Start,
  775. IN ULONGLONG End,
  776. IN PVOID Owner
  777. )
  778. /*++
  779. Routine Description:
  780. This routine deletes a range from a range list.
  781. Arguments:
  782. Start - The location of the start of the range to be deleted.
  783. End - The location of the end of the range to be deleted.
  784. Owner - The owner of the range to be deleted, used to distinguish the
  785. range from another with the same start and end.
  786. Return Value:
  787. Status code that indicates whether or not the function was successful:
  788. STATUS_INSUFFICIENT_RESOURCES
  789. STATUS_RANGE_LIST_CONFLICT
  790. --*/
  791. {
  792. NTSTATUS status = STATUS_RANGE_NOT_FOUND;
  793. PRTLP_RANGE_LIST_ENTRY current, next, currentMerged, nextMerged;
  794. RTL_PAGED_CODE();
  795. ASSERT(RangeList);
  796. DEBUG_PRINT(1,
  797. ("RtlDeleteRange(0x%08x, 0x%I64x, 0x%I64x, 0x%08x)\n",
  798. RangeList,
  799. Start,
  800. End,
  801. Owner
  802. ));
  803. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  804. &RangeList->ListHead,
  805. current,
  806. next) {
  807. //
  808. // We're passed all possible intersections
  809. //
  810. if (End < current->Start) {
  811. //
  812. // We didn't find a match
  813. //
  814. break;
  815. }
  816. if (MERGED(current)) {
  817. //
  818. // COuld our range exist in this merged range?
  819. //
  820. if (Start >= current->Start && End <= current->End) {
  821. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  822. &current->Merged.ListHead,
  823. currentMerged,
  824. nextMerged) {
  825. if (currentMerged->Start == Start
  826. && currentMerged->End == End
  827. && currentMerged->Allocated.Owner == Owner) {
  828. //
  829. // This is the range - delete it and rebuild the merged
  830. // range appropriately
  831. //
  832. status = RtlpDeleteFromMergedRange(currentMerged,
  833. current
  834. );
  835. goto exit;
  836. }
  837. }
  838. }
  839. } else if (current->Start == Start
  840. && current->End == End
  841. && current->Allocated.Owner == Owner) {
  842. //
  843. // This is the range - delete it!
  844. //
  845. RemoveEntryList(&current->ListEntry);
  846. RtlpFreeRangeListEntry(current);
  847. status = STATUS_SUCCESS;
  848. goto exit;
  849. }
  850. }
  851. exit:
  852. if (NT_SUCCESS(status)) {
  853. //
  854. // We have removed a range so decrement the count in the header
  855. //
  856. RangeList->Count--;
  857. RangeList->Stamp++;
  858. }
  859. return status;
  860. }
  861. NTSTATUS
  862. RtlDeleteOwnersRanges(
  863. IN OUT PRTL_RANGE_LIST RangeList,
  864. IN PVOID Owner
  865. )
  866. /*++
  867. Routine Description:
  868. This routine deletes all the ranges owned by a specific owner from a range
  869. list.
  870. Arguments:
  871. Owner - The owner of the ranges to be deleted.
  872. Return Value:
  873. Status code that indicates whether or not the function was successful:
  874. STATUS_INSUFFICIENT_RESOURCES
  875. --*/
  876. {
  877. NTSTATUS status = STATUS_SUCCESS;
  878. PRTLP_RANGE_LIST_ENTRY current, next, currentMerged, nextMerged;
  879. RTL_PAGED_CODE();
  880. ASSERT(RangeList);
  881. DEBUG_PRINT(1,
  882. ("RtlDeleteOwnersRanges(0x%08x, 0x%08x)\n",
  883. RangeList,
  884. Owner
  885. ));
  886. findNext:
  887. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  888. &RangeList->ListHead,
  889. current,
  890. next) {
  891. if (MERGED(current)) {
  892. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  893. &current->Merged.ListHead,
  894. currentMerged,
  895. nextMerged) {
  896. if (currentMerged->Allocated.Owner == Owner) {
  897. //
  898. // This is the range - delete it and rebuild the merged
  899. // range appropriately
  900. //
  901. DEBUG_PRINT(2,
  902. ("RtlDeleteOwnersRanges: Deleting merged range \
  903. (Start=%I64x, End=%I64x)\n",
  904. currentMerged->Start,
  905. currentMerged->End
  906. ));
  907. status = RtlpDeleteFromMergedRange(currentMerged,
  908. current
  909. );
  910. if (!NT_SUCCESS(status)) {
  911. goto cleanup;
  912. }
  913. RangeList->Count--;
  914. RangeList->Stamp++;
  915. //
  916. // Can't keep scanning the list as it might have changed
  917. // underneath us - start from the beginning again...
  918. // (We could keep a last safe position to go from...)
  919. //
  920. goto findNext;
  921. }
  922. }
  923. } else if (current->Allocated.Owner == Owner) {
  924. //
  925. // This is the range - delete it!
  926. //
  927. RemoveEntryList(&current->ListEntry);
  928. RtlpFreeRangeListEntry(current);
  929. DEBUG_PRINT(2,
  930. ("RtlDeleteOwnersRanges: Deleting range (Start=%I64x,End=%I64x)\n",
  931. current->Start,
  932. current->End
  933. ));
  934. RangeList->Count--;
  935. RangeList->Stamp++;
  936. status = STATUS_SUCCESS;
  937. }
  938. }
  939. cleanup:
  940. return status;
  941. }
  942. NTSTATUS
  943. RtlpDeleteFromMergedRange(
  944. IN PRTLP_RANGE_LIST_ENTRY Delete,
  945. IN PRTLP_RANGE_LIST_ENTRY Merged
  946. )
  947. /*++
  948. Routine Description:
  949. This routine deletes a range from a merged range and rebuilds the merged
  950. range as appropriate. This includes adding new merged and unmerged ranges.
  951. If no ranges are left in the merged range it will be deleted.
  952. Arguments:
  953. Delete - Range list entry to delete
  954. Merged - Merged range that contains it
  955. Return Value:
  956. Status code that indicates whether or not the function was successful:
  957. STATUS_INSUFFICIENT_RESOURCES
  958. --*/
  959. {
  960. NTSTATUS status = STATUS_SUCCESS;
  961. PRTLP_RANGE_LIST_ENTRY current, next;
  962. LIST_ENTRY keepList;
  963. PLIST_ENTRY previousInsert, nextInsert;
  964. RTL_PAGED_CODE();
  965. ASSERT(MERGED(Merged));
  966. //
  967. // Remove the entry
  968. //
  969. RemoveEntryList(&Delete->ListEntry);
  970. //
  971. // Initialize the temporary list where the new list will be build
  972. //
  973. InitializeListHead(&keepList);
  974. //
  975. // Add the previously merged ranges into the keep list and put
  976. // any duplicates of the delete range into the delete list
  977. //
  978. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  979. &Merged->Merged.ListHead,
  980. current,
  981. next) {
  982. //
  983. // Add it to the keepList. Explicitly remove the entries from the
  984. // list so it is still valid if we need to rebuild it.
  985. //
  986. RemoveEntryList(&current->ListEntry);
  987. //
  988. // Clear the conflict flag - if there is still a conflict RtlpAddRange
  989. // should set it again.
  990. //
  991. current->PublicFlags &= ~RTL_RANGE_CONFLICT;
  992. status = RtlpAddRange(&keepList,
  993. current,
  994. RTL_RANGE_LIST_ADD_IF_CONFLICT
  995. );
  996. if (!NT_SUCCESS(status)) {
  997. //
  998. // This should only happen if we run out of pool
  999. //
  1000. goto cleanup;
  1001. }
  1002. }
  1003. if (!IsListEmpty(&keepList)) {
  1004. //
  1005. // Everything went well so splice this temporary list into the
  1006. // main list where Merged used to be
  1007. //
  1008. previousInsert = Merged->ListEntry.Blink;
  1009. nextInsert = Merged->ListEntry.Flink;
  1010. previousInsert->Flink = keepList.Flink;
  1011. keepList.Flink->Blink = previousInsert;
  1012. nextInsert->Blink = keepList.Blink;
  1013. keepList.Blink->Flink = nextInsert;
  1014. } else {
  1015. RemoveEntryList(&Merged->ListEntry);
  1016. }
  1017. //
  1018. // Finally free the range we deleted and the merged range we have orphaned
  1019. //
  1020. RtlpFreeRangeListEntry(Delete);
  1021. RtlpFreeRangeListEntry(Merged);
  1022. return status;
  1023. cleanup:
  1024. //
  1025. // Things went wrong - should only be a STATUS_INSUFFICIENT_RESOURCES
  1026. // Reconstruct the list as it was before the call using the keepList and
  1027. // deleteList.
  1028. //
  1029. ASSERT(status == STATUS_INSUFFICIENT_RESOURCES);
  1030. //
  1031. // Add all the ranges we moved to the keepList back into Merged
  1032. //
  1033. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY, &keepList, current, next) {
  1034. status = RtlpAddToMergedRange(Merged,
  1035. current,
  1036. RTL_RANGE_LIST_ADD_IF_CONFLICT
  1037. );
  1038. ASSERT(NT_SUCCESS(status));
  1039. }
  1040. //
  1041. // And the one were meant to delete
  1042. //
  1043. status = RtlpAddToMergedRange(Merged,
  1044. Delete,
  1045. RTL_RANGE_LIST_ADD_IF_CONFLICT
  1046. );
  1047. return status;
  1048. }
  1049. PRTLP_RANGE_LIST_ENTRY
  1050. RtlpCopyRangeListEntry(
  1051. PRTLP_RANGE_LIST_ENTRY Entry
  1052. )
  1053. /*++
  1054. Routine Description:
  1055. This routine copies a range list entry. If the entry is merged all the
  1056. member ranges are copied too.
  1057. Arguments:
  1058. Entry - the range list entry to be copied.
  1059. Return Value:
  1060. Pointer to the new range list entry or NULL if a new entry could not be
  1061. allocated.
  1062. --*/
  1063. {
  1064. PRTLP_RANGE_LIST_ENTRY newEntry;
  1065. RTL_PAGED_CODE();
  1066. ASSERT(Entry);
  1067. if (newEntry = RtlpAllocateRangeListEntry()) {
  1068. RtlCopyMemory(newEntry, Entry, sizeof(RTLP_RANGE_LIST_ENTRY));
  1069. #if DBG
  1070. newEntry->ListEntry.Flink = NULL;
  1071. newEntry->ListEntry.Blink = NULL;
  1072. #endif
  1073. if (MERGED(Entry)) {
  1074. //
  1075. // Copy the merged list
  1076. //
  1077. PRTLP_RANGE_LIST_ENTRY current, newMerged;
  1078. InitializeListHead(&newEntry->Merged.ListHead);
  1079. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY,
  1080. &Entry->Merged.ListHead,
  1081. current) {
  1082. //
  1083. // Allocate a new entry and copy the contents
  1084. //
  1085. newMerged = RtlpAllocateRangeListEntry();
  1086. if (!newMerged) {
  1087. goto cleanup;
  1088. }
  1089. RtlCopyMemory(newMerged, current, sizeof(RTLP_RANGE_LIST_ENTRY));
  1090. //
  1091. // Insert the new entry
  1092. //
  1093. InsertTailList(&newEntry->Merged.ListHead, &newMerged->ListEntry);
  1094. }
  1095. }
  1096. }
  1097. return newEntry;
  1098. cleanup:
  1099. //
  1100. // Free the partially build copy
  1101. //
  1102. RtlpDeleteRangeListEntry(newEntry);
  1103. return NULL;
  1104. }
  1105. NTSTATUS
  1106. RtlCopyRangeList(
  1107. OUT PRTL_RANGE_LIST CopyRangeList,
  1108. IN PRTL_RANGE_LIST RangeList
  1109. )
  1110. /*++
  1111. Routine Description:
  1112. This routine copies a range list.
  1113. Arguments:
  1114. CopyRangeList - An initialized but empty range list where RangeList should
  1115. be copied to.
  1116. RangeList - The range list that is to be copied.
  1117. Return Value:
  1118. Status code that indicates whether or not the function was successful:
  1119. STATUS_INSUFFICIENT_RESOURCES
  1120. STATUS_INVALID_PARAMETER
  1121. --*/
  1122. {
  1123. NTSTATUS status = STATUS_SUCCESS;
  1124. PRTLP_RANGE_LIST_ENTRY current, newEntry, currentMerged, newMerged;
  1125. RTL_PAGED_CODE();
  1126. ASSERT(RangeList);
  1127. ASSERT(CopyRangeList);
  1128. DEBUG_PRINT(1,
  1129. ("RtlCopyRangeList(0x%08x, 0x%08x)\n",
  1130. CopyRangeList,
  1131. RangeList
  1132. ));
  1133. //
  1134. // Sanity checks...
  1135. //
  1136. if (CopyRangeList->Count != 0) {
  1137. return STATUS_INVALID_PARAMETER;
  1138. }
  1139. //
  1140. // Copy the header information
  1141. //
  1142. CopyRangeList->Flags = RangeList->Flags;
  1143. CopyRangeList->Count = RangeList->Count;
  1144. CopyRangeList->Stamp = RangeList->Stamp;
  1145. //
  1146. // Perform the copy
  1147. //
  1148. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY, &RangeList->ListHead, current) {
  1149. //
  1150. // Copy the current entry
  1151. //
  1152. newEntry = RtlpCopyRangeListEntry(current);
  1153. if (!newEntry) {
  1154. status = STATUS_INSUFFICIENT_RESOURCES;
  1155. goto cleanup;
  1156. }
  1157. //
  1158. // Add it into the list
  1159. //
  1160. InsertTailList(&CopyRangeList->ListHead, &newEntry->ListEntry);
  1161. }
  1162. return status;
  1163. cleanup:
  1164. //
  1165. // Free up the partially complete range list
  1166. //
  1167. RtlFreeRangeList(CopyRangeList);
  1168. return status;
  1169. }
  1170. VOID
  1171. RtlpDeleteRangeListEntry(
  1172. IN PRTLP_RANGE_LIST_ENTRY Entry
  1173. )
  1174. /*++
  1175. Routine Description:
  1176. This routine deletes a range list entry - if the entry is merged then all
  1177. the member ranges will be deleted as well. The entry will not be removed
  1178. from any list before deletion - this should be done before calling this
  1179. routine.
  1180. Arguments:
  1181. Entry - The entry to be deleted.
  1182. Return Value:
  1183. None
  1184. --*/
  1185. {
  1186. RTL_PAGED_CODE();
  1187. if (MERGED(Entry)) {
  1188. PRTLP_RANGE_LIST_ENTRY current, next;
  1189. //
  1190. // Free all member ranges first
  1191. //
  1192. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  1193. &Entry->Merged.ListHead,
  1194. current,
  1195. next) {
  1196. RtlpFreeRangeListEntry(current);
  1197. }
  1198. }
  1199. RtlpFreeRangeListEntry(Entry);
  1200. }
  1201. VOID
  1202. RtlFreeRangeList(
  1203. IN PRTL_RANGE_LIST RangeList
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. This routine deletes all the ranges in a range list.
  1208. Arguments:
  1209. RangeList - the range list to operate on.
  1210. Return Value:
  1211. None
  1212. --*/
  1213. {
  1214. PRTLP_RANGE_LIST_ENTRY current, next;
  1215. //
  1216. // Sanity checks...
  1217. //
  1218. RTL_PAGED_CODE();
  1219. ASSERT(RangeList);
  1220. //
  1221. // Clean up the header information
  1222. //
  1223. RangeList->Flags = 0;
  1224. RangeList->Count = 0;
  1225. FOR_ALL_IN_LIST_SAFE(RTLP_RANGE_LIST_ENTRY,
  1226. &RangeList->ListHead,
  1227. current,
  1228. next) {
  1229. //
  1230. // Delete the current entry
  1231. //
  1232. RemoveEntryList(&current->ListEntry);
  1233. RtlpDeleteRangeListEntry(current);
  1234. }
  1235. }
  1236. NTSTATUS
  1237. RtlIsRangeAvailable(
  1238. IN PRTL_RANGE_LIST RangeList,
  1239. IN ULONGLONG Start,
  1240. IN ULONGLONG End,
  1241. IN ULONG Flags,
  1242. IN UCHAR AttributeAvailableMask,
  1243. IN PVOID Context OPTIONAL,
  1244. IN PRTL_CONFLICT_RANGE_CALLBACK Callback OPTIONAL,
  1245. OUT PBOOLEAN Available
  1246. )
  1247. /*++
  1248. Routine Description:
  1249. This routine determines if a given range is available.
  1250. Arguments:
  1251. RangeList - The range list to test availability on.
  1252. Start - The start of the range to test for availability.
  1253. End - The end of the range to test for availability.
  1254. Flags - Modify the behaviour of the routine.
  1255. RTL_RANGE_LIST_SHARED_OK - indicates that shared ranges should be
  1256. considered to be available.
  1257. AttributeAvailableMask - Any range encountered with any of these bits set will be
  1258. consideredto be available.
  1259. Available - Pointer to a boolean which will be set to TRUE if the range
  1260. is available, otherwise FALSE;
  1261. Return Value:
  1262. Status code that indicates whether or not the function was successful:
  1263. --*/
  1264. {
  1265. NTSTATUS status;
  1266. RTL_RANGE_LIST_ITERATOR iterator;
  1267. PRTL_RANGE dummy;
  1268. RTL_PAGED_CODE();
  1269. ASSERT(RangeList);
  1270. ASSERT(Available);
  1271. DEBUG_PRINT(1,
  1272. ("RtlIsRangeAvailable(0x%08x, 0x%I64x, 0x%I64x, 0x%08x, 0x%08x)\n",
  1273. RangeList,
  1274. Start,
  1275. End,
  1276. Flags,
  1277. Available
  1278. ));
  1279. //
  1280. // Initialize iterator to the start of the list
  1281. //
  1282. status = RtlGetFirstRange(RangeList, &iterator, &dummy);
  1283. if (status == STATUS_NO_MORE_ENTRIES) {
  1284. //
  1285. // The range list is empty therefore the range is available
  1286. //
  1287. *Available = TRUE;
  1288. return STATUS_SUCCESS;
  1289. } else if (!NT_SUCCESS(status)) {
  1290. return status;
  1291. }
  1292. *Available = RtlpIsRangeAvailable(&iterator,
  1293. Start,
  1294. End,
  1295. AttributeAvailableMask,
  1296. (BOOLEAN)(Flags & RTL_RANGE_LIST_SHARED_OK),
  1297. (BOOLEAN)(Flags & RTL_RANGE_LIST_NULL_CONFLICT_OK),
  1298. TRUE,
  1299. Context,
  1300. Callback
  1301. );
  1302. return STATUS_SUCCESS;
  1303. }
  1304. BOOLEAN
  1305. RtlpIsRangeAvailable(
  1306. IN PRTL_RANGE_LIST_ITERATOR Iterator,
  1307. IN ULONGLONG Start,
  1308. IN ULONGLONG End,
  1309. IN UCHAR AttributeAvailableMask,
  1310. IN BOOLEAN SharedOK,
  1311. IN BOOLEAN NullConflictOK,
  1312. IN BOOLEAN Forward,
  1313. IN PVOID Context OPTIONAL,
  1314. IN PRTL_CONFLICT_RANGE_CALLBACK Callback OPTIONAL
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. This routine determines if a given range is available.
  1319. Arguments:
  1320. Iterator - An iterator set to the first range to test in the range list.
  1321. Start - The start of the range to test for availability.
  1322. End - The end of the range to test for availability.
  1323. AttributeAvailableMask - Any range encountered with any of these bits set will be
  1324. considered to be available.
  1325. SharedOK - Indicated whether or not shared ranges are considered to be
  1326. available.
  1327. Return Value:
  1328. TRUE if the range is available, FALSE otherwise.
  1329. --*/
  1330. {
  1331. PRTL_RANGE current;
  1332. RTL_PAGED_CODE();
  1333. ASSERT(Iterator);
  1334. FOR_REST_OF_RANGES(Iterator, current, Forward) {
  1335. //
  1336. // If we have passed all possible intersections then break out. This
  1337. // can't be done in a merged region because of possible overlaps.
  1338. //
  1339. if (Forward) {
  1340. if (!Iterator->MergedHead && End < current->Start) {
  1341. break;
  1342. }
  1343. } else {
  1344. if (!Iterator->MergedHead && Start > current->End) {
  1345. break;
  1346. }
  1347. }
  1348. //
  1349. // Do we intersect?
  1350. //
  1351. if (RANGE_LIMITS_INTERSECT(Start, End, current->Start, current->End)) {
  1352. DEBUG_PRINT(2,
  1353. ("Intersection 0x%I64x-0x%I64x and 0x%I64x-0x%I64x\n",
  1354. Start,
  1355. End,
  1356. current->Start,
  1357. current->End
  1358. ));
  1359. //
  1360. // Is the intersection not Ok because it is with a non-shared
  1361. // region or we don't want a shared region? Or the user said that
  1362. // it should be considered available because of the user flags set.
  1363. //
  1364. if (!((SharedOK && (current->Flags & RTL_RANGE_SHARED))
  1365. || (current->Attributes & AttributeAvailableMask)
  1366. || (NullConflictOK && (current->Owner == NULL))
  1367. )
  1368. ) {
  1369. //
  1370. // If the caller provided a callback to support extra conflict
  1371. // semantics call it
  1372. //
  1373. if (ARGUMENT_PRESENT(Callback)) {
  1374. if ((*Callback)(Context, (PRTL_RANGE)current)) {
  1375. DEBUG_PRINT(2,
  1376. ("User provided callback overrode conflict\n",
  1377. Start,
  1378. End,
  1379. current->Start,
  1380. current->End
  1381. ));
  1382. continue;
  1383. }
  1384. }
  1385. return FALSE;
  1386. }
  1387. }
  1388. }
  1389. return TRUE;
  1390. }
  1391. NTSTATUS
  1392. RtlFindRange(
  1393. IN PRTL_RANGE_LIST RangeList,
  1394. IN ULONGLONG Minimum,
  1395. IN ULONGLONG Maximum,
  1396. IN ULONG Length,
  1397. IN ULONG Alignment,
  1398. IN ULONG Flags,
  1399. IN UCHAR AttributeAvailableMask,
  1400. IN PVOID Context OPTIONAL,
  1401. IN PRTL_CONFLICT_RANGE_CALLBACK Callback OPTIONAL,
  1402. OUT PULONGLONG Start
  1403. )
  1404. /*++
  1405. Routine Description:
  1406. This routine finds the first available range that meets the criterion specified.
  1407. Arguments:
  1408. RangeList - The range list to find a range in.
  1409. Minimum - The minimum acceptable value of the start of the range.
  1410. Maximum - The maximum acceptable value of the end of the range.
  1411. Length - The length of the range required.
  1412. Alignmnent - The alignment of the start of the range.
  1413. Flags - Modify the behaviour of the routine.
  1414. RTL_RANGE_LIST_SHARED_OK - indicates that shared ranges should be
  1415. considered to be available.
  1416. AttributeAvailableMask - Any range encountered with any of these bits set will be
  1417. considered to be available.
  1418. Start - Pointer to a ULONGLONG where the start value will be returned on
  1419. success.
  1420. Return Value:
  1421. Status code that indicates whether or not the function was successful:
  1422. STATUS_UNSUCCESSFUL
  1423. STATUS_INVALID_PARAMETER
  1424. --*/
  1425. {
  1426. ULONGLONG start, end;
  1427. RTL_RANGE_LIST_ITERATOR iterator;
  1428. PRTL_RANGE dummy;
  1429. BOOLEAN sharedOK, nullConflictOK;
  1430. RTL_PAGED_CODE();
  1431. ASSERT(RangeList);
  1432. ASSERT(Start);
  1433. ASSERT(Alignment > 0);
  1434. ASSERT(Length > 0);
  1435. DEBUG_PRINT(1,
  1436. ("RtlFindRange(0x%08x, 0x%I64x, 0x%I64x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
  1437. RangeList,
  1438. Minimum,
  1439. Maximum,
  1440. Length,
  1441. Alignment,
  1442. Flags,
  1443. Start
  1444. ));
  1445. //
  1446. // Search from high to low, Align start if necessary
  1447. //
  1448. start = Maximum - (Length - 1);
  1449. start -= start % Alignment;
  1450. //
  1451. // Valiate parameters
  1452. //
  1453. if ((Minimum > Maximum)
  1454. || (Maximum - Minimum < Length - 1)
  1455. || (Minimum + Alignment < Minimum)
  1456. || (start < Minimum)
  1457. || (Length == 0)
  1458. || (Alignment == 0)) {
  1459. return STATUS_INVALID_PARAMETER;
  1460. }
  1461. sharedOK = (BOOLEAN) Flags & RTL_RANGE_LIST_SHARED_OK;
  1462. nullConflictOK = (BOOLEAN) Flags & RTL_RANGE_LIST_NULL_CONFLICT_OK;
  1463. //
  1464. // Calculate the end
  1465. //
  1466. end = start + Length - 1;
  1467. //
  1468. // Initialze the iterator to the end of the list
  1469. //
  1470. RtlGetLastRange(RangeList, &iterator, &dummy);
  1471. //
  1472. // Keep trying to find ranges until we run out of room or we
  1473. // wrap around
  1474. //
  1475. do {
  1476. DEBUG_PRINT(2,
  1477. ("RtlFindRange: Testing range %I64x-%I64x\n",
  1478. start,
  1479. end
  1480. ));
  1481. if (RtlpIsRangeAvailable(&iterator,
  1482. start,
  1483. end,
  1484. AttributeAvailableMask,
  1485. sharedOK,
  1486. nullConflictOK,
  1487. FALSE,
  1488. Context,
  1489. Callback)) {
  1490. *Start = start;
  1491. //
  1492. // Assert our result, if we produced one, is in the in
  1493. // the range specified
  1494. //
  1495. ASSERT(*Start >= Minimum && *Start + Length - 1 <= Maximum);
  1496. return STATUS_SUCCESS;
  1497. }
  1498. //
  1499. // Find a suitable range starting from the one we conflicted with,
  1500. // that is the current range in the iterator - this breaks the
  1501. // abstraction of the iterator in the name of efficiency.
  1502. //
  1503. start = ((PRTLP_RANGE_LIST_ENTRY)(iterator.Current))->Start;
  1504. if ((start - Length) > start) {
  1505. //
  1506. // Wrapped, fail.
  1507. //
  1508. break;
  1509. }
  1510. start -= Length;
  1511. start -= start % Alignment;
  1512. end = start + Length - 1;
  1513. } while ( start >= Minimum );
  1514. return STATUS_UNSUCCESSFUL;
  1515. }
  1516. NTSTATUS
  1517. RtlGetFirstRange(
  1518. IN PRTL_RANGE_LIST RangeList,
  1519. OUT PRTL_RANGE_LIST_ITERATOR Iterator,
  1520. OUT PRTL_RANGE *Range
  1521. )
  1522. /*++
  1523. Routine Description:
  1524. This routine extracts the first range in a range list. If there are no
  1525. ranges then STATUS_NO_MORE_ENTRIES is returned.
  1526. Arguments:
  1527. RangeList - The range list to operate on.
  1528. Iterator - On success this contains the state of the iteration and can be
  1529. passed to RtlGetNextRange.
  1530. Range - On success this contains a pointer to the first range
  1531. Return Value:
  1532. Status code that indicates whether or not the function was successful:
  1533. STATUS_NO_MORE_ENTRIES
  1534. --*/
  1535. {
  1536. NTSTATUS status = STATUS_SUCCESS;
  1537. PRTLP_RANGE_LIST_ENTRY first;
  1538. RTL_PAGED_CODE();
  1539. //
  1540. // Fill in the first part of the iterator
  1541. //
  1542. Iterator->RangeListHead = &RangeList->ListHead;
  1543. Iterator->Stamp = RangeList->Stamp;
  1544. if (!IsListEmpty(&RangeList->ListHead)) {
  1545. first = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(RangeList->ListHead.Flink);
  1546. //
  1547. // Fill in the iterator and update to point to the first merged
  1548. // range if we are merged
  1549. //
  1550. if (MERGED(first)) {
  1551. ASSERT(!IsListEmpty(&first->Merged.ListHead));
  1552. Iterator->MergedHead = &first->Merged.ListHead;
  1553. Iterator->Current = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1554. first->Merged.ListHead.Flink
  1555. );
  1556. } else {
  1557. Iterator->MergedHead = NULL;
  1558. Iterator->Current = first;
  1559. }
  1560. *Range = (PRTL_RANGE) Iterator->Current;
  1561. } else {
  1562. Iterator->Current = NULL;
  1563. Iterator->MergedHead = NULL;
  1564. *Range = NULL;
  1565. status = STATUS_NO_MORE_ENTRIES;
  1566. }
  1567. return status;
  1568. }
  1569. NTSTATUS
  1570. RtlGetLastRange(
  1571. IN PRTL_RANGE_LIST RangeList,
  1572. OUT PRTL_RANGE_LIST_ITERATOR Iterator,
  1573. OUT PRTL_RANGE *Range
  1574. )
  1575. /*++
  1576. Routine Description:
  1577. This routine extracts the first range in a range list. If there are no
  1578. ranges then STATUS_NO_MORE_ENTRIES is returned.
  1579. Arguments:
  1580. RangeList - The range list to operate on.
  1581. Iterator - On success this contains the state of the iteration and can be
  1582. passed to RtlGetNextRange.
  1583. Range - On success this contains a pointer to the first range
  1584. Return Value:
  1585. Status code that indicates whether or not the function was successful:
  1586. STATUS_NO_MORE_ENTRIES
  1587. --*/
  1588. {
  1589. NTSTATUS status = STATUS_SUCCESS;
  1590. PRTLP_RANGE_LIST_ENTRY first;
  1591. RTL_PAGED_CODE();
  1592. //
  1593. // Fill in the first part of the iterator
  1594. //
  1595. Iterator->RangeListHead = &RangeList->ListHead;
  1596. Iterator->Stamp = RangeList->Stamp;
  1597. if (!IsListEmpty(&RangeList->ListHead)) {
  1598. first = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(RangeList->ListHead.Blink);
  1599. //
  1600. // Fill in the iterator and update to point to the first merged
  1601. // range if we are merged
  1602. //
  1603. if (MERGED(first)) {
  1604. ASSERT(!IsListEmpty(&first->Merged.ListHead));
  1605. Iterator->MergedHead = &first->Merged.ListHead;
  1606. Iterator->Current = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1607. first->Merged.ListHead.Blink
  1608. );
  1609. } else {
  1610. Iterator->MergedHead = NULL;
  1611. Iterator->Current = first;
  1612. }
  1613. *Range = (PRTL_RANGE) Iterator->Current;
  1614. } else {
  1615. Iterator->Current = NULL;
  1616. Iterator->MergedHead = NULL;
  1617. *Range = NULL;
  1618. status = STATUS_NO_MORE_ENTRIES;
  1619. }
  1620. return status;
  1621. }
  1622. NTSTATUS
  1623. RtlGetNextRange(
  1624. IN OUT PRTL_RANGE_LIST_ITERATOR Iterator,
  1625. OUT PRTL_RANGE *Range,
  1626. IN BOOLEAN MoveForwards
  1627. )
  1628. /*++
  1629. Routine Description:
  1630. This routine extracts the next range in a range list. If there are no
  1631. more ranges then STATUS_NO_MORE_ENTRIES is returned.
  1632. Arguments:
  1633. Iterator - The iterator filled in by RtlGet{First|Next}Range which will
  1634. be update on success.
  1635. Range - On success this contains a pointer to the next range
  1636. MoveForwards - If true, go forwards thru the list, otherwise,
  1637. go backwards.
  1638. Return Value:
  1639. Status code that indicates whether or not the function was successful:
  1640. STATUS_NO_MORE_ENTRIES
  1641. STATUS_INVALID_PARAMETER
  1642. Note:
  1643. Add/Delete operations can not be performed on the list between calls to
  1644. RtlGetFirstRange / RtlGetNextRange and RtlGetNextRange / RtlGetNextRange.
  1645. If such calls are made the routine will detect and fail the call.
  1646. --*/
  1647. {
  1648. PRTLP_RANGE_LIST_ENTRY mergedEntry, next;
  1649. PLIST_ENTRY entry;
  1650. RTL_PAGED_CODE();
  1651. //
  1652. // Make sure that we haven't changed the list between calls
  1653. //
  1654. if (RANGE_LIST_FROM_LIST_HEAD(Iterator->RangeListHead)->Stamp !=
  1655. Iterator->Stamp) {
  1656. ASSERTMSG(
  1657. "RtlGetNextRange: Add/Delete operations have been performed while \
  1658. iterating through a list\n", FALSE);
  1659. return STATUS_INVALID_PARAMETER;
  1660. }
  1661. //
  1662. // If we have already reached the end of the list then return
  1663. //
  1664. if (!Iterator->Current) {
  1665. *Range = NULL;
  1666. return STATUS_NO_MORE_ENTRIES;
  1667. }
  1668. entry = &((PRTLP_RANGE_LIST_ENTRY)(Iterator->Current))->ListEntry;
  1669. next = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1670. MoveForwards ? entry->Flink : entry->Blink);
  1671. ASSERT(next);
  1672. //
  1673. // Are we in a merged range?
  1674. //
  1675. if (Iterator->MergedHead) {
  1676. //
  1677. // Have we reached the end of the merged range?
  1678. //
  1679. if (&next->ListEntry == Iterator->MergedHead) {
  1680. //
  1681. // Get back to the merged entry
  1682. //
  1683. mergedEntry = CONTAINING_RECORD(
  1684. Iterator->MergedHead,
  1685. RTLP_RANGE_LIST_ENTRY,
  1686. Merged.ListHead
  1687. );
  1688. //
  1689. // Move on to the next entry in the main list
  1690. //
  1691. next = MoveForwards ?
  1692. RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1693. mergedEntry->ListEntry.Flink
  1694. )
  1695. : RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1696. mergedEntry->ListEntry.Blink
  1697. );
  1698. Iterator->MergedHead = NULL;
  1699. } else {
  1700. //
  1701. // There are merged ranges left - return the next one
  1702. //
  1703. Iterator->Current = next;
  1704. *Range = (PRTL_RANGE) next;
  1705. return STATUS_SUCCESS;
  1706. }
  1707. }
  1708. //
  1709. // Have we reached the end of the main list?
  1710. //
  1711. if (&next->ListEntry == Iterator->RangeListHead) {
  1712. //
  1713. // Tell the caller there are no more ranges
  1714. //
  1715. Iterator->Current = NULL;
  1716. *Range = NULL;
  1717. return STATUS_NO_MORE_ENTRIES;
  1718. } else {
  1719. //
  1720. // Is the next range merged?
  1721. //
  1722. if (MERGED(next)) {
  1723. //
  1724. // Goto the first merged entry
  1725. //
  1726. ASSERT(!Iterator->MergedHead);
  1727. Iterator->MergedHead = &next->Merged.ListHead;
  1728. Iterator->Current = MoveForwards ?
  1729. RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1730. next->Merged.ListHead.Flink
  1731. )
  1732. : RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1733. next->Merged.ListHead.Blink
  1734. );
  1735. } else {
  1736. //
  1737. // Go to the next entry in the main list
  1738. //
  1739. Iterator->Current = RANGE_LIST_ENTRY_FROM_LIST_ENTRY(
  1740. &next->ListEntry
  1741. );
  1742. }
  1743. *Range = (PRTL_RANGE) Iterator->Current;
  1744. }
  1745. return STATUS_SUCCESS;
  1746. }
  1747. NTSTATUS
  1748. RtlMergeRangeLists(
  1749. OUT PRTL_RANGE_LIST MergedRangeList,
  1750. IN PRTL_RANGE_LIST RangeList1,
  1751. IN PRTL_RANGE_LIST RangeList2,
  1752. IN ULONG Flags
  1753. )
  1754. /*++
  1755. Routine Description:
  1756. This routine merges two range lists into one.
  1757. Arguments:
  1758. MergedRangeList - An empty range list where on success the result of the
  1759. merge will be placed.
  1760. RangeList1 - One of the range lists to be merged.
  1761. RangeList2 - The other the range list to merged.
  1762. Flags - Modifies the behaviour of the routine:
  1763. RTL_RANGE_LIST_MERGE_IF_CONFLICT - Merged ranges even if the conflict.
  1764. Return Value:
  1765. Status code that indicates whether or not the function was successful:
  1766. STATUS_INSUFFICIENT_RESOURCES
  1767. STATUS_RANGE_LIST_CONFLICT
  1768. --*/
  1769. {
  1770. NTSTATUS status;
  1771. PRTLP_RANGE_LIST_ENTRY current, currentMerged, newEntry;
  1772. ULONG addFlags;
  1773. RTL_PAGED_CODE();
  1774. DEBUG_PRINT(1,
  1775. ("RtlMergeRangeList(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
  1776. MergedRangeList,
  1777. RangeList1,
  1778. RangeList2,
  1779. Flags
  1780. ));
  1781. //
  1782. // Copy the first range list
  1783. //
  1784. status = RtlCopyRangeList(MergedRangeList, RangeList1);
  1785. if (!NT_SUCCESS(status)) {
  1786. goto cleanup;
  1787. }
  1788. //
  1789. // Add all ranges from 2nd list
  1790. //
  1791. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY, &RangeList2->ListHead, current) {
  1792. if (MERGED(current)) {
  1793. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY,
  1794. &current->Merged.ListHead,
  1795. currentMerged) {
  1796. if (!(newEntry = RtlpCopyRangeListEntry(currentMerged))) {
  1797. status = STATUS_INSUFFICIENT_RESOURCES;
  1798. goto cleanup;
  1799. }
  1800. if (CONFLICT(currentMerged)) {
  1801. //
  1802. // If a range was already conflicting in then it will conflict in
  1803. // the merged range list - allow this.
  1804. //
  1805. addFlags = Flags | RTL_RANGE_LIST_ADD_IF_CONFLICT;
  1806. } else {
  1807. addFlags = Flags;
  1808. }
  1809. status = RtlpAddRange(&MergedRangeList->ListHead,
  1810. newEntry,
  1811. addFlags
  1812. );
  1813. }
  1814. } else {
  1815. if (!(newEntry = RtlpCopyRangeListEntry(current))){
  1816. status = STATUS_INSUFFICIENT_RESOURCES;
  1817. goto cleanup;
  1818. }
  1819. if (CONFLICT(current)) {
  1820. //
  1821. // If a range was already conflicting in then it will conflict in
  1822. // the merged range list - allow this.
  1823. //
  1824. addFlags = Flags | RTL_RANGE_LIST_ADD_IF_CONFLICT;
  1825. } else {
  1826. addFlags = Flags;
  1827. }
  1828. status = RtlpAddRange(&MergedRangeList->ListHead,
  1829. newEntry,
  1830. addFlags
  1831. );
  1832. if (!NT_SUCCESS(status)) {
  1833. goto cleanup;
  1834. }
  1835. }
  1836. }
  1837. //
  1838. // Correct the count
  1839. //
  1840. MergedRangeList->Count += RangeList2->Count;
  1841. MergedRangeList->Stamp += RangeList2->Count;
  1842. return status;
  1843. cleanup:
  1844. //
  1845. // Something went wrong... Free up what we have built of the
  1846. // new list and return the error
  1847. //
  1848. RtlFreeRangeList(MergedRangeList);
  1849. return status;
  1850. }
  1851. NTSTATUS
  1852. RtlInvertRangeList(
  1853. OUT PRTL_RANGE_LIST InvertedRangeList,
  1854. IN PRTL_RANGE_LIST RangeList
  1855. )
  1856. /*
  1857. Routine Description:
  1858. This inverts a range list so that all areas which are allocated
  1859. in InvertedRangeList will not be in RangeList, and vice
  1860. versa. The ranges in InvertedRangeList will all be owned by NULL.
  1861. Arguments:
  1862. InvertedRangeList - a pointer to an empty Range List to be filled
  1863. with the inverted list
  1864. RangeList - a pointer to the Range List to be inverted
  1865. Return Value:
  1866. Status of operation.
  1867. */
  1868. {
  1869. PRTLP_RANGE_LIST_ENTRY currentRange;
  1870. ULONGLONG currentStart = 0;
  1871. NTSTATUS status;
  1872. RTL_PAGED_CODE();
  1873. //
  1874. // if Inverted List does not start out empty, the inverted list
  1875. // is meaningless
  1876. //
  1877. ASSERT(InvertedRangeList->Count == 0);
  1878. //
  1879. // iterate through all elements of the ReverseAllocation
  1880. // adding the unallocated part before the current element
  1881. // to the RealAllocation
  1882. //
  1883. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY,
  1884. &RangeList->ListHead,
  1885. currentRange) {
  1886. if (currentRange->Start > currentStart) {
  1887. //
  1888. // we want a NULL range owner to show that the
  1889. // range is unavailable
  1890. //
  1891. status = RtlAddRange(InvertedRangeList,
  1892. currentStart,
  1893. currentRange->Start-1,
  1894. 0, // Attributes
  1895. 0, // Flags
  1896. 0, // UserData
  1897. NULL); // Owner
  1898. if (!NT_SUCCESS(status)) {
  1899. return status;
  1900. }
  1901. }
  1902. currentStart = currentRange->End + 1;
  1903. }
  1904. //
  1905. // add the portion of the address space above the last
  1906. // element in the ReverseAllocation to the RealAllocation
  1907. //
  1908. // unless we've wrapped, in which case we've already added
  1909. // the last element
  1910. //
  1911. if (currentStart > (currentStart - 1)) {
  1912. status = RtlAddRange(InvertedRangeList,
  1913. currentStart,
  1914. MAX_ULONGLONG,
  1915. 0,
  1916. 0,
  1917. 0,
  1918. NULL);
  1919. if (!NT_SUCCESS(status)) {
  1920. return status;
  1921. }
  1922. }
  1923. return STATUS_SUCCESS;
  1924. }
  1925. #if DBG
  1926. VOID
  1927. RtlpDumpRangeListEntry(
  1928. LONG Level,
  1929. PRTLP_RANGE_LIST_ENTRY Entry,
  1930. BOOLEAN Indent
  1931. )
  1932. {
  1933. PWSTR indentString;
  1934. PRTLP_RANGE_LIST_ENTRY current;
  1935. RTL_PAGED_CODE();
  1936. if (Indent) {
  1937. indentString = L"\t\t";
  1938. } else {
  1939. indentString = L"";
  1940. }
  1941. //
  1942. // Print the range
  1943. //
  1944. DEBUG_PRINT(Level,
  1945. ("%sRange (0x%08x): 0x%I64x-0x%I64x\n",
  1946. indentString,
  1947. Entry,
  1948. Entry->Start,
  1949. Entry->End
  1950. ));
  1951. //
  1952. // Print the flags
  1953. //
  1954. DEBUG_PRINT(Level, ("%s\tPrivateFlags: ", indentString));
  1955. if (MERGED(Entry)) {
  1956. DEBUG_PRINT(Level, ("MERGED "));
  1957. }
  1958. DEBUG_PRINT(Level, ("\n%s\tPublicFlags: ", indentString));
  1959. if (SHARED(Entry)) {
  1960. DEBUG_PRINT(Level, ("SHARED "));
  1961. }
  1962. if (CONFLICT(Entry)) {
  1963. DEBUG_PRINT(Level, ("CONFLICT "));
  1964. }
  1965. DEBUG_PRINT(Level, ("\n"));
  1966. if (MERGED(Entry)) {
  1967. DEBUG_PRINT(Level, ("%sMerged entries:\n", indentString));
  1968. //
  1969. // Print the merged entries
  1970. //
  1971. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY,
  1972. &Entry->Merged.ListHead,
  1973. current) {
  1974. RtlpDumpRangeListEntry(Level, current, TRUE);
  1975. }
  1976. } else {
  1977. //
  1978. // Print the other data
  1979. //
  1980. DEBUG_PRINT(Level,
  1981. ("%s\tUserData: 0x%08x\n\tOwner: 0x%08x\n",
  1982. indentString,
  1983. Entry->Allocated.UserData,
  1984. Entry->Allocated.Owner
  1985. ));
  1986. }
  1987. }
  1988. VOID
  1989. RtlpDumpRangeList(
  1990. LONG Level,
  1991. PRTL_RANGE_LIST RangeList
  1992. )
  1993. {
  1994. PRTLP_RANGE_LIST_ENTRY current, currentMerged;
  1995. RTL_PAGED_CODE();
  1996. DEBUG_PRINT(Level,
  1997. ("*** Range List (0x%08x) - Count: %i\n",
  1998. RangeList,
  1999. RangeList->Count
  2000. ));
  2001. FOR_ALL_IN_LIST(RTLP_RANGE_LIST_ENTRY, &RangeList->ListHead, current) {
  2002. //
  2003. // Print the entry
  2004. //
  2005. RtlpDumpRangeListEntry(Level, current, FALSE);
  2006. }
  2007. }
  2008. #endif