Windows NT 4.0 source code leak
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.

1144 lines
30 KiB

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