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.

809 lines
18 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. range.c
  5. Abstract:
  6. This module implements the range list routines for the Plug and Play Memory
  7. driver.
  8. Author:
  9. Dave Richards (daveri) 16-Aug-1999
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "pnpmem.h"
  15. PPM_RANGE_LIST_ENTRY
  16. PmAllocateRangeListEntry(
  17. VOID
  18. );
  19. VOID
  20. PmFreeRangeListEntry(
  21. IN PPM_RANGE_LIST_ENTRY RangeListEntry
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, PmAllocateRangeListEntry)
  25. #pragma alloc_text(PAGE, PmInsertRangeInList)
  26. #pragma alloc_text(PAGE, PmFreeRangeListEntry)
  27. #pragma alloc_text(PAGE, PmAllocateRangeList)
  28. #pragma alloc_text(PAGE, PmFreeRangeList)
  29. #pragma alloc_text(PAGE, PmIsRangeListEmpty)
  30. #pragma alloc_text(PAGE, PmDebugDumpRangeList)
  31. #pragma alloc_text(PAGE, PmCopyRangeList)
  32. #pragma alloc_text(PAGE, PmSubtractRangeList)
  33. #pragma alloc_text(PAGE, PmIntersectRangeList)
  34. #pragma alloc_text(PAGE, PmCreateRangeListFromCmResourceList)
  35. #pragma alloc_text(PAGE, PmCreateRangeListFromPhysicalMemoryRanges)
  36. #endif
  37. PPM_RANGE_LIST_ENTRY
  38. PmAllocateRangeListEntry(
  39. VOID
  40. )
  41. /*++
  42. Routine Description:
  43. This function allocates a range list entry from paged pool.
  44. Arguments:
  45. None.
  46. Return Value:
  47. Upon success a pointer to a PM_RANGE_LIST_ENTRY object is returned,
  48. otherwise NULL.
  49. --*/
  50. {
  51. PPM_RANGE_LIST_ENTRY RangeListEntry;
  52. PAGED_CODE();
  53. RangeListEntry = ExAllocatePool(
  54. PagedPool,
  55. sizeof (PM_RANGE_LIST_ENTRY)
  56. );
  57. return RangeListEntry;
  58. }
  59. NTSTATUS
  60. PmInsertRangeInList(
  61. PPM_RANGE_LIST InsertionList,
  62. ULONGLONG Start,
  63. ULONGLONG End
  64. )
  65. {
  66. PPM_RANGE_LIST_ENTRY entry;
  67. entry = PmAllocateRangeListEntry();
  68. if (entry == NULL) {
  69. return STATUS_INSUFFICIENT_RESOURCES;
  70. }
  71. entry->Start = Start;
  72. entry->End = End;
  73. InsertTailList(&InsertionList->List,
  74. &entry->ListEntry);
  75. return STATUS_SUCCESS;
  76. }
  77. VOID
  78. PmFreeRangeListEntry(
  79. IN PPM_RANGE_LIST_ENTRY RangeListEntry
  80. )
  81. /*++
  82. Routine Description:
  83. This function de-allocates a range list entry object.
  84. Arguments:
  85. RangeListEntry - The PM_RANGE_LIST_ENTRY to be de-allocated.
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. PAGED_CODE();
  91. ASSERT(RangeListEntry != NULL);
  92. ExFreePool(RangeListEntry);
  93. }
  94. PPM_RANGE_LIST
  95. PmAllocateRangeList(
  96. VOID
  97. )
  98. /*++
  99. Routine Description:
  100. This function allocates and initializes a range list from paged pool.
  101. Arguments:
  102. None.
  103. Return Value:
  104. Upon success a pointer to a PM_RANGE_LIST object is returned, otherwise
  105. NULL.
  106. --*/
  107. {
  108. PPM_RANGE_LIST RangeList;
  109. PAGED_CODE();
  110. RangeList = ExAllocatePool(
  111. PagedPool,
  112. sizeof (PM_RANGE_LIST)
  113. );
  114. if (RangeList != NULL) {
  115. InitializeListHead(&RangeList->List);
  116. }
  117. return RangeList;
  118. }
  119. VOID
  120. PmFreeRangeList(
  121. IN PPM_RANGE_LIST RangeList
  122. )
  123. /*++
  124. Routine Description:
  125. This function removes all entries from a range list and de-allocates it.
  126. Arguments:
  127. RangeList - The PM_RANGE_LIST to be de-allocated.
  128. Return Value:
  129. None.
  130. --*/
  131. {
  132. PLIST_ENTRY ListEntry;
  133. PPM_RANGE_LIST_ENTRY RangeListEntry;
  134. PAGED_CODE();
  135. for (ListEntry = RangeList->List.Flink;
  136. ListEntry != &RangeList->List;
  137. ListEntry = RangeList->List.Flink) {
  138. RangeListEntry = CONTAINING_RECORD(
  139. ListEntry,
  140. PM_RANGE_LIST_ENTRY,
  141. ListEntry
  142. );
  143. RemoveEntryList(ListEntry);
  144. PmFreeRangeListEntry(RangeListEntry);
  145. }
  146. ExFreePool(RangeList);
  147. }
  148. BOOLEAN
  149. PmIsRangeListEmpty(
  150. IN PPM_RANGE_LIST RangeList
  151. )
  152. /*++
  153. Routine Description:
  154. This function determines whether the specified range list is empty.
  155. Arguments:
  156. RangeList - The PM_RANGE_LIST.
  157. Return Value:
  158. TRUE if the PM_RANGE_LIST has no PM_RANGE_LIST_ENTRYs, otherwise FALSE.
  159. --*/
  160. {
  161. PAGED_CODE();
  162. return IsListEmpty(&RangeList->List);
  163. }
  164. VOID
  165. PmDebugDumpRangeList(
  166. IN ULONG DebugPrintLevel,
  167. IN PCCHAR DebugMessage,
  168. PPM_RANGE_LIST RangeList
  169. )
  170. {
  171. PLIST_ENTRY listEntry;
  172. PPM_RANGE_LIST_ENTRY rangeListEntry;
  173. PmPrint((DebugPrintLevel, DebugMessage));
  174. if (RangeList == NULL) {
  175. PmPrint((DebugPrintLevel, "\tNULL\n"));
  176. return;
  177. } else if (PmIsRangeListEmpty(RangeList)) {
  178. PmPrint((DebugPrintLevel, "\tEmpty\n"));
  179. return;
  180. } else {
  181. for (listEntry = RangeList->List.Flink;
  182. listEntry != &RangeList->List;
  183. listEntry = listEntry->Flink) {
  184. rangeListEntry = CONTAINING_RECORD(
  185. listEntry,
  186. PM_RANGE_LIST_ENTRY,
  187. ListEntry
  188. );
  189. PmPrint((DebugPrintLevel, "\t0x%I64X - 0x%I64X\n",
  190. rangeListEntry->Start, rangeListEntry->End));
  191. }
  192. }
  193. }
  194. PPM_RANGE_LIST
  195. PmCopyRangeList(
  196. IN PPM_RANGE_LIST SrcRangeList
  197. )
  198. /*++
  199. Routine Description:
  200. This function creates a copy of a PM_RANGE_LIST and its supporting
  201. PM_RANGE_LIST_ENTRY objects.
  202. Arguments:
  203. SrcRangeList - The PM_RANGE_LIST to be copied.
  204. Return Value:
  205. Upon success a pointer to a PM_RANGE_LIST is returned, otherwise NULL.
  206. --*/
  207. {
  208. PPM_RANGE_LIST DstRangeList;
  209. PLIST_ENTRY ListEntry;
  210. PPM_RANGE_LIST_ENTRY SrcRangeListEntry;
  211. PPM_RANGE_LIST_ENTRY DstRangeListEntry;
  212. PAGED_CODE();
  213. DstRangeList = PmAllocateRangeList();
  214. if (DstRangeList != NULL) {
  215. for (ListEntry = SrcRangeList->List.Flink;
  216. ListEntry != &SrcRangeList->List;
  217. ListEntry = ListEntry->Flink) {
  218. SrcRangeListEntry = CONTAINING_RECORD(
  219. ListEntry,
  220. PM_RANGE_LIST_ENTRY,
  221. ListEntry
  222. );
  223. DstRangeListEntry = PmAllocateRangeListEntry();
  224. if (DstRangeListEntry == NULL) {
  225. PmFreeRangeList(DstRangeList);
  226. DstRangeList = NULL;
  227. break;
  228. }
  229. DstRangeListEntry->Start = SrcRangeListEntry->Start;
  230. DstRangeListEntry->End = SrcRangeListEntry->End;
  231. InsertTailList(
  232. &DstRangeList->List,
  233. &DstRangeListEntry->ListEntry
  234. );
  235. }
  236. }
  237. return DstRangeList;
  238. }
  239. PPM_RANGE_LIST
  240. PmSubtractRangeList(
  241. IN PPM_RANGE_LIST MinuendList,
  242. IN PPM_RANGE_LIST SubtrahendList
  243. )
  244. /*++
  245. Routine Description:
  246. This function creates a new range list which represents the set difference
  247. between MinuendList and SubtrahendList.
  248. Arguments:
  249. MinuendList - The minuend range list.
  250. SubtrahendList - The subtrahend range list.
  251. Return Value:
  252. Upon success a pointer to the destination (difference) PM_RANGE_LIST is
  253. returned, otherwise NULL.
  254. --*/
  255. {
  256. PPM_RANGE_LIST DstRangeList;
  257. PLIST_ENTRY DstListEntry;
  258. PPM_RANGE_LIST_ENTRY DstRangeListEntry;
  259. PLIST_ENTRY SrcListEntry;
  260. PPM_RANGE_LIST_ENTRY SrcRangeListEntry;
  261. ULONGLONG Start;
  262. ULONGLONG End;
  263. PLIST_ENTRY ListEntry;
  264. PPM_RANGE_LIST_ENTRY RangeListEntry;
  265. PAGED_CODE();
  266. ASSERT(MinuendList != NULL);
  267. ASSERT(SubtrahendList != NULL);
  268. //
  269. // Make a copy of the minuend.
  270. //
  271. DstRangeList = PmCopyRangeList(MinuendList);
  272. if (DstRangeList != NULL) {
  273. //
  274. // Loop through each range list entry in the minuend.
  275. //
  276. for (DstListEntry = DstRangeList->List.Flink;
  277. DstListEntry != &DstRangeList->List;
  278. DstListEntry = DstListEntry->Flink) {
  279. DstRangeListEntry = CONTAINING_RECORD(
  280. DstListEntry,
  281. PM_RANGE_LIST_ENTRY,
  282. ListEntry
  283. );
  284. //
  285. // Loop through each range list entry in the subtrahend.
  286. //
  287. for (SrcListEntry = SubtrahendList->List.Flink;
  288. SrcListEntry != &SubtrahendList->List;
  289. SrcListEntry = SrcListEntry->Flink) {
  290. SrcRangeListEntry = CONTAINING_RECORD(
  291. SrcListEntry,
  292. PM_RANGE_LIST_ENTRY,
  293. ListEntry
  294. );
  295. //
  296. // Compute the intersection of the minuend and subtrahend
  297. // range list entries.
  298. //
  299. Start = DstRangeListEntry->Start;
  300. if (Start < SrcRangeListEntry->Start) {
  301. Start = SrcRangeListEntry->Start;
  302. };
  303. End = DstRangeListEntry->End;
  304. if (End > SrcRangeListEntry->End) {
  305. End = SrcRangeListEntry->End;
  306. };
  307. if (Start > End) {
  308. continue;
  309. }
  310. //
  311. // There are 4 cases:
  312. //
  313. // 1. The intersection overlaps the minuend range completely.
  314. // 2. The intersection overlaps the start of the minuend
  315. // range.
  316. // 3. The intersection overlaps the end of the minuend range.
  317. // 4. The intersection overlaps the middle of the minuend
  318. // range.
  319. //
  320. if (DstRangeListEntry->Start == Start) {
  321. if (DstRangeListEntry->End == End) {
  322. //
  323. // Case 1: Remove the minuend range list entry.
  324. //
  325. ListEntry = DstListEntry;
  326. DstListEntry = DstListEntry->Blink;
  327. RemoveEntryList(ListEntry);
  328. PmFreeRangeListEntry(DstRangeListEntry);
  329. break;
  330. } else {
  331. //
  332. // Case 2: Increase the minuend's start.
  333. //
  334. DstRangeListEntry->Start = End + 1;
  335. }
  336. } else {
  337. if (DstRangeListEntry->End == End) {
  338. //
  339. // Case 3: Decrease the minend's end.
  340. //
  341. DstRangeListEntry->End = Start - 1;
  342. } else {
  343. //
  344. // Case 4: Divide the range list entry into two
  345. // pieces. The first range list entry's end should
  346. // be just before the intersection start. The
  347. // second range list entry's start should be just
  348. // after the intersection end.
  349. //
  350. RangeListEntry = PmAllocateRangeListEntry();
  351. if (RangeListEntry == NULL) {
  352. PmFreeRangeList(DstRangeList);
  353. return NULL;
  354. }
  355. RangeListEntry->Start = End + 1;
  356. RangeListEntry->End = DstRangeListEntry->End;
  357. //
  358. // BUGBUG Break the list ordering but ensure that
  359. // we'll perform the subtraction against the
  360. // new range list entry as well.
  361. //
  362. InsertHeadList(
  363. &DstRangeListEntry->ListEntry,
  364. &RangeListEntry->ListEntry
  365. );
  366. DstRangeListEntry->End = Start - 1;
  367. }
  368. }
  369. }
  370. }
  371. }
  372. return DstRangeList;
  373. }
  374. PPM_RANGE_LIST
  375. PmIntersectRangeList(
  376. IN PPM_RANGE_LIST SrcRangeList1,
  377. IN PPM_RANGE_LIST SrcRangeList2
  378. )
  379. /*++
  380. Routine Description:
  381. This function creates a new range list which represents the intersection
  382. between SrcRangeList1 and SrcRangeList2.
  383. Arguments:
  384. SrcRangeList1, SrcRangeList - The range lists upon which to compute the
  385. intersection.
  386. Return Value:
  387. Upon success a pointer to the destination (intersection) PM_RANGE_LIST is
  388. returned, otherwise NULL.
  389. --*/
  390. {
  391. PPM_RANGE_LIST DstRangeList;
  392. PLIST_ENTRY SrcListEntry1;
  393. PPM_RANGE_LIST_ENTRY SrcRangeListEntry1;
  394. PLIST_ENTRY SrcListEntry2;
  395. PPM_RANGE_LIST_ENTRY SrcRangeListEntry2;
  396. ULONGLONG Start;
  397. ULONGLONG End;
  398. PPM_RANGE_LIST_ENTRY RangeListEntry;
  399. PAGED_CODE();
  400. ASSERT(SrcRangeList1 != NULL);
  401. ASSERT(SrcRangeList2 != NULL);
  402. DstRangeList = PmAllocateRangeList();
  403. if (DstRangeList != NULL) {
  404. for (SrcListEntry1 = SrcRangeList1->List.Flink;
  405. SrcListEntry1 != &SrcRangeList1->List;
  406. SrcListEntry1 = SrcListEntry1->Flink) {
  407. SrcRangeListEntry1 = CONTAINING_RECORD(
  408. SrcListEntry1,
  409. PM_RANGE_LIST_ENTRY,
  410. ListEntry
  411. );
  412. for (SrcListEntry2 = SrcRangeList2->List.Flink;
  413. SrcListEntry2 != &SrcRangeList2->List;
  414. SrcListEntry2 = SrcListEntry2->Flink) {
  415. SrcRangeListEntry2 = CONTAINING_RECORD(
  416. SrcListEntry2,
  417. PM_RANGE_LIST_ENTRY,
  418. ListEntry
  419. );
  420. Start = SrcRangeListEntry1->Start;
  421. if (Start < SrcRangeListEntry2->Start) {
  422. Start = SrcRangeListEntry2->Start;
  423. };
  424. End = SrcRangeListEntry1->End;
  425. if (End > SrcRangeListEntry2->End) {
  426. End = SrcRangeListEntry2->End;
  427. };
  428. if (Start > End) {
  429. continue;
  430. }
  431. RangeListEntry = PmAllocateRangeListEntry();
  432. if (RangeListEntry == NULL) {
  433. PmFreeRangeList(DstRangeList);
  434. return NULL;
  435. }
  436. RangeListEntry->Start = Start;
  437. RangeListEntry->End = End;
  438. InsertTailList(
  439. &DstRangeList->List,
  440. &RangeListEntry->ListEntry
  441. );
  442. }
  443. }
  444. }
  445. return DstRangeList;
  446. }
  447. PPM_RANGE_LIST
  448. PmCreateRangeListFromCmResourceList(
  449. IN PCM_RESOURCE_LIST CmResourceList
  450. )
  451. /*++
  452. Routine Description:
  453. This function converts a CM_RESOURCE_LIST to a PM_RANGE_LIST. Only
  454. CmResourceTypeMemory descriptors are added to the PM_RANGE_LIST.
  455. Arguments:
  456. CmResourceList - The CM_RESOURCE_LIST to convert.
  457. Return Value:
  458. Upon success a pointer to the converted PM_RANGE_LIST is returned,
  459. otherwise NULL.
  460. --*/
  461. {
  462. PPM_RANGE_LIST RangeList;
  463. PCM_FULL_RESOURCE_DESCRIPTOR FDesc;
  464. ULONG FIndex;
  465. PCM_PARTIAL_RESOURCE_DESCRIPTOR PDesc;
  466. ULONG PIndex;
  467. ULONGLONG Start;
  468. ULONGLONG End;
  469. PPM_RANGE_LIST_ENTRY RangeListEntry;
  470. PAGED_CODE();
  471. RangeList = PmAllocateRangeList();
  472. if (RangeList == NULL) {
  473. return NULL;
  474. }
  475. FDesc = CmResourceList->List;
  476. //
  477. // Note: Any Device-Specific partial descriptor (which could be
  478. // variably sized) is defined to be at the end and thus this code
  479. // is safe.
  480. //
  481. for (FIndex = 0;
  482. FIndex < CmResourceList->Count;
  483. FIndex++) {
  484. PDesc = FDesc->PartialResourceList.PartialDescriptors;
  485. for (PIndex = 0;
  486. PIndex < FDesc->PartialResourceList.Count;
  487. PIndex++, PDesc++) {
  488. //
  489. // ISSUE Fix for ia64 (andy's change), IA32 large memory region
  490. //
  491. if (PDesc->Type == CmResourceTypeMemory) {
  492. Start = PDesc->u.Memory.Start.QuadPart;
  493. End = Start + PDesc->u.Memory.Length - 1;
  494. RangeListEntry = PmAllocateRangeListEntry();
  495. if (RangeListEntry == NULL) {
  496. PmFreeRangeList(RangeList);
  497. return NULL;
  498. }
  499. RangeListEntry->Start = Start;
  500. RangeListEntry->End = End;
  501. InsertTailList(
  502. &RangeList->List,
  503. &RangeListEntry->ListEntry
  504. );
  505. }
  506. }
  507. FDesc = (PCM_FULL_RESOURCE_DESCRIPTOR)PDesc;
  508. }
  509. return RangeList;
  510. }
  511. PPM_RANGE_LIST
  512. PmCreateRangeListFromPhysicalMemoryRanges(
  513. VOID
  514. )
  515. /*++
  516. Routine Description:
  517. This function calls MmGetPhysicalRanges and converts the returned
  518. PHYSICAL_MEMORY_RANGE list to a PM_RANGE_LIST.
  519. Arguments:
  520. None.
  521. Return Value:
  522. Upon success a pointer to the converted PM_RANGE_LIST is returned,
  523. otherwise NULL.
  524. --*/
  525. {
  526. PPM_RANGE_LIST RangeList;
  527. PPHYSICAL_MEMORY_RANGE MemoryRange;
  528. ULONG Index;
  529. ULONGLONG Start;
  530. ULONGLONG End;
  531. PPM_RANGE_LIST_ENTRY RangeListEntry;
  532. PAGED_CODE();
  533. RangeList = PmAllocateRangeList();
  534. if (RangeList != NULL) {
  535. MemoryRange = MmGetPhysicalMemoryRanges();
  536. if (MemoryRange == NULL) {
  537. PmFreeRangeList(RangeList);
  538. RangeList = NULL;
  539. } else {
  540. for (Index = 0;
  541. MemoryRange[Index].NumberOfBytes.QuadPart != 0;
  542. Index++) {
  543. Start = MemoryRange[Index].BaseAddress.QuadPart;
  544. End = Start + (MemoryRange[Index].NumberOfBytes.QuadPart - 1);
  545. RangeListEntry = PmAllocateRangeListEntry();
  546. if (RangeListEntry == NULL) {
  547. PmFreeRangeList(RangeList);
  548. ExFreePool(MemoryRange);
  549. return NULL;
  550. }
  551. RangeListEntry->Start = Start;
  552. RangeListEntry->End = End;
  553. InsertTailList(
  554. &RangeList->List,
  555. &RangeListEntry->ListEntry
  556. );
  557. }
  558. ExFreePool(MemoryRange);
  559. }
  560. }
  561. return RangeList;
  562. }