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.

1175 lines
32 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. rangesup.c
  6. Abstract:
  7. Supplies support function for dealing with SUPPORTED_RANGEs.
  8. Author:
  9. Ken Reneris (kenr) March-27-1995
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. */
  14. #include "halp.h"
  15. #define STATIC
  16. STATIC ULONG
  17. HalpSortRanges (
  18. IN PSUPPORTED_RANGE pRange1
  19. );
  20. typedef struct tagNRParams {
  21. PIO_RESOURCE_DESCRIPTOR InDesc;
  22. PIO_RESOURCE_DESCRIPTOR OutDesc;
  23. PSUPPORTED_RANGE CurrentPosition;
  24. LONGLONG Base;
  25. LONGLONG Limit;
  26. UCHAR DescOpt;
  27. BOOLEAN AnotherListPending;
  28. } NRPARAMS, *PNRPARAMS;
  29. STATIC PIO_RESOURCE_DESCRIPTOR
  30. HalpGetNextSupportedRange (
  31. IN LONGLONG MinimumAddress,
  32. IN LONGLONG MaximumAddress,
  33. IN OUT PNRPARAMS PNRParams
  34. );
  35. //
  36. // These following functions are usable at to initialize
  37. // the supported_ranges information for a bus handler.
  38. // HalpMergeRanges - merges two bus supported ranges
  39. // HalpMergeRangeList - merges two single supported ranges lists
  40. // HalpCopyRanges - copy a bus supported ranges to a new supported ranges structure
  41. // HalpAddRangeList - adds a supported range list to another
  42. // HalpAddRange - adds a single range to a supported range list
  43. // HalpRemoveRanges - removes all ranges from one buses supported ranges from another
  44. // HalpRemoveRangeList - removes all ranges in one supported range list from another
  45. // HalpRemoveRange - removes a single range from a supported range list
  46. // HalpAllocateNewRangeList - allocates a new, "blank" bus supported ranges structure
  47. // HalpFreeRangeList - frees an entire bus supported ranges
  48. //
  49. // HalpConsolidateRanges - cleans up a supported ranges structure to be ready for usage
  50. //
  51. //
  52. // These functions are used to intersect a buses supported ranges
  53. // to an IO_RESOURCE_REQUIREMENTS_LIST:
  54. // HaliAdjustResourceListRange
  55. //
  56. // These functions are used internal to this module:
  57. // HalpSortRanges
  58. // HalpGetNextSupportedRange
  59. //
  60. #ifdef ALLOC_PRAGMA
  61. #pragma alloc_text(INIT,HalpMergeRanges)
  62. #pragma alloc_text(INIT,HalpMergeRangeList)
  63. #pragma alloc_text(INIT,HalpCopyRanges)
  64. #pragma alloc_text(INIT,HalpAddRangeList)
  65. #pragma alloc_text(INIT,HalpAddRange)
  66. #pragma alloc_text(INIT,HalpRemoveRanges)
  67. #pragma alloc_text(INIT,HalpRemoveRangeList)
  68. #pragma alloc_text(INIT,HalpRemoveRange)
  69. #pragma alloc_text(INIT,HalpConsolidateRanges)
  70. #pragma alloc_text(PAGE,HalpAllocateNewRangeList)
  71. #pragma alloc_text(PAGE,HalpFreeRangeList)
  72. #pragma alloc_text(PAGE,HaliAdjustResourceListRange)
  73. #pragma alloc_text(PAGE,HalpSortRanges)
  74. #pragma alloc_text(PAGE,HalpGetNextSupportedRange)
  75. #endif
  76. #ifdef ALLOC_DATA_PRAGMA
  77. #pragma const_seg("PAGECONST")
  78. #endif
  79. struct {
  80. ULONG Offset;
  81. } const HalpRangeList[] = {
  82. FIELD_OFFSET (SUPPORTED_RANGES, IO),
  83. FIELD_OFFSET (SUPPORTED_RANGES, Memory),
  84. FIELD_OFFSET (SUPPORTED_RANGES, PrefetchMemory),
  85. FIELD_OFFSET (SUPPORTED_RANGES, Dma),
  86. 0,
  87. };
  88. #ifdef ALLOC_DATA_PRAGMA
  89. #pragma const_seg()
  90. #endif
  91. #define RANGE_LIST(a,i) ((PSUPPORTED_RANGE) ((PUCHAR) a + HalpRangeList[i].Offset))
  92. PSUPPORTED_RANGES
  93. HalpMergeRanges (
  94. IN PSUPPORTED_RANGES Parent,
  95. IN PSUPPORTED_RANGES Child
  96. )
  97. /*++
  98. Routine Description:
  99. This function produces a NewList which is a subset of all overlapping
  100. ranges in Parent and Child for all range lists.
  101. The resulting SystemBaseAddresses and SystemAddressSpaces are taken
  102. from the Child supported ranges.
  103. Note: Resulting list needs consolidated
  104. --*/
  105. {
  106. PSUPPORTED_RANGES NewList;
  107. PSUPPORTED_RANGES List1;
  108. NewList = HalpAllocateNewRangeList();
  109. HalpMergeRangeList (&NewList->IO, &Parent->IO, &Child->IO);
  110. HalpMergeRangeList (&NewList->Dma, &Parent->Dma, &Child->Dma);
  111. HalpMergeRangeList (&NewList->Memory, &Parent->Memory, &Child->Memory);
  112. List1 = HalpAllocateNewRangeList();
  113. HalpAddRangeList (&List1->Memory, &Parent->Memory);
  114. HalpAddRangeList (&List1->Memory, &Parent->PrefetchMemory);
  115. HalpMergeRangeList (&NewList->PrefetchMemory, &List1->Memory, &Child->PrefetchMemory);
  116. HalpFreeRangeList (List1);
  117. return NewList;
  118. }
  119. VOID
  120. HalpMergeRangeList (
  121. OUT PSUPPORTED_RANGE NewList,
  122. IN PSUPPORTED_RANGE Parent,
  123. IN PSUPPORTED_RANGE Child
  124. )
  125. /*++
  126. Routine Description:
  127. Completes NewList to be a subset of all overlapping
  128. ranges in the Parent and Child list.
  129. The resulting SystemBaseAddresses and SystemAddressSpaces are
  130. taken from the Child supported ranges.
  131. Note: Resulting list needs consolidated
  132. --*/
  133. {
  134. BOOLEAN HeadCompleted;
  135. PSUPPORTED_RANGE List1, List2;
  136. LONGLONG Base, Limit;
  137. HeadCompleted = FALSE;
  138. for (List1 = Parent; List1; List1 = List1->Next) {
  139. for (List2 = Child; List2; List2 = List2->Next) {
  140. Base = List1->Base;
  141. Limit = List1->Limit;
  142. //
  143. // Clip to range supported by List2
  144. //
  145. if (Base < List2->Base) {
  146. Base = List2->Base;
  147. }
  148. if (Limit > List2->Limit) {
  149. Limit = List2->Limit;
  150. }
  151. //
  152. // If valid range, add it
  153. //
  154. if (Base <= Limit) {
  155. if (HeadCompleted) {
  156. NewList->Next = ExAllocatePoolWithTag (
  157. SPRANGEPOOL,
  158. sizeof (SUPPORTED_RANGE),
  159. HAL_POOL_TAG
  160. );
  161. RtlZeroMemory (NewList->Next, sizeof (SUPPORTED_RANGE));
  162. NewList = NewList->Next;
  163. NewList->Next = NULL;
  164. }
  165. HeadCompleted = TRUE;
  166. NewList->Base = Base;
  167. NewList->Limit = Limit;
  168. NewList->SystemBase = List2->SystemBase;
  169. NewList->SystemAddressSpace = List2->SystemAddressSpace;
  170. }
  171. }
  172. }
  173. }
  174. PSUPPORTED_RANGES
  175. HalpCopyRanges (
  176. PSUPPORTED_RANGES Source
  177. )
  178. /*++
  179. Routine Description:
  180. Builds a copy of the Source list to the destination list.
  181. Note that an invalid entry lands at the begining of the copy, but
  182. that's OK - it will be pulled out at consolidation time.
  183. Note: Resulting list needs consolidated
  184. --*/
  185. {
  186. PSUPPORTED_RANGES Dest;
  187. ULONG i;
  188. Dest = HalpAllocateNewRangeList ();
  189. for (i=0; HalpRangeList[i].Offset; i++) {
  190. HalpAddRangeList (RANGE_LIST(Dest, i), RANGE_LIST(Source, i));
  191. }
  192. return Dest;
  193. }
  194. VOID
  195. HalpAddRangeList (
  196. IN OUT PSUPPORTED_RANGE DRange,
  197. OUT PSUPPORTED_RANGE SRange
  198. )
  199. /*++
  200. Routine Description:
  201. Adds ranges from SRange to DRange.
  202. --*/
  203. {
  204. while (SRange) {
  205. HalpAddRange (
  206. DRange,
  207. SRange->SystemAddressSpace,
  208. SRange->SystemBase,
  209. SRange->Base,
  210. SRange->Limit
  211. );
  212. SRange = SRange->Next;
  213. }
  214. }
  215. VOID
  216. HalpAddRange (
  217. PSUPPORTED_RANGE HRange,
  218. ULONG AddressSpace,
  219. LONGLONG SystemBase,
  220. LONGLONG Base,
  221. LONGLONG Limit
  222. )
  223. /*++
  224. Routine Description:
  225. Adds a range to the supported list. Here we just add the range, if it's
  226. a duplicate it will be removed later at consolidation time.
  227. --*/
  228. {
  229. PSUPPORTED_RANGE Range;
  230. Range = ExAllocatePoolWithTag (
  231. SPRANGEPOOL,
  232. sizeof (SUPPORTED_RANGE),
  233. HAL_POOL_TAG
  234. );
  235. RtlZeroMemory (Range, sizeof (SUPPORTED_RANGE));
  236. Range->Next = HRange->Next;
  237. HRange->Next = Range;
  238. Range->Base = Base;
  239. Range->Limit = Limit;
  240. Range->SystemBase = SystemBase;
  241. Range->SystemAddressSpace = AddressSpace;
  242. }
  243. VOID
  244. HalpRemoveRanges (
  245. IN OUT PSUPPORTED_RANGES Minuend,
  246. IN PSUPPORTED_RANGES Subtrahend
  247. )
  248. /*++
  249. Routine Description:
  250. Returns a list where all ranges from Subtrahend are removed from Minuend.
  251. Note: Resulting list needs consolidated
  252. --*/
  253. {
  254. HalpRemoveRangeList (&Minuend->IO, &Subtrahend->IO);
  255. HalpRemoveRangeList (&Minuend->Dma, &Subtrahend->Dma);
  256. HalpRemoveRangeList (&Minuend->Memory, &Subtrahend->Memory);
  257. HalpRemoveRangeList (&Minuend->Memory, &Subtrahend->PrefetchMemory);
  258. HalpRemoveRangeList (&Minuend->PrefetchMemory, &Subtrahend->PrefetchMemory);
  259. HalpRemoveRangeList (&Minuend->PrefetchMemory, &Subtrahend->Memory);
  260. }
  261. VOID
  262. HalpRemoveRangeList (
  263. IN OUT PSUPPORTED_RANGE Minuend,
  264. IN PSUPPORTED_RANGE Subtrahend
  265. )
  266. /*++
  267. Routine Description:
  268. Removes all ranges from Subtrahend from Minuend
  269. ranges in Source1 and Source1 list
  270. --*/
  271. {
  272. while (Subtrahend) {
  273. HalpRemoveRange (
  274. Minuend,
  275. Subtrahend->Base,
  276. Subtrahend->Limit
  277. );
  278. Subtrahend = Subtrahend->Next;
  279. }
  280. }
  281. VOID
  282. HalpRemoveRange (
  283. PSUPPORTED_RANGE HRange,
  284. LONGLONG Base,
  285. LONGLONG Limit
  286. )
  287. /*++
  288. Routine Description:
  289. Removes the range Base-Limit from the the HRange list
  290. Note: The returned list needs consolidated, as some entries
  291. may be turned into "null ranges".
  292. --*/
  293. {
  294. PSUPPORTED_RANGE Range;
  295. //
  296. // If range isn't a range at all, then nothing to remove
  297. //
  298. if (Limit < Base) {
  299. return ;
  300. }
  301. //
  302. // Clip any area not to include this range
  303. //
  304. for (Range = HRange; Range; Range = Range->Next) {
  305. if (Range->Limit < Range->Base) {
  306. continue;
  307. }
  308. if (Range->Base < Base) {
  309. if (Range->Limit >= Base && Range->Limit <= Limit) {
  310. // truncate
  311. Range->Limit = Base - 1;
  312. }
  313. if (Range->Limit > Limit) {
  314. //
  315. // Target area is contained totally within this area.
  316. // Split into two ranges
  317. //
  318. HalpAddRange (
  319. HRange,
  320. Range->SystemAddressSpace,
  321. Range->SystemBase,
  322. Limit + 1,
  323. Range->Limit
  324. );
  325. Range->Limit = Base - 1;
  326. }
  327. } else {
  328. // Range->Base >= Base
  329. if (Range->Base <= Limit) {
  330. if (Range->Limit <= Limit) {
  331. //
  332. // This range is totally within the target area. Remove it.
  333. // (make it invalid - it will get remove when colsolidated)
  334. //
  335. Range->Base = 1;
  336. Range->Limit = 0;
  337. } else {
  338. // Bump begining
  339. Range->Base = Limit + 1;
  340. }
  341. }
  342. }
  343. }
  344. }
  345. PSUPPORTED_RANGES
  346. HalpConsolidateRanges (
  347. IN OUT PSUPPORTED_RANGES Ranges
  348. )
  349. /*++
  350. Routine Description:
  351. Cleans the Range list. Consolidates overlapping ranges, removes
  352. ranges which don't have any size, etc...
  353. The returned Ranges list is a clean as possible, and is now ready
  354. to be used.
  355. --*/
  356. {
  357. PSUPPORTED_RANGE RangeList, List1, List2;
  358. LONGLONG Base, Limit, SystemBase;
  359. ULONG i, AddressSpace;
  360. LONGLONG l;
  361. ASSERT (Ranges != NULL);
  362. for (i=0; HalpRangeList[i].Offset; i++) {
  363. RangeList = RANGE_LIST(Ranges, i);
  364. //
  365. // Sort the list by base address
  366. //
  367. for (List1 = RangeList; List1; List1 = List1->Next) {
  368. for (List2 = List1->Next; List2; List2 = List2->Next) {
  369. if (List2->Base < List1->Base) {
  370. Base = List1->Base;
  371. Limit = List1->Limit;
  372. SystemBase = List1->SystemBase;
  373. AddressSpace = List1->SystemAddressSpace;
  374. List1->Base = List2->Base;
  375. List1->Limit = List2->Limit;
  376. List1->SystemBase = List2->SystemBase;
  377. List1->SystemAddressSpace = List2->SystemAddressSpace;
  378. List2->Base = Base;
  379. List2->Limit = Limit;
  380. List2->SystemBase = SystemBase;
  381. List2->SystemAddressSpace = AddressSpace;
  382. }
  383. }
  384. }
  385. //
  386. // Check for adjacent/overlapping ranges and combined them
  387. //
  388. List1 = RangeList;
  389. while (List1 && List1->Next) {
  390. if (List1->Limit < List1->Base) {
  391. //
  392. // This range's limit is less then it's base. This
  393. // entry doesn't reprent anything uasable, remove it.
  394. //
  395. List2 = List1->Next;
  396. List1->Next = List2->Next;
  397. List1->Base = List2->Base;
  398. List1->Limit = List2->Limit;
  399. List1->SystemBase = List2->SystemBase;
  400. List1->SystemAddressSpace = List2->SystemAddressSpace;
  401. ExFreePool (List2);
  402. continue;
  403. }
  404. l = List1->Limit + 1;
  405. if (l > List1->Limit && l >= List1->Next->Base &&
  406. (List1->SystemBase == List1->Next->SystemBase)) {
  407. //
  408. // Overlapping. Combine them.
  409. //
  410. List2 = List1->Next;
  411. List1->Next = List2->Next;
  412. if (List2->Limit > List1->Limit) {
  413. List1->Limit = List2->Limit;
  414. ASSERT (List1->SystemAddressSpace == List2->SystemAddressSpace);
  415. }
  416. ExFreePool (List2);
  417. continue ;
  418. }
  419. List1 = List1->Next;
  420. }
  421. //
  422. // If the last range is invalid, and it's not the only
  423. // thing in the list - remove it
  424. //
  425. if (List1 != RangeList && List1->Limit < List1->Base) {
  426. for (List2=RangeList; List2->Next != List1; List2 = List2->Next) ;
  427. List2->Next = NULL;
  428. ExFreePool (List1);
  429. }
  430. }
  431. return Ranges;
  432. }
  433. PSUPPORTED_RANGES
  434. HalpAllocateNewRangeList (
  435. VOID
  436. )
  437. /*++
  438. Routine Description:
  439. Allocates a range list
  440. --*/
  441. {
  442. PSUPPORTED_RANGES RangeList;
  443. ULONG i;
  444. PAGED_CODE();
  445. RangeList = (PSUPPORTED_RANGES) ExAllocatePoolWithTag (
  446. SPRANGEPOOL,
  447. sizeof (SUPPORTED_RANGES),
  448. HAL_POOL_TAG
  449. );
  450. RtlZeroMemory (RangeList, sizeof (SUPPORTED_RANGES));
  451. RangeList->Version = BUS_SUPPORTED_RANGE_VERSION;
  452. for (i=0; HalpRangeList[i].Offset; i++) {
  453. // Limit set to zero, set initial base to 1
  454. RANGE_LIST(RangeList, i)->Base = 1;
  455. }
  456. return RangeList;
  457. }
  458. VOID
  459. HalpFreeRangeList (
  460. PSUPPORTED_RANGES Ranges
  461. )
  462. /*++
  463. Routine Description:
  464. Frees a range list which was allocated via HalpAllocateNewRangeList, and
  465. extended / modified via the generic support functions.
  466. --*/
  467. {
  468. PSUPPORTED_RANGE Entry, NextEntry;
  469. ULONG i;
  470. PAGED_CODE();
  471. for (i=0; HalpRangeList[i].Offset; i++) {
  472. Entry = RANGE_LIST(Ranges, i)->Next;
  473. while (Entry) {
  474. NextEntry = Entry->Next;
  475. ExFreePool (Entry);
  476. Entry = NextEntry;
  477. }
  478. }
  479. ExFreePool (Ranges);
  480. }
  481. #if DBG
  482. STATIC VOID
  483. HalpDisplayAddressRange (
  484. PSUPPORTED_RANGE Address,
  485. PUCHAR String
  486. )
  487. /*++
  488. Routine Description:
  489. Debugging code. Used only by HalpDisplayAllBusRanges
  490. --*/
  491. {
  492. ULONG i;
  493. i = 0;
  494. while (Address) {
  495. if (i == 0) {
  496. DbgPrint (String);
  497. i = 3;
  498. }
  499. i -= 1;
  500. DbgPrint (" %x:%08x - %x:%08x ",
  501. (ULONG) (Address->Base >> 32),
  502. (ULONG) (Address->Base),
  503. (ULONG) (Address->Limit >> 32),
  504. (ULONG) (Address->Limit)
  505. );
  506. Address = Address->Next;
  507. }
  508. }
  509. VOID
  510. HalpDisplayAllBusRanges (
  511. VOID
  512. )
  513. /*++
  514. Routine Description:
  515. Debugging code. Displays the current supported range information
  516. for all the registered buses in the system.
  517. --*/
  518. {
  519. PSUPPORTED_RANGES Addresses;
  520. PBUS_HANDLER Bus;
  521. PUCHAR p;
  522. ULONG i, j;
  523. DbgPrint ("\nHAL - dumping all supported bus ranges");
  524. for (i=0; i < MaximumInterfaceType; i++) {
  525. for (j=0; Bus = HaliHandlerForBus (i, j); j++) {
  526. Addresses = Bus->BusAddresses;
  527. if (Addresses) {
  528. p = NULL;
  529. switch (Bus->InterfaceType) {
  530. case Internal: p = "Internal"; break;
  531. case Isa: p = "Isa"; break;
  532. case Eisa: p = "Eisa"; break;
  533. case PCIBus: p = "PCI"; break;
  534. }
  535. if (p) {
  536. DbgPrint ("\n%s %d", p, Bus->BusNumber);
  537. } else {
  538. DbgPrint ("\nBus-%d %d", Bus->InterfaceType, Bus->BusNumber);
  539. }
  540. HalpDisplayAddressRange (&Addresses->IO, "\n IO......:");
  541. HalpDisplayAddressRange (&Addresses->Memory, "\n Memory..:");
  542. HalpDisplayAddressRange (&Addresses->PrefetchMemory,"\n PFMemory:");
  543. HalpDisplayAddressRange (&Addresses->Dma, "\n Dma.....:");
  544. DbgPrint ("\n");
  545. }
  546. }
  547. }
  548. }
  549. #endif
  550. NTSTATUS
  551. HaliAdjustResourceListRange (
  552. IN PSUPPORTED_RANGES SRanges,
  553. IN PSUPPORTED_RANGE InterruptRange,
  554. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
  555. )
  556. /*++
  557. Routine Description:
  558. This functions takes an IO_RESOURCE_REQUIREMENT_LIST and
  559. adjusts it such that all ranges in the list fit in the
  560. ranges specified by SRanges & InterruptRange.
  561. This function is used by some HALs to clip the possible
  562. settings to be contained on what the particular bus supports
  563. in reponse to a HalAdjustResourceList call.
  564. Arguments:
  565. SRanges - Valid IO, Memory, Prefetch Memory, and DMA ranges.
  566. InterruptRange - Valid InterruptRanges
  567. pResourceList - The resource requirements list which needs to
  568. be adjusted to only contain the ranges as
  569. described by SRanges & InterruptRange.
  570. Return Value:
  571. STATUS_SUCCESS or an appropiate error return.
  572. --*/
  573. {
  574. PIO_RESOURCE_REQUIREMENTS_LIST InCompleteList, OutCompleteList;
  575. PIO_RESOURCE_LIST InResourceList, OutResourceList;
  576. PIO_RESOURCE_DESCRIPTOR HeadOutDesc, SetDesc;
  577. NRPARAMS Pos;
  578. ULONG len, alt, cnt, i;
  579. ULONG icnt;
  580. PAGED_CODE();
  581. //
  582. // Sanity check
  583. //
  584. if (!SRanges || SRanges->Version != BUS_SUPPORTED_RANGE_VERSION) {
  585. return STATUS_INVALID_PARAMETER;
  586. }
  587. //
  588. // If SupportedRanges aren't sorted, sort them and get the
  589. // number of ranges for each type
  590. //
  591. if (!SRanges->Sorted) {
  592. SRanges->NoIO = HalpSortRanges (&SRanges->IO);
  593. SRanges->NoMemory = HalpSortRanges (&SRanges->Memory);
  594. SRanges->NoPrefetchMemory = HalpSortRanges (&SRanges->PrefetchMemory);
  595. SRanges->NoDma = HalpSortRanges (&SRanges->Dma);
  596. SRanges->Sorted = TRUE;
  597. }
  598. icnt = HalpSortRanges (InterruptRange);
  599. InCompleteList = *pResourceList;
  600. len = InCompleteList->ListSize;
  601. //
  602. // Scan input list - verify revision #'s, and increase len varible
  603. // by amount output list may increase.
  604. //
  605. i = 1;
  606. InResourceList = InCompleteList->List;
  607. for (alt=0; alt < InCompleteList->AlternativeLists; alt++) {
  608. if (InResourceList->Version != 1 || InResourceList->Revision < 1) {
  609. return STATUS_INVALID_PARAMETER;
  610. }
  611. Pos.InDesc = InResourceList->Descriptors;
  612. for (cnt = InResourceList->Count; cnt; cnt--) {
  613. switch (Pos.InDesc->Type) {
  614. case CmResourceTypeInterrupt: i += icnt; break;
  615. case CmResourceTypePort: i += SRanges->NoIO; break;
  616. case CmResourceTypeDma: i += SRanges->NoDma; break;
  617. case CmResourceTypeMemory:
  618. i += SRanges->NoMemory;
  619. if (Pos.InDesc->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) {
  620. i += SRanges->NoPrefetchMemory;
  621. }
  622. break;
  623. default:
  624. return STATUS_INVALID_PARAMETER;
  625. }
  626. // take one off for the original which is already accounted for in 'len'
  627. i -= 1;
  628. // Next descriptor
  629. Pos.InDesc++;
  630. }
  631. // Next Resource List
  632. InResourceList = (PIO_RESOURCE_LIST) Pos.InDesc;
  633. }
  634. len += i * sizeof (IO_RESOURCE_DESCRIPTOR);
  635. //
  636. // Allocate output list
  637. //
  638. OutCompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST)
  639. ExAllocatePoolWithTag (PagedPool,
  640. len,
  641. ' laH');
  642. if (!OutCompleteList) {
  643. return STATUS_INSUFFICIENT_RESOURCES;
  644. }
  645. RtlZeroMemory (OutCompleteList, len);
  646. //
  647. // Walk each ResourceList and build output structure
  648. //
  649. InResourceList = InCompleteList->List;
  650. *OutCompleteList = *InCompleteList;
  651. OutResourceList = OutCompleteList->List;
  652. for (alt=0; alt < InCompleteList->AlternativeLists; alt++) {
  653. OutResourceList->Version = 1;
  654. OutResourceList->Revision = 1;
  655. Pos.InDesc = InResourceList->Descriptors;
  656. Pos.OutDesc = OutResourceList->Descriptors;
  657. HeadOutDesc = Pos.OutDesc;
  658. for (cnt = InResourceList->Count; cnt; cnt--) {
  659. //
  660. // Limit desctiptor to be with the buses supported ranges
  661. //
  662. Pos.DescOpt = Pos.InDesc->Option;
  663. Pos.AnotherListPending = FALSE;
  664. switch (Pos.InDesc->Type) {
  665. case CmResourceTypePort:
  666. //
  667. // Get supported IO ranges
  668. //
  669. Pos.CurrentPosition = &SRanges->IO;
  670. do {
  671. SetDesc = HalpGetNextSupportedRange (
  672. Pos.InDesc->u.Port.MinimumAddress.QuadPart,
  673. Pos.InDesc->u.Port.MaximumAddress.QuadPart,
  674. &Pos
  675. );
  676. if (SetDesc) {
  677. SetDesc->u.Port.MinimumAddress.QuadPart = Pos.Base;
  678. SetDesc->u.Port.MaximumAddress.QuadPart = Pos.Limit;
  679. }
  680. } while (SetDesc) ;
  681. break;
  682. case CmResourceTypeInterrupt:
  683. //
  684. // Get supported Interrupt ranges
  685. //
  686. Pos.CurrentPosition = InterruptRange;
  687. do {
  688. SetDesc = HalpGetNextSupportedRange (
  689. Pos.InDesc->u.Interrupt.MinimumVector,
  690. Pos.InDesc->u.Interrupt.MaximumVector,
  691. &Pos
  692. );
  693. if (SetDesc) {
  694. SetDesc->u.Interrupt.MinimumVector = (ULONG) Pos.Base;
  695. SetDesc->u.Interrupt.MaximumVector = (ULONG) Pos.Limit;
  696. }
  697. } while (SetDesc) ;
  698. break;
  699. case CmResourceTypeMemory:
  700. //
  701. // Get supported memory ranges
  702. //
  703. if (Pos.InDesc->Flags & CM_RESOURCE_MEMORY_PREFETCHABLE) {
  704. //
  705. // This is a Prefetchable range.
  706. // First add in any supported prefetchable ranges, then
  707. // add in any regualer supported ranges
  708. //
  709. Pos.AnotherListPending = TRUE;
  710. Pos.CurrentPosition = &SRanges->PrefetchMemory;
  711. do {
  712. SetDesc = HalpGetNextSupportedRange (
  713. Pos.InDesc->u.Memory.MinimumAddress.QuadPart,
  714. Pos.InDesc->u.Memory.MaximumAddress.QuadPart,
  715. &Pos
  716. );
  717. if (SetDesc) {
  718. SetDesc->u.Memory.MinimumAddress.QuadPart = Pos.Base;
  719. SetDesc->u.Memory.MaximumAddress.QuadPart = Pos.Limit;
  720. SetDesc->Option |= IO_RESOURCE_PREFERRED;
  721. }
  722. } while (SetDesc) ;
  723. Pos.AnotherListPending = FALSE;
  724. }
  725. //
  726. // Add in supported bus memory ranges
  727. //
  728. Pos.CurrentPosition = &SRanges->Memory;
  729. do {
  730. SetDesc = HalpGetNextSupportedRange (
  731. Pos.InDesc->u.Memory.MinimumAddress.QuadPart,
  732. Pos.InDesc->u.Memory.MaximumAddress.QuadPart,
  733. &Pos
  734. );
  735. if (SetDesc) {
  736. SetDesc->u.Memory.MinimumAddress.QuadPart = Pos.Base;
  737. SetDesc->u.Memory.MaximumAddress.QuadPart = Pos.Limit;
  738. }
  739. } while (SetDesc);
  740. break;
  741. case CmResourceTypeDma:
  742. //
  743. // Get supported DMA ranges
  744. //
  745. Pos.CurrentPosition = &SRanges->Dma;
  746. do {
  747. SetDesc = HalpGetNextSupportedRange (
  748. Pos.InDesc->u.Dma.MinimumChannel,
  749. Pos.InDesc->u.Dma.MaximumChannel,
  750. &Pos
  751. );
  752. if (SetDesc) {
  753. SetDesc->u.Dma.MinimumChannel = (ULONG) Pos.Base;
  754. SetDesc->u.Dma.MaximumChannel = (ULONG) Pos.Limit;
  755. }
  756. } while (SetDesc) ;
  757. break;
  758. #if DBG
  759. default:
  760. DbgPrint ("HalAdjustResourceList: Unkown resource type\n");
  761. break;
  762. #endif
  763. }
  764. //
  765. // Next descriptor
  766. //
  767. Pos.InDesc++;
  768. }
  769. OutResourceList->Count = (ULONG)(Pos.OutDesc - HeadOutDesc);
  770. //
  771. // Next Resource List
  772. //
  773. InResourceList = (PIO_RESOURCE_LIST) Pos.InDesc;
  774. OutResourceList = (PIO_RESOURCE_LIST) Pos.OutDesc;
  775. }
  776. //
  777. // Free input list, and return output list
  778. //
  779. ExFreePool (InCompleteList);
  780. OutCompleteList->ListSize = (ULONG) ((PUCHAR) OutResourceList - (PUCHAR) OutCompleteList);
  781. *pResourceList = OutCompleteList;
  782. return STATUS_SUCCESS;
  783. }
  784. STATIC PIO_RESOURCE_DESCRIPTOR
  785. HalpGetNextSupportedRange (
  786. IN LONGLONG MinimumAddress,
  787. IN LONGLONG MaximumAddress,
  788. IN OUT PNRPARAMS Pos
  789. )
  790. /*++
  791. Routine Description:
  792. Support function for HaliAdjustResourceListRange.
  793. Returns the next supported range in the area passed in.
  794. Arguments:
  795. MinimumAddress
  796. MaximumAddress - Min & Max address of a range which needs
  797. to be clipped to match that of the supported
  798. ranges of the current bus.
  799. Pos - describes the current postion
  800. Return Value:
  801. NULL is no more returned ranges
  802. Otherwise, the IO_RESOURCE_DESCRIPTOR which needs to be set
  803. with the matching range returned in Pos.
  804. --*/
  805. {
  806. LONGLONG Base, Limit;
  807. //
  808. // Find next range which is supported
  809. //
  810. Base = MinimumAddress;
  811. Limit = MaximumAddress;
  812. while (Pos->CurrentPosition) {
  813. Pos->Base = Base;
  814. Pos->Limit = Limit;
  815. //
  816. // Clip to current range
  817. //
  818. if (Pos->Base < Pos->CurrentPosition->Base) {
  819. Pos->Base = Pos->CurrentPosition->Base;
  820. }
  821. if (Pos->Limit > Pos->CurrentPosition->Limit) {
  822. Pos->Limit = Pos->CurrentPosition->Limit;
  823. }
  824. //
  825. // set position to next range
  826. //
  827. Pos->CurrentPosition = Pos->CurrentPosition->Next;
  828. //
  829. // If valid range, return it
  830. //
  831. if (Pos->Base <= Pos->Limit) {
  832. *Pos->OutDesc = *Pos->InDesc;
  833. Pos->OutDesc->Option = Pos->DescOpt;
  834. //
  835. // next descriptor (if any) is an alternative
  836. // to the descriptor being returned now
  837. //
  838. Pos->OutDesc += 1;
  839. Pos->DescOpt |= IO_RESOURCE_ALTERNATIVE;
  840. return Pos->OutDesc - 1;
  841. }
  842. }
  843. //
  844. // There's no overlapping range. If this descriptor is
  845. // not an alternative and this descriptor is not going to
  846. // be processed by another range list, then return
  847. // a descriptor which can't be satisified.
  848. //
  849. if (!(Pos->DescOpt & IO_RESOURCE_ALTERNATIVE) &&
  850. Pos->AnotherListPending == FALSE) {
  851. #if DBG
  852. DbgPrint ("HAL: returning impossible range\n");
  853. #endif
  854. Pos->Base = MinimumAddress;
  855. Pos->Limit = Pos->Base - 1;
  856. if (Pos->Base == 0) { // if wrapped, fix it
  857. Pos->Base = 1;
  858. Pos->Limit = 0;
  859. }
  860. *Pos->OutDesc = *Pos->InDesc;
  861. Pos->OutDesc->Option = Pos->DescOpt;
  862. Pos->OutDesc += 1;
  863. Pos->DescOpt |= IO_RESOURCE_ALTERNATIVE;
  864. return Pos->OutDesc - 1;
  865. }
  866. //
  867. // No range found (or no more ranges)
  868. //
  869. return NULL;
  870. }
  871. STATIC ULONG
  872. HalpSortRanges (
  873. IN PSUPPORTED_RANGE RangeList
  874. )
  875. /*++
  876. Routine Description:
  877. Support function for HaliAdjustResourceListRange.
  878. Sorts a supported range list into decending order.
  879. Arguments:
  880. pRange - List to sort
  881. Return Value:
  882. --*/
  883. {
  884. ULONG cnt;
  885. LONGLONG hldBase, hldLimit, hldSystemBase;
  886. PSUPPORTED_RANGE Range1, Range2;
  887. PAGED_CODE();
  888. //
  889. // Sort it
  890. //
  891. for (Range1 = RangeList; Range1; Range1 = Range1->Next) {
  892. for (Range2 = Range1->Next; Range2; Range2 = Range2->Next) {
  893. if (Range2->Base > Range1->Base) {
  894. hldBase = Range1->Base;
  895. hldLimit = Range1->Limit;
  896. hldSystemBase = Range1->SystemBase;
  897. Range1->Base = Range2->Base;
  898. Range1->Limit = Range2->Limit;
  899. Range1->SystemBase = Range2->SystemBase;
  900. Range2->Base = hldBase;
  901. Range2->Limit = hldLimit;
  902. Range2->SystemBase = hldSystemBase;
  903. }
  904. }
  905. }
  906. //
  907. // Count the number of ranges
  908. //
  909. cnt = 0;
  910. for (Range1 = RangeList; Range1; Range1 = Range1->Next) {
  911. cnt += 1;
  912. }
  913. return cnt;
  914. }