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.

2355 lines
62 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. rangesup.c
  5. Abstract:
  6. This handles the subtraction of a set of CmResList from an IoResList
  7. IoResList
  8. Author:
  9. Stephane Plante (splante)
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. Aug-05-97 - Initial Revision
  14. --*/
  15. #include "pch.h"
  16. NTSTATUS
  17. ACPIRangeAdd(
  18. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *GlobalList,
  19. IN PIO_RESOURCE_REQUIREMENTS_LIST AddList
  20. )
  21. /*++
  22. Routine Description:
  23. This routine is called to add an Io List to another. This is not a
  24. straightforward operation
  25. Arguments:
  26. IoList - The list that contains both lists
  27. AddList - The list what will be added to the other. We are desctructive
  28. to this list
  29. Return Value:
  30. NTSTATUS:
  31. --*/
  32. {
  33. BOOLEAN proceed;
  34. NTSTATUS status;
  35. PIO_RESOURCE_DESCRIPTOR addDesc;
  36. PIO_RESOURCE_DESCRIPTOR newDesc;
  37. PIO_RESOURCE_LIST addList;
  38. PIO_RESOURCE_LIST globalList;
  39. PIO_RESOURCE_LIST newList;
  40. PIO_RESOURCE_REQUIREMENTS_LIST globalResList;
  41. PIO_RESOURCE_REQUIREMENTS_LIST newResList;
  42. ULONG addCount = 0;
  43. ULONG addIndex = 0;
  44. ULONG ioCount = 0;
  45. ULONG ioIndex = 0;
  46. ULONG maxSize = 0;
  47. ULONG size = 0;
  48. if (GlobalList == NULL) {
  49. return STATUS_INVALID_PARAMETER_1;
  50. }
  51. globalResList = *GlobalList;
  52. //
  53. // Make sure that we have a list to add
  54. //
  55. if (AddList == NULL || AddList->AlternativeLists == 0) {
  56. return STATUS_SUCCESS;
  57. }
  58. //
  59. // Figure out how much space we need in the
  60. //
  61. addList = &(AddList->List[0]);
  62. maxSize = addCount = addList->Count;
  63. ACPIRangeSortIoList( addList );
  64. //
  65. // Worst case is that the new list is as big as both lists combined
  66. //
  67. size = AddList->ListSize;
  68. //
  69. // Do we have a global list to add to?
  70. //
  71. if (globalResList == NULL || globalResList->AlternativeLists == 0) {
  72. //
  73. // No? Then just copy the old list
  74. //
  75. newResList = ExAllocatePoolWithTag(
  76. NonPagedPool,
  77. size,
  78. ACPI_RESOURCE_POOLTAG
  79. );
  80. if (newResList == NULL) {
  81. return STATUS_INSUFFICIENT_RESOURCES;
  82. }
  83. RtlCopyMemory(
  84. newResList,
  85. AddList,
  86. size
  87. );
  88. } else {
  89. //
  90. // Yes, so calculate how much space the first one will take
  91. //
  92. globalList = &(globalResList->List[0]);
  93. ioCount = globalList->Count;
  94. maxSize += ioCount;
  95. size += (ioCount * sizeof(IO_RESOURCE_DESCRIPTOR) );
  96. //
  97. // Allocate the list
  98. //
  99. newResList = ExAllocatePoolWithTag(
  100. NonPagedPool,
  101. size,
  102. ACPI_RESOURCE_POOLTAG
  103. );
  104. if (newResList == NULL) {
  105. return STATUS_INSUFFICIENT_RESOURCES;
  106. }
  107. //
  108. // Copy both lists into the new one
  109. //
  110. RtlZeroMemory( newResList, size );
  111. RtlCopyMemory(
  112. newResList,
  113. AddList,
  114. AddList->ListSize
  115. );
  116. RtlCopyMemory(
  117. &(newResList->List[0].Descriptors[addCount]),
  118. globalList->Descriptors,
  119. (ioCount * sizeof(IO_RESOURCE_DESCRIPTOR) )
  120. );
  121. //
  122. // We no longer need this list
  123. //
  124. ExFreePool( *GlobalList );
  125. }
  126. //
  127. // Make sure that we update the list count
  128. //
  129. newResList->ListSize = size;
  130. newList = &(newResList->List[0]);
  131. newList->Count = ioCount = addCount = maxSize;
  132. //
  133. // Sort the new list
  134. //
  135. status = ACPIRangeSortIoList( newList );
  136. if (!NT_SUCCESS(status)) {
  137. //
  138. // We failed, so exit now
  139. //
  140. ExFreePool( newResList );
  141. return status;
  142. }
  143. //
  144. // Add all the resource we can together
  145. //
  146. for (ioIndex = 0; ioIndex < maxSize; ioIndex++) {
  147. //
  148. // First step is to copy the current desc from the master list to
  149. // the new list
  150. //
  151. newDesc = &(newList->Descriptors[ioIndex]);
  152. //
  153. // Is it interesting?
  154. //
  155. if (newDesc->Type == CmResourceTypeNull) {
  156. //
  157. // No
  158. //
  159. continue;
  160. }
  161. //
  162. // Do we care about it?
  163. //
  164. if (newDesc->Type != CmResourceTypeMemory &&
  165. newDesc->Type != CmResourceTypePort &&
  166. newDesc->Type != CmResourceTypeDma &&
  167. newDesc->Type != CmResourceTypeInterrupt) {
  168. //
  169. // We do not care
  170. //
  171. newDesc->Type = CmResourceTypeNull;
  172. ioCount--;
  173. continue;
  174. }
  175. //
  176. // Try to get as far as possible
  177. //
  178. proceed = TRUE;
  179. //
  180. // Now we try to find any lists that we can merge in that location
  181. //
  182. for (addIndex = ioIndex + 1; addIndex < maxSize; addIndex++) {
  183. addDesc = &(newList->Descriptors[addIndex]);
  184. //
  185. // If they are not the same type, then next
  186. //
  187. if (newDesc->Type != addDesc->Type) {
  188. continue;
  189. }
  190. //
  191. // What we do next is dependent on the type
  192. //
  193. switch (newDesc->Type) {
  194. case CmResourceTypePort:
  195. case CmResourceTypeMemory:
  196. //
  197. // Does the new descriptor lie entirely before the add
  198. // descriptor?
  199. //
  200. if (addDesc->u.Port.MinimumAddress.QuadPart >
  201. newDesc->u.Port.MaximumAddress.QuadPart + 1) {
  202. //
  203. // Then we are done with this newDesc
  204. //
  205. proceed = FALSE;
  206. break;
  207. }
  208. //
  209. // does part of the current new descriptor lie in part
  210. // of the add one?
  211. //
  212. if (newDesc->u.Port.MaximumAddress.QuadPart <=
  213. addDesc->u.Port.MaximumAddress.QuadPart) {
  214. //
  215. // Update the current new descriptor to refect the
  216. // correct range and length
  217. //
  218. newDesc->u.Port.MaximumAddress.QuadPart =
  219. addDesc->u.Port.MaximumAddress.QuadPart;
  220. newDesc->u.Port.Length = (ULONG)
  221. (newDesc->u.Port.MaximumAddress.QuadPart -
  222. newDesc->u.Port.MinimumAddress.QuadPart + 1);
  223. newDesc->u.Port.Alignment = 1;
  224. }
  225. //
  226. // Nuke the add descriptor since it has been swallowed up
  227. //
  228. ioCount--;
  229. addDesc->Type = CmResourceTypeNull;
  230. break;
  231. case CmResourceTypeDma:
  232. case CmResourceTypeInterrupt:
  233. //
  234. // Does the current new descriptor lie entirely before the
  235. // one we are looking at now?
  236. //
  237. if (addDesc->u.Dma.MinimumChannel >
  238. newDesc->u.Dma.MaximumChannel + 1) {
  239. proceed = FALSE;
  240. break;
  241. }
  242. //
  243. // does part of the current new descriptor lie in part
  244. // of the add one?
  245. //
  246. if (newDesc->u.Dma.MaximumChannel <=
  247. addDesc->u.Dma.MaximumChannel ) {
  248. //
  249. // Update the current new descriptor to reflect the
  250. // correct range
  251. //
  252. newDesc->u.Dma.MaximumChannel =
  253. addDesc->u.Dma.MaximumChannel;
  254. }
  255. //
  256. // Nuke the add descriptor since it has been swallowed up
  257. //
  258. ioCount--;
  259. addDesc->Type = CmResourceTypeNull;
  260. break;
  261. } // switch
  262. //
  263. // Do we need to stop?
  264. //
  265. if (proceed == FALSE) {
  266. break;
  267. }
  268. }
  269. } // for
  270. //
  271. // Do we have any items left that we care about?
  272. //
  273. if (ioCount == 0) {
  274. //
  275. // No then free everything and return an empty list
  276. //
  277. ExFreePool( newResList );
  278. return STATUS_SUCCESS;
  279. }
  280. //
  281. // Now we can build the proper list. See how many items we must allocate
  282. //
  283. size = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) + (ioCount - 1) *
  284. sizeof(IO_RESOURCE_DESCRIPTOR);
  285. globalResList = ExAllocatePoolWithTag(
  286. NonPagedPool,
  287. size,
  288. ACPI_RESOURCE_POOLTAG
  289. );
  290. if (globalResList == NULL) {
  291. ExFreePool( newResList );
  292. return STATUS_INSUFFICIENT_RESOURCES;
  293. }
  294. //
  295. // Initialize the new list by copying the header from the working list
  296. //
  297. RtlZeroMemory( globalResList, size );
  298. RtlCopyMemory(
  299. globalResList,
  300. newResList,
  301. sizeof(IO_RESOURCE_REQUIREMENTS_LIST)
  302. );
  303. globalResList->ListSize = size;
  304. globalList = &(globalResList->List[0]);
  305. globalList->Count = ioCount;
  306. //
  307. // Copy all of the valid items into this new list
  308. //
  309. for (addIndex = 0, ioIndex = 0;
  310. ioIndex < ioCount && addIndex < maxSize;
  311. addIndex++) {
  312. addDesc = &(newList->Descriptors[addIndex]);
  313. //
  314. // If the type is null, skip it
  315. //
  316. if (addDesc->Type == CmResourceTypeNull) {
  317. continue;
  318. }
  319. //
  320. // Copy the new list
  321. //
  322. RtlCopyMemory(
  323. &(globalList->Descriptors[ioIndex]),
  324. addDesc,
  325. sizeof(IO_RESOURCE_DESCRIPTOR)
  326. );
  327. ioIndex++;
  328. }
  329. //
  330. // Free the old list
  331. //
  332. ExFreePool( newResList );
  333. //
  334. // Point the global to the new list
  335. //
  336. *GlobalList = globalResList;
  337. //
  338. // Done
  339. //
  340. return STATUS_SUCCESS;
  341. }
  342. NTSTATUS
  343. ACPIRangeAddCmList(
  344. IN OUT PCM_RESOURCE_LIST *GlobalList,
  345. IN PCM_RESOURCE_LIST AddList
  346. )
  347. /*++
  348. Routine Description:
  349. This routine is called to add an Cm List to another. This is not a
  350. straightforward operation
  351. Arguments:
  352. CmList - The list that contains both lists
  353. AddList - The list what will be added to the other. We are desctructive
  354. to this list
  355. Return Value:
  356. NTSTATUS:
  357. --*/
  358. {
  359. BOOLEAN proceed;
  360. NTSTATUS status;
  361. PCM_PARTIAL_RESOURCE_DESCRIPTOR addDesc;
  362. PCM_PARTIAL_RESOURCE_DESCRIPTOR newDesc;
  363. PCM_PARTIAL_RESOURCE_LIST addPartialList;
  364. PCM_PARTIAL_RESOURCE_LIST cmPartialList;
  365. PCM_PARTIAL_RESOURCE_LIST newPartialList;
  366. PCM_RESOURCE_LIST globalList;
  367. PCM_RESOURCE_LIST newList;
  368. ULONG addCount = 0;
  369. ULONG addIndex = 0;
  370. ULONG cmCount = 0;
  371. ULONG cmIndex = 0;
  372. ULONG maxSize = 0;
  373. ULONG size = 0;
  374. ULONGLONG maxAddr1;
  375. ULONGLONG maxAddr2;
  376. if (GlobalList == NULL) {
  377. return STATUS_INVALID_PARAMETER_1;
  378. }
  379. globalList = *GlobalList;
  380. //
  381. // Make sure that we have a list to add
  382. //
  383. if (AddList == NULL || AddList->Count == 0) {
  384. return STATUS_SUCCESS;
  385. }
  386. addPartialList = &(AddList->List[0].PartialResourceList);
  387. addCount = addPartialList->Count;
  388. //
  389. // If we have no global list, then we just copy over the other one
  390. //
  391. if (globalList == NULL || globalList->Count == 0) {
  392. //
  393. // Just copy over the original list
  394. //
  395. size = sizeof(CM_RESOURCE_LIST) + (addCount - 1) *
  396. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  397. maxSize = addCount;
  398. newList = ExAllocatePoolWithTag(
  399. NonPagedPool,
  400. size,
  401. ACPI_RESOURCE_POOLTAG
  402. );
  403. if (newList == NULL) {
  404. return STATUS_INSUFFICIENT_RESOURCES;
  405. }
  406. RtlCopyMemory(
  407. newList,
  408. AddList,
  409. size
  410. );
  411. } else {
  412. cmPartialList = &( globalList->List[0].PartialResourceList);
  413. cmCount = cmPartialList->Count;
  414. maxSize = addCount + cmCount;
  415. //
  416. // Allocate space for both lists
  417. //
  418. size = sizeof(CM_RESOURCE_LIST) + (maxSize - 1) *
  419. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  420. newList = ExAllocatePoolWithTag(
  421. NonPagedPool,
  422. size,
  423. ACPI_RESOURCE_POOLTAG
  424. );
  425. if (newList == NULL) {
  426. return STATUS_INSUFFICIENT_RESOURCES;
  427. }
  428. //
  429. // Merge both sets of descriptors into one list
  430. //
  431. RtlZeroMemory( newList, size );
  432. RtlCopyMemory(
  433. newList,
  434. AddList,
  435. size - (cmCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))
  436. );
  437. RtlCopyMemory(
  438. ( (PUCHAR) newList) +
  439. (size - (cmCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR ) ) ),
  440. &(cmPartialList->PartialDescriptors[0]),
  441. cmCount * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  442. );
  443. //
  444. // Make sure to preserver the version id from the global list
  445. //
  446. newList->List->PartialResourceList.Version =
  447. globalList->List->PartialResourceList.Version;
  448. newList->List->PartialResourceList.Revision =
  449. globalList->List->PartialResourceList.Revision;
  450. ExFreePool( globalList );
  451. }
  452. //
  453. // Obtain a pointer to the descriptors of the new list, and update the
  454. // number of descriptors in the list
  455. //
  456. newPartialList = &(newList->List[0].PartialResourceList);
  457. newPartialList->Count = cmCount = addCount = maxSize;
  458. //
  459. // Make sure to sort the combined list
  460. //
  461. status = ACPIRangeSortCmList( newList );
  462. if (!NT_SUCCESS(status)) {
  463. ExFreePool( newList );
  464. return status;
  465. }
  466. //
  467. // Add all the resource we can together
  468. //
  469. for (cmIndex = 0; cmIndex < maxSize; cmIndex++) {
  470. //
  471. // Grab a pointer to the current descriptor
  472. //
  473. newDesc = &(newPartialList->PartialDescriptors[cmIndex]);
  474. //
  475. // Is it interesting?
  476. //
  477. if (newDesc->Type == CmResourceTypeNull) {
  478. //
  479. // No
  480. //
  481. continue;
  482. }
  483. //
  484. // Do we care about it?
  485. //
  486. if (newDesc->Type != CmResourceTypeMemory &&
  487. newDesc->Type != CmResourceTypePort &&
  488. newDesc->Type != CmResourceTypeDma &&
  489. newDesc->Type != CmResourceTypeInterrupt) {
  490. //
  491. // We do not care
  492. //
  493. newDesc->Type = CmResourceTypeNull;
  494. cmCount--;
  495. continue;
  496. }
  497. //
  498. // Try to get as far as possible
  499. //
  500. proceed = TRUE;
  501. //
  502. // Try to merge the following items
  503. //
  504. for (addIndex = cmIndex + 1; addIndex < maxSize; addIndex++) {
  505. addDesc = &(newPartialList->PartialDescriptors[addIndex]);
  506. //
  507. // If they are not the same type, then we are done here
  508. //
  509. if (newDesc->Type != addDesc->Type) {
  510. continue;
  511. }
  512. switch (newDesc->Type) {
  513. case CmResourceTypePort:
  514. case CmResourceTypeMemory:
  515. //
  516. // Obtain the max addresses
  517. //
  518. maxAddr1 = newDesc->u.Port.Start.QuadPart +
  519. newDesc->u.Port.Length;
  520. maxAddr2 = addDesc->u.Port.Start.QuadPart +
  521. addDesc->u.Port.Length;
  522. //
  523. // does the current new descriptor lie entirely before the
  524. // add one?
  525. //
  526. if (maxAddr1 < (ULONGLONG) addDesc->u.Port.Start.QuadPart ) {
  527. //
  528. // Yes, so we are done with this newDesc;
  529. //
  530. proceed = FALSE;
  531. break;
  532. }
  533. //
  534. // does part of the current new descriptor lie in part of the
  535. // add one?
  536. //
  537. if (maxAddr1 <= maxAddr2) {
  538. //
  539. // Update the current new descriptor to reflect the
  540. // correct length
  541. //
  542. newDesc->u.Port.Length = (ULONG) (maxAddr2 -
  543. newDesc->u.Port.Start.QuadPart);
  544. }
  545. //
  546. // Nuke the add descriptor since it has been swallowed up
  547. //
  548. cmCount--;
  549. addDesc->Type = CmResourceTypeNull;
  550. break;
  551. case CmResourceTypeDma:
  552. //
  553. // Do the resource match?
  554. //
  555. if (addDesc->u.Dma.Channel != newDesc->u.Dma.Channel) {
  556. //
  557. // No, then stop
  558. //
  559. proceed = FALSE;
  560. break;
  561. }
  562. //
  563. // We can ignore the duplicate copy
  564. //
  565. addDesc->Type = CmResourceTypeNull;
  566. cmCount--;
  567. break;
  568. case CmResourceTypeInterrupt:
  569. //
  570. // Do the resource match?
  571. //
  572. if (addDesc->u.Interrupt.Vector !=
  573. newDesc->u.Interrupt.Vector) {
  574. //
  575. // No, then stop
  576. //
  577. proceed = FALSE;
  578. break;
  579. }
  580. //
  581. // We can ignore the duplicate copy
  582. //
  583. addDesc->Type = CmResourceTypeNull;
  584. cmCount--;
  585. break;
  586. } // switch
  587. //
  588. // Do we have to stop?
  589. //
  590. if (proceed == FALSE) {
  591. break;
  592. }
  593. } // for
  594. } // for
  595. //
  596. // Do we have any items that we care about left?
  597. //
  598. if (cmCount == 0) {
  599. //
  600. // No, then free everything and return an empty list
  601. //
  602. ExFreePool( newList );
  603. return STATUS_SUCCESS;
  604. }
  605. //
  606. // Now we can build the proper list. See how many items we must
  607. // allocate
  608. //
  609. size = sizeof(CM_RESOURCE_LIST) + (cmCount - 1) *
  610. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  611. globalList = ExAllocatePoolWithTag(
  612. NonPagedPool,
  613. size,
  614. ACPI_RESOURCE_POOLTAG
  615. );
  616. if (globalList == NULL) {
  617. ExFreePool( newList );
  618. return STATUS_INSUFFICIENT_RESOURCES;
  619. }
  620. //
  621. // Initialize the list by copying the header from the AddList
  622. //
  623. RtlZeroMemory( globalList, size );
  624. RtlCopyMemory(
  625. globalList,
  626. AddList,
  627. sizeof(CM_RESOURCE_LIST)
  628. );
  629. cmPartialList = &(globalList->List[0].PartialResourceList);
  630. cmPartialList->Count = cmCount;
  631. //
  632. // Copy all of the valid resources into this new list
  633. //
  634. for (cmIndex = 0, addIndex = 0;
  635. cmIndex < maxSize && addIndex < cmCount;
  636. cmIndex++) {
  637. newDesc = &(newPartialList->PartialDescriptors[cmIndex]);
  638. //
  639. // If the type is null, skip it
  640. //
  641. if (newDesc->Type == CmResourceTypeNull) {
  642. continue;
  643. }
  644. //
  645. // Copy the new list
  646. //
  647. RtlCopyMemory(
  648. &(cmPartialList->PartialDescriptors[addIndex]),
  649. newDesc,
  650. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  651. );
  652. addIndex++;
  653. }
  654. //
  655. // Free the old lists
  656. //
  657. ExFreePool( newList );
  658. //
  659. // Point the global to the new list
  660. //
  661. *GlobalList = globalList;
  662. //
  663. // Done
  664. //
  665. return STATUS_SUCCESS;
  666. }
  667. NTSTATUS
  668. ACPIRangeFilterPICInterrupt(
  669. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResList
  670. )
  671. /*++
  672. Routine Description:
  673. This routine is called to remove Interrupt #2 from the list of
  674. resources that are returned by the PIC
  675. Arguments:
  676. IoResList - The IO Resource List to smash
  677. Return Value:
  678. NTSTATUS
  679. --*/
  680. {
  681. NTSTATUS status;
  682. PIO_RESOURCE_LIST ioList;
  683. ULONG i;
  684. ULONG j;
  685. ULONG size;
  686. //
  687. // Sanity checks
  688. //
  689. if (IoResList == NULL) {
  690. //
  691. // No work to do
  692. //
  693. return STATUS_SUCCESS;
  694. }
  695. //
  696. // Walk the resource requirements list
  697. //
  698. ioList = &(IoResList->List[0]);
  699. for (i = 0; i < IoResList->AlternativeLists; i++) {
  700. //
  701. // Walk the IO list
  702. //
  703. for (j = 0; j < ioList->Count; j++) {
  704. if (ioList->Descriptors[j].Type != CmResourceTypeInterrupt) {
  705. continue;
  706. }
  707. //
  708. // Do we have the case where the minimum starts on int 2?
  709. //
  710. if (ioList->Descriptors[j].u.Interrupt.MinimumVector == 2) {
  711. //
  712. // If the maximum is on 2, then we snuff out this
  713. // descriptors, otherwise, we change the minimum
  714. //
  715. if (ioList->Descriptors[j].u.Interrupt.MaximumVector == 2) {
  716. ioList->Descriptors[j].Type = CmResourceTypeNull;
  717. } else {
  718. ioList->Descriptors[j].u.Interrupt.MinimumVector++;
  719. }
  720. continue;
  721. }
  722. //
  723. // Do we have the case where the maximum ends on int 2?
  724. // Note that the minimum cannot be on 2...
  725. //
  726. if (ioList->Descriptors[j].u.Interrupt.MaximumVector == 2) {
  727. ioList->Descriptors[j].u.Interrupt.MaximumVector--;
  728. continue;
  729. }
  730. //
  731. // If INT2 is in the middle of the ranges, then prune them
  732. // one way or the other...
  733. //
  734. if (ioList->Descriptors[j].u.Interrupt.MinimumVector < 2 &&
  735. ioList->Descriptors[j].u.Interrupt.MaximumVector > 2) {
  736. ioList->Descriptors[j].u.Interrupt.MinimumVector = 3;
  737. }
  738. }
  739. //
  740. // Next list
  741. //
  742. size = sizeof(IO_RESOURCE_LIST) +
  743. ( (ioList->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
  744. ioList = (PIO_RESOURCE_LIST) ( ( (PUCHAR) ioList ) + size );
  745. }
  746. //
  747. // Done
  748. //
  749. return STATUS_SUCCESS;
  750. }
  751. NTSTATUS
  752. ACPIRangeSortCmList(
  753. IN PCM_RESOURCE_LIST CmResList
  754. )
  755. /*++
  756. Routine Description:
  757. This routine ensures that the elements of a CmResList are sorted in
  758. assending order (by type)
  759. Arguments:
  760. CmResList - The list to sort
  761. Return Value:
  762. NTSTATUS
  763. --*/
  764. {
  765. CM_PARTIAL_RESOURCE_DESCRIPTOR tempDesc;
  766. PCM_PARTIAL_RESOURCE_DESCRIPTOR curDesc;
  767. PCM_PARTIAL_RESOURCE_DESCRIPTOR subDesc;
  768. PCM_PARTIAL_RESOURCE_LIST cmList;
  769. ULONG cmIndex;
  770. ULONG cmSize;
  771. ULONG cmSubLoop;
  772. //
  773. // Setup the pointer to the cmList
  774. //
  775. cmList = &(CmResList->List[0].PartialResourceList);
  776. cmSize = cmList->Count;
  777. for (cmIndex = 0; cmIndex < cmSize; cmIndex++) {
  778. curDesc = &(cmList->PartialDescriptors[cmIndex]);
  779. for (cmSubLoop = cmIndex + 1; cmSubLoop < cmSize; cmSubLoop++) {
  780. subDesc = &(cmList->PartialDescriptors[cmSubLoop]);
  781. //
  782. // Is this a compatible descriptor?
  783. //
  784. if (curDesc->Type != subDesc->Type) {
  785. continue;
  786. }
  787. //
  788. // Test by type
  789. //
  790. if (curDesc->Type == CmResourceTypePort ||
  791. curDesc->Type == CmResourceTypeMemory) {
  792. if (subDesc->u.Port.Start.QuadPart <
  793. curDesc->u.Port.Start.QuadPart) {
  794. curDesc = subDesc;
  795. }
  796. } else if (curDesc->Type == CmResourceTypeInterrupt) {
  797. if (subDesc->u.Interrupt.Vector < curDesc->u.Interrupt.Vector) {
  798. curDesc = subDesc;
  799. }
  800. } else if (curDesc->Type == CmResourceTypeDma) {
  801. if (subDesc->u.Dma.Channel < curDesc->u.Dma.Channel) {
  802. curDesc = subDesc;
  803. }
  804. }
  805. }
  806. //
  807. // Did we find a smaller element?
  808. //
  809. if (curDesc == &(cmList->PartialDescriptors[cmIndex])) {
  810. continue;
  811. }
  812. //
  813. // We have found the smallest element. Swap them
  814. //
  815. RtlCopyMemory(
  816. &tempDesc,
  817. &(cmList->PartialDescriptors[cmIndex]),
  818. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  819. );
  820. RtlCopyMemory(
  821. &(cmList->PartialDescriptors[cmIndex]),
  822. curDesc,
  823. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  824. );
  825. RtlCopyMemory(
  826. curDesc,
  827. &tempDesc,
  828. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  829. );
  830. }
  831. //
  832. // Success
  833. //
  834. return STATUS_SUCCESS;
  835. }
  836. NTSTATUS
  837. ACPIRangeSortIoList(
  838. IN PIO_RESOURCE_LIST IoList
  839. )
  840. /*++
  841. Routine Description:
  842. This routine ensures that the elements of a CmResList are sorted in
  843. assending order (by type)
  844. Arguments:
  845. CmResList - The list to sort
  846. Return Value:
  847. NTSTATUS
  848. --*/
  849. {
  850. IO_RESOURCE_DESCRIPTOR tempDesc;
  851. PIO_RESOURCE_DESCRIPTOR curDesc;
  852. PIO_RESOURCE_DESCRIPTOR subDesc;
  853. ULONG ioIndex;
  854. ULONG ioSize;
  855. ULONG ioSubLoop;
  856. //
  857. // Count the number of element ioList
  858. //
  859. ioSize = IoList->Count;
  860. for (ioIndex = 0; ioIndex < ioSize; ioIndex++) {
  861. curDesc = &(IoList->Descriptors[ioIndex]);
  862. for (ioSubLoop = ioIndex + 1; ioSubLoop < ioSize; ioSubLoop++) {
  863. subDesc = &(IoList->Descriptors[ioSubLoop]);
  864. //
  865. // Is this a compatible descriptor?
  866. //
  867. if (curDesc->Type != subDesc->Type) {
  868. continue;
  869. }
  870. //
  871. // Test by type
  872. //
  873. if (curDesc->Type == CmResourceTypePort ||
  874. curDesc->Type == CmResourceTypeMemory) {
  875. if (subDesc->u.Port.MinimumAddress.QuadPart <
  876. curDesc->u.Port.MinimumAddress.QuadPart) {
  877. curDesc = subDesc;
  878. }
  879. } else if (curDesc->Type == CmResourceTypeInterrupt ||
  880. curDesc->Type == CmResourceTypeDma) {
  881. if (subDesc->u.Interrupt.MinimumVector <
  882. curDesc->u.Interrupt.MinimumVector) {
  883. curDesc = subDesc;
  884. }
  885. }
  886. }
  887. //
  888. // Did we find a smaller element?
  889. //
  890. if (curDesc == &(IoList->Descriptors[ioIndex])) {
  891. continue;
  892. }
  893. //
  894. // We have found the smallest element. Swap them
  895. //
  896. RtlCopyMemory(
  897. &tempDesc,
  898. &(IoList->Descriptors[ioIndex]),
  899. sizeof(IO_RESOURCE_DESCRIPTOR)
  900. );
  901. RtlCopyMemory(
  902. &(IoList->Descriptors[ioIndex]),
  903. curDesc,
  904. sizeof(IO_RESOURCE_DESCRIPTOR)
  905. );
  906. RtlCopyMemory(
  907. curDesc,
  908. &tempDesc,
  909. sizeof(IO_RESOURCE_DESCRIPTOR)
  910. );
  911. }
  912. //
  913. // Success
  914. //
  915. return STATUS_SUCCESS;
  916. }
  917. NTSTATUS
  918. ACPIRangeSubtract(
  919. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResReqList,
  920. IN PCM_RESOURCE_LIST CmResList
  921. )
  922. /*++
  923. Routine Description:
  924. This routine takes a IoResReqList, and subtracts the CmResList
  925. from each one of the IoResList, and returns the new list
  926. Arguments:
  927. IoResReqList The original list and where to store the new one
  928. CmResList What to subtract
  929. Return Value:
  930. NTSTATUS
  931. --*/
  932. {
  933. NTSTATUS status;
  934. PIO_RESOURCE_LIST curList;
  935. PIO_RESOURCE_LIST *resourceArray;
  936. PIO_RESOURCE_REQUIREMENTS_LIST newList;
  937. PUCHAR buffer;
  938. ULONG listIndex;
  939. ULONG listSize = (*IoResReqList)->AlternativeLists;
  940. ULONG newSize;
  941. ULONG size;
  942. //
  943. // Sort the CmResList
  944. //
  945. status = ACPIRangeSortCmList( CmResList );
  946. if (!NT_SUCCESS(status)) {
  947. ACPIPrint( (
  948. ACPI_PRINT_FAILURE,
  949. "ACPIRangeSubtract: AcpiRangeSortCmList 0x%08lx Failed 0x%08lx\n",
  950. CmResList,
  951. status
  952. ) );
  953. return status;
  954. }
  955. //
  956. // Allocate an array to hold all the alternatives
  957. //
  958. resourceArray = ExAllocatePoolWithTag(
  959. NonPagedPool,
  960. sizeof(PIO_RESOURCE_LIST) * listSize,
  961. ACPI_RESOURCE_POOLTAG
  962. );
  963. if (resourceArray == NULL) {
  964. return STATUS_INSUFFICIENT_RESOURCES;
  965. }
  966. RtlZeroMemory( resourceArray, sizeof(PIO_RESOURCE_LIST) * listSize );
  967. //
  968. // Get the first list to work on
  969. //
  970. curList = &( (*IoResReqList)->List[0]);
  971. buffer = (PUCHAR) curList;
  972. newSize = sizeof(IO_RESOURCE_REQUIREMENTS_LIST) - sizeof(IO_RESOURCE_LIST);
  973. //
  974. // Sort the IoResList
  975. //
  976. status = ACPIRangeSortIoList( curList );
  977. if (!NT_SUCCESS(status)) {
  978. ACPIPrint( (
  979. ACPI_PRINT_FAILURE,
  980. "ACPIRangeSubtract: AcpiRangeSortIoList 0x%08lx Failed 0x%08lx\n",
  981. *curList,
  982. status
  983. ) );
  984. return status;
  985. }
  986. //
  987. // Process all the elements in the list
  988. //
  989. for (listIndex = 0; listIndex < listSize; listIndex++) {
  990. //
  991. // Process that list
  992. //
  993. status = ACPIRangeSubtractIoList(
  994. curList,
  995. CmResList,
  996. &(resourceArray[listIndex])
  997. );
  998. if (!NT_SUCCESS(status)) {
  999. ACPIPrint( (
  1000. ACPI_PRINT_CRITICAL,
  1001. "ACPIRangeSubtract: Failed - 0x%08lx\n",
  1002. status
  1003. ) );
  1004. while (listIndex) {
  1005. ExFreePool( resourceArray[listIndex] );
  1006. listIndex--;
  1007. }
  1008. ExFreePool( resourceArray );
  1009. return status;
  1010. }
  1011. //
  1012. // Help calculate the size of the new res req descriptor
  1013. //
  1014. newSize += sizeof(IO_RESOURCE_LIST) +
  1015. ( ( (resourceArray[listIndex])->Count - 1) *
  1016. sizeof(IO_RESOURCE_DESCRIPTOR) );
  1017. //
  1018. // Find the next list
  1019. //
  1020. size = sizeof(IO_RESOURCE_LIST) + (curList->Count - 1) *
  1021. sizeof(IO_RESOURCE_DESCRIPTOR);
  1022. buffer += size;
  1023. curList = (PIO_RESOURCE_LIST) buffer;
  1024. }
  1025. //
  1026. // Allocate the new list
  1027. //
  1028. newList = ExAllocatePoolWithTag(
  1029. NonPagedPool,
  1030. newSize,
  1031. ACPI_RESOURCE_POOLTAG
  1032. );
  1033. if (newList == NULL) {
  1034. ACPIPrint( (
  1035. ACPI_PRINT_CRITICAL,
  1036. "ACPIRangeSubtract: Failed to allocate 0x%08lx bytes\n",
  1037. size
  1038. ) );
  1039. do {
  1040. listSize--;
  1041. ExFreePool( resourceArray[listSize] );
  1042. } while (listSize);
  1043. ExFreePool( resourceArray );
  1044. return STATUS_INSUFFICIENT_RESOURCES;
  1045. }
  1046. //
  1047. // Copy the head of the res req list
  1048. //
  1049. RtlZeroMemory( newList, newSize );
  1050. RtlCopyMemory(
  1051. newList,
  1052. *IoResReqList,
  1053. sizeof(IO_RESOURCE_REQUIREMENTS_LIST) -
  1054. sizeof(IO_RESOURCE_LIST)
  1055. );
  1056. newList->ListSize = newSize;
  1057. curList = &(newList->List[0]);
  1058. buffer = (PUCHAR) curList;
  1059. for (listIndex = 0; listIndex < listSize; listIndex++) {
  1060. //
  1061. // Determine the size to copy
  1062. //
  1063. size = sizeof(IO_RESOURCE_LIST) +
  1064. ( ( ( (resourceArray[listIndex])->Count) - 1) *
  1065. sizeof(IO_RESOURCE_DESCRIPTOR) );
  1066. //
  1067. // Copy the new resource to the correct place
  1068. //
  1069. RtlCopyMemory(
  1070. curList,
  1071. resourceArray[ listIndex ],
  1072. size
  1073. );
  1074. //
  1075. // Find the next list
  1076. //
  1077. buffer += size;
  1078. curList = (PIO_RESOURCE_LIST) buffer;
  1079. //
  1080. // Done with this list
  1081. //
  1082. ExFreePool( resourceArray[listIndex] );
  1083. }
  1084. //
  1085. // Done with this area of memory
  1086. //
  1087. ExFreePool( resourceArray );
  1088. //
  1089. // Free Old list
  1090. //
  1091. ExFreePool( *IoResReqList );
  1092. //
  1093. // Return the new list
  1094. //
  1095. *IoResReqList = newList;
  1096. //
  1097. // Done
  1098. //
  1099. return STATUS_SUCCESS;
  1100. }
  1101. NTSTATUS
  1102. ACPIRangeSubtractIoList(
  1103. IN PIO_RESOURCE_LIST IoResList,
  1104. IN PCM_RESOURCE_LIST CmResList,
  1105. OUT PIO_RESOURCE_LIST *Result
  1106. )
  1107. /*++
  1108. Routine Description:
  1109. This routine is responsible for subtracting the elements of the
  1110. CmResList from the IoResList
  1111. Arguments:
  1112. IoResList - The list to subtract from
  1113. CmResList - The list to subtract
  1114. Result - The answer
  1115. Return Value:
  1116. NTSTATUS
  1117. --*/
  1118. {
  1119. //
  1120. // The current CM descriptor
  1121. //
  1122. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmDesc;
  1123. //
  1124. // The current CM resource list that we are processing
  1125. //
  1126. PCM_PARTIAL_RESOURCE_LIST cmList;
  1127. //
  1128. // The current IO descriptor
  1129. //
  1130. PIO_RESOURCE_DESCRIPTOR ioDesc;
  1131. //
  1132. // The working copy of the result list
  1133. //
  1134. PIO_RESOURCE_LIST workList;
  1135. //
  1136. // The current index into the cm res list
  1137. //
  1138. ULONG cmIndex;
  1139. //
  1140. // The number of elements there are in the cm res list
  1141. //
  1142. ULONG cmSize;
  1143. //
  1144. // The current index into the io res list
  1145. //
  1146. ULONG ioIndex;
  1147. //
  1148. // The number of elements there are in the io res list
  1149. //
  1150. ULONG ioSize;
  1151. //
  1152. // The current index into the result. This is where the 'next' resource
  1153. // descriptor goes into.
  1154. //
  1155. ULONG resultIndex = 0;
  1156. //
  1157. // How many elements there are in the result
  1158. //
  1159. ULONG resultSize;
  1160. //
  1161. // These are the max and min of the cm desc
  1162. //
  1163. ULONGLONG cmMax, cmMin;
  1164. //
  1165. // These are the max and min of the io desc
  1166. //
  1167. ULONGLONG ioMax, ioMin;
  1168. //
  1169. // The length of the resource
  1170. //
  1171. ULONGLONG length;
  1172. //
  1173. // Step one: Obtain the pointers we need to the start of the cm list
  1174. // and the size of the supplied lists
  1175. //
  1176. cmList = &(CmResList->List[0].PartialResourceList);
  1177. cmSize = cmList->Count;
  1178. ioSize = IoResList->Count;
  1179. //
  1180. // Step two: Calculate the number of Io descriptors needed in the
  1181. // worst case. That is 2x the number of cm descriptors plut the number
  1182. // of original io descriptors.
  1183. //
  1184. resultSize = cmSize * 2 + ioSize * 2;
  1185. //
  1186. // Step three: Allocate enough memory for those descriptors
  1187. //
  1188. workList = ExAllocatePoolWithTag(
  1189. NonPagedPool,
  1190. sizeof(IO_RESOURCE_LIST) +
  1191. (sizeof(IO_RESOURCE_DESCRIPTOR) * (resultSize - 1) ),
  1192. ACPI_RESOURCE_POOLTAG
  1193. );
  1194. if (workList == NULL) {
  1195. return STATUS_INSUFFICIENT_RESOURCES;
  1196. }
  1197. RtlZeroMemory( workList, sizeof(IO_RESOURCE_LIST) +
  1198. (sizeof(IO_RESOURCE_DESCRIPTOR) * (resultSize - 1) ) );
  1199. RtlCopyMemory(
  1200. workList,
  1201. IoResList,
  1202. sizeof(IO_RESOURCE_LIST) - sizeof(IO_RESOURCE_DESCRIPTOR)
  1203. );
  1204. //
  1205. // Step four: walk through the entire io res list
  1206. //
  1207. for (ioIndex = 0; ioIndex < ioSize; ioIndex++) {
  1208. //
  1209. // Step five: copy the current descriptor to the result, and
  1210. // keep a pointer to it. Remember where to store the next io
  1211. // descriptor.
  1212. //
  1213. RtlCopyMemory(
  1214. &(workList->Descriptors[resultIndex]),
  1215. &(IoResList->Descriptors[ioIndex]),
  1216. sizeof(IO_RESOURCE_DESCRIPTOR)
  1217. );
  1218. ACPIPrint( (
  1219. ACPI_PRINT_RESOURCES_2,
  1220. "Copied Desc %d (0x%08lx) to Index %d (0x%08lx)\n",
  1221. ioIndex,
  1222. &(IoResList->Descriptors[ioIndex]),
  1223. resultIndex,
  1224. &(workList->Descriptors[resultIndex])
  1225. ) );
  1226. ioDesc = &(workList->Descriptors[resultIndex]);
  1227. resultIndex += 1;
  1228. //
  1229. // Step six: Walk the Cm Res list, looking for resources to
  1230. // subtract from this descriptor
  1231. //
  1232. for (cmIndex = 0; cmIndex < cmSize; cmIndex++) {
  1233. //
  1234. // If we don't have a resource descriptor any more, then
  1235. // we stop looping
  1236. //
  1237. if (ioDesc == NULL) {
  1238. break;
  1239. }
  1240. //
  1241. // Step seven: determine the current cm descriptor
  1242. //
  1243. cmDesc = &(cmList->PartialDescriptors[cmIndex]);
  1244. //
  1245. // Step eight: is the current cm descriptor of the same type
  1246. // as the io descriptor?
  1247. //
  1248. if (cmDesc->Type != ioDesc->Type) {
  1249. //
  1250. // No
  1251. //
  1252. continue;
  1253. }
  1254. //
  1255. // Step nine: we must handle each resource type indepently.
  1256. //
  1257. switch (ioDesc->Type) {
  1258. case CmResourceTypeMemory:
  1259. case CmResourceTypePort:
  1260. ioMin = ioDesc->u.Port.MinimumAddress.QuadPart;
  1261. ioMax = ioDesc->u.Port.MaximumAddress.QuadPart;
  1262. cmMin = cmDesc->u.Port.Start.QuadPart;
  1263. cmMax = cmDesc->u.Port.Start.QuadPart +
  1264. cmDesc->u.Port.Length - 1;
  1265. ACPIPrint( (
  1266. ACPI_PRINT_RESOURCES_2,
  1267. "ACPIRangeSubtractIoRange: ioMin 0x%lx ioMax 0x%lx "
  1268. "cmMin 0x%lx cmMax 0x%lx resultIndex 0x%lx\n",
  1269. (ULONG) ioMin,
  1270. (ULONG) ioMax,
  1271. (ULONG) cmMin,
  1272. (ULONG) cmMax,
  1273. resultIndex
  1274. ) );
  1275. //
  1276. // Does the descriptors overlap?
  1277. //
  1278. if (ioMin > cmMax || ioMax < cmMin) {
  1279. break;
  1280. }
  1281. //
  1282. // Do we need to remove the descriptor from the list?
  1283. //
  1284. if (ioMin >= cmMin && ioMax <= cmMax) {
  1285. resultIndex -= 1;
  1286. ioDesc = NULL;
  1287. break;
  1288. }
  1289. //
  1290. // Do we need to truncate the lowpart of the io desc?
  1291. //
  1292. if (ioMin >= cmMin && ioMax > cmMax) {
  1293. ioDesc->u.Port.MinimumAddress.QuadPart = (cmMax + 1);
  1294. length = ioMax - cmMax;
  1295. }
  1296. //
  1297. // Do we need to truncate the highpart of the io desc?
  1298. //
  1299. if (ioMin < cmMin && ioMax <= cmMax) {
  1300. ioDesc->u.Port.MaximumAddress.QuadPart = (cmMin - 1);
  1301. length = cmMin - ioMin;
  1302. }
  1303. //
  1304. // Do we need to split the descriptor into two parts
  1305. //
  1306. if (ioMin < cmMin && ioMax > cmMax) {
  1307. //
  1308. // Create a new descriptors
  1309. //
  1310. RtlCopyMemory(
  1311. &(workList->Descriptors[resultIndex]),
  1312. ioDesc,
  1313. sizeof(IO_RESOURCE_DESCRIPTOR)
  1314. );
  1315. ACPIPrint( (
  1316. ACPI_PRINT_RESOURCES_2,
  1317. "Copied Desc (0x%08lx) to Index %d (0x%08lx)\n",
  1318. &(IoResList->Descriptors[ioIndex]),
  1319. resultIndex,
  1320. &(workList->Descriptors[resultIndex])
  1321. ) );
  1322. ioDesc->u.Port.MaximumAddress.QuadPart = (cmMin - 1);
  1323. ioDesc->u.Port.Alignment = 1;
  1324. length = cmMin - ioMin;
  1325. if ( (ULONG) length < ioDesc->u.Port.Length) {
  1326. ioDesc->u.Port.Length = (ULONG) length;
  1327. }
  1328. //
  1329. // Next descriptor
  1330. //
  1331. ioDesc = &(workList->Descriptors[resultIndex]);
  1332. ioDesc->u.Port.MinimumAddress.QuadPart = (cmMax + 1);
  1333. ioDesc->u.Port.Alignment = 1;
  1334. length = ioMax - cmMax;
  1335. resultIndex += 1;
  1336. }
  1337. //
  1338. // Do we need to update the length?
  1339. //
  1340. if ( (ULONG) length < ioDesc->u.Port.Length) {
  1341. ioDesc->u.Port.Length = (ULONG) length;
  1342. }
  1343. break;
  1344. case CmResourceTypeInterrupt:
  1345. //
  1346. // Do the descriptors overlap?
  1347. //
  1348. if (ioDesc->u.Interrupt.MinimumVector >
  1349. cmDesc->u.Interrupt.Vector ||
  1350. ioDesc->u.Interrupt.MaximumVector <
  1351. cmDesc->u.Interrupt.Vector) {
  1352. break;
  1353. }
  1354. //
  1355. // Do we have to remove the descriptor
  1356. //
  1357. if (ioDesc->u.Interrupt.MinimumVector ==
  1358. cmDesc->u.Interrupt.Vector &&
  1359. ioDesc->u.Interrupt.MaximumVector ==
  1360. cmDesc->u.Interrupt.Vector) {
  1361. resultIndex =- 1;
  1362. ioDesc = NULL;
  1363. break;
  1364. }
  1365. //
  1366. // Do we clip the low part?
  1367. //
  1368. if (ioDesc->u.Interrupt.MinimumVector ==
  1369. cmDesc->u.Interrupt.Vector) {
  1370. ioDesc->u.Interrupt.MinimumVector++;
  1371. break;
  1372. }
  1373. //
  1374. // Do we clip the high part
  1375. //
  1376. if (ioDesc->u.Interrupt.MaximumVector ==
  1377. cmDesc->u.Interrupt.Vector) {
  1378. ioDesc->u.Interrupt.MaximumVector--;
  1379. break;
  1380. }
  1381. //
  1382. // Split the record
  1383. //
  1384. RtlCopyMemory(
  1385. &(workList->Descriptors[resultIndex]),
  1386. ioDesc,
  1387. sizeof(IO_RESOURCE_DESCRIPTOR)
  1388. );
  1389. ACPIPrint( (
  1390. ACPI_PRINT_RESOURCES_2,
  1391. "Copied Desc (0x%08lx) to Index %d (0x%08lx)\n",
  1392. &(IoResList->Descriptors[ioIndex]),
  1393. resultIndex,
  1394. &(workList->Descriptors[resultIndex])
  1395. ) );
  1396. ioDesc->u.Interrupt.MaximumVector =
  1397. cmDesc->u.Interrupt.Vector - 1;
  1398. ioDesc = &(workList->Descriptors[resultIndex]);
  1399. ioDesc->u.Interrupt.MinimumVector =
  1400. cmDesc->u.Interrupt.Vector + 1;
  1401. resultIndex += 1;
  1402. break;
  1403. case CmResourceTypeDma:
  1404. //
  1405. // Do the descriptors overlap?
  1406. //
  1407. if (ioDesc->u.Dma.MinimumChannel >
  1408. cmDesc->u.Dma.Channel ||
  1409. ioDesc->u.Dma.MaximumChannel <
  1410. cmDesc->u.Dma.Channel) {
  1411. break;
  1412. }
  1413. //
  1414. // Do we have to remove the descriptor
  1415. //
  1416. if (ioDesc->u.Dma.MinimumChannel ==
  1417. cmDesc->u.Dma.Channel &&
  1418. ioDesc->u.Dma.MaximumChannel ==
  1419. cmDesc->u.Dma.Channel) {
  1420. resultIndex -= 1;
  1421. ioDesc = NULL;
  1422. break;
  1423. }
  1424. //
  1425. // Do we clip the low part?
  1426. //
  1427. if (ioDesc->u.Dma.MinimumChannel ==
  1428. cmDesc->u.Dma.Channel) {
  1429. ioDesc->u.Dma.MinimumChannel++;
  1430. break;
  1431. }
  1432. //
  1433. // Do we clip the high part
  1434. //
  1435. if (ioDesc->u.Dma.MaximumChannel ==
  1436. cmDesc->u.Dma.Channel) {
  1437. ioDesc->u.Dma.MaximumChannel--;
  1438. break;
  1439. }
  1440. //
  1441. // Split the record
  1442. //
  1443. RtlCopyMemory(
  1444. &(workList->Descriptors[resultIndex]),
  1445. ioDesc,
  1446. sizeof(IO_RESOURCE_DESCRIPTOR)
  1447. );
  1448. ACPIPrint( (
  1449. ACPI_PRINT_RESOURCES_2,
  1450. "Copied Desc (0x%08lx) to Index %d (0x%08lx)\n",
  1451. &(IoResList->Descriptors[ioIndex]),
  1452. resultIndex,
  1453. &(workList->Descriptors[resultIndex])
  1454. ) );
  1455. ioDesc->u.Dma.MaximumChannel =
  1456. cmDesc->u.Dma.Channel - 1;
  1457. ioDesc = &(workList->Descriptors[resultIndex]);
  1458. ioDesc->u.Dma.MinimumChannel =
  1459. cmDesc->u.Dma.Channel + 1;
  1460. resultIndex += 1;
  1461. break;
  1462. } // switch
  1463. } // for
  1464. //
  1465. // Step ten, make a backup copy of the original descriptor, and
  1466. // mark it as a DeviceSpecific resource
  1467. //
  1468. RtlCopyMemory(
  1469. &(workList->Descriptors[resultIndex]),
  1470. &(IoResList->Descriptors[ioIndex]),
  1471. sizeof(IO_RESOURCE_DESCRIPTOR)
  1472. );
  1473. ACPIPrint( (
  1474. ACPI_PRINT_RESOURCES_2,
  1475. "Copied Desc %d (0x%08lx) to Index %d (0x%08lx) for backup\n",
  1476. ioIndex,
  1477. &(IoResList->Descriptors[ioIndex]),
  1478. resultIndex,
  1479. &(workList->Descriptors[resultIndex])
  1480. ) );
  1481. ioDesc = &(workList->Descriptors[resultIndex]);
  1482. ioDesc->Type = CmResourceTypeDevicePrivate;
  1483. resultIndex += 1;
  1484. } // for
  1485. //
  1486. // Step 11: Calculate the number of resources in the new list
  1487. //
  1488. workList->Count = resultIndex;
  1489. //
  1490. // Step 12: Allocate the block for the return value. Don't waste
  1491. // any memory here
  1492. //
  1493. *Result = ExAllocatePoolWithTag(
  1494. NonPagedPool,
  1495. sizeof(IO_RESOURCE_LIST) +
  1496. (sizeof(IO_RESOURCE_DESCRIPTOR) * (resultIndex - 1) ),
  1497. ACPI_RESOURCE_POOLTAG
  1498. );
  1499. if (*Result == NULL) {
  1500. return STATUS_INSUFFICIENT_RESOURCES;
  1501. }
  1502. //
  1503. // Step 13: Copy the result over and free the work buffer
  1504. //
  1505. RtlCopyMemory(
  1506. *Result,
  1507. workList,
  1508. sizeof(IO_RESOURCE_LIST) +
  1509. (sizeof(IO_RESOURCE_DESCRIPTOR) * (resultIndex - 1) )
  1510. );
  1511. //
  1512. // Step 14: Done
  1513. //
  1514. return STATUS_SUCCESS;
  1515. }
  1516. VOID
  1517. ACPIRangeValidatePciMemoryResource(
  1518. IN PIO_RESOURCE_LIST IoList,
  1519. IN ULONG Index,
  1520. IN PACPI_BIOS_MULTI_NODE E820Info,
  1521. OUT ULONG *BugCheck
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. This routine checks the specified descriptor in the resource list does
  1526. not in any way overlap or conflict with any of the descriptors in the
  1527. E820 information structure
  1528. Arguments:
  1529. IoResList - The IoResourceList to check
  1530. Index - The descript we are currently looking at
  1531. E820Info - The BIOS's memory description table (Chapter 14 of ACPI Spec)
  1532. BugCheck - The number of bugcheckable offences commited
  1533. Return Value:
  1534. None
  1535. --*/
  1536. {
  1537. ULONG i;
  1538. ULONGLONG absMin;
  1539. ULONGLONG absMax;
  1540. ASSERT( IoList != NULL );
  1541. //
  1542. // Make sure that there is an E820 table before we look at it
  1543. //
  1544. if (E820Info == NULL) {
  1545. return;
  1546. }
  1547. //
  1548. // Calculate the absolute maximum and minimum size of the memory window
  1549. //
  1550. absMin = IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart;
  1551. absMax = IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart;
  1552. //
  1553. // Look at all the entries in the E820Info and see if there is an
  1554. // overlap
  1555. //
  1556. for (i = 0; i < E820Info->Count; i++) {
  1557. //
  1558. // Hackhack --- if this is a "Reserved" address, then don't consider
  1559. // those a bugcheck
  1560. //
  1561. if (E820Info->E820Entry[i].Type == AcpiAddressRangeReserved) {
  1562. continue;
  1563. }
  1564. //
  1565. // Do some fixups firsts
  1566. //
  1567. if (E820Info->E820Entry[i].Type == AcpiAddressRangeNVS ||
  1568. E820Info->E820Entry[i].Type == AcpiAddressRangeACPI) {
  1569. ASSERT( E820Info->E820Entry[i].Length.HighPart == 0);
  1570. if (E820Info->E820Entry[i].Length.HighPart != 0) {
  1571. ACPIPrint( (
  1572. ACPI_PRINT_WARNING,
  1573. "ACPI: E820 Entry #%d (type %d) Length = %016I64x > 32bit\n",
  1574. i,
  1575. E820Info->E820Entry[i].Type,
  1576. E820Info->E820Entry[i].Length.QuadPart
  1577. ) );
  1578. E820Info->E820Entry[i].Length.HighPart = 0;
  1579. }
  1580. }
  1581. //
  1582. // Is the descriptor beyond what we are looking for?
  1583. //
  1584. if (absMax < (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart) {
  1585. continue;
  1586. }
  1587. //
  1588. // Is it before what we are looking for?
  1589. //
  1590. if (absMin >= (ULONGLONG) (E820Info->E820Entry[i].Base.QuadPart + E820Info->E820Entry[i].Length.QuadPart) ) {
  1591. continue;
  1592. }
  1593. ACPIPrint( (
  1594. ACPI_PRINT_CRITICAL,
  1595. "ACPI: E820 Entry %d (type %I64d) (%I64x-%I64x) overlaps\n"
  1596. "ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
  1597. i, E820Info->E820Entry[i].Type,
  1598. E820Info->E820Entry[i].Base.QuadPart,
  1599. (E820Info->E820Entry[i].Base.QuadPart + E820Info->E820Entry[i].Length.QuadPart),
  1600. Index,
  1601. IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart,
  1602. IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart,
  1603. IoList->Descriptors[Index].u.Memory.Length,
  1604. IoList->Descriptors[Index].u.Memory.Alignment
  1605. ) );
  1606. //
  1607. // Is this an NVS area? Are we doing an override of this?
  1608. //
  1609. if ( (AcpiOverrideAttributes & ACPI_OVERRIDE_NVS_CHECK) &&
  1610. (E820Info->E820Entry[i].Type == AcpiAddressRangeNVS) ) {
  1611. if (absMax >= (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart &&
  1612. absMin < (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart) {
  1613. //
  1614. // We can attempt to do a helpfull fixup here
  1615. //
  1616. IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart =
  1617. (ULONGLONG) E820Info->E820Entry[i].Base.QuadPart - 1;
  1618. IoList->Descriptors[Index].u.Memory.Length = (ULONG)
  1619. (IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart -
  1620. IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart + 1);
  1621. ACPIPrint( (
  1622. ACPI_PRINT_CRITICAL,
  1623. "ACPI: PCI Entry %d Changed to\n"
  1624. "ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
  1625. Index,
  1626. Index,
  1627. IoList->Descriptors[Index].u.Memory.MinimumAddress.QuadPart,
  1628. IoList->Descriptors[Index].u.Memory.MaximumAddress.QuadPart,
  1629. IoList->Descriptors[Index].u.Memory.Length,
  1630. IoList->Descriptors[Index].u.Memory.Alignment
  1631. ) );
  1632. }
  1633. ACPIPrint( (
  1634. ACPI_PRINT_CRITICAL,
  1635. "ACPI: E820 Entry %d Overrides PCI Entry\n",
  1636. i
  1637. ) );
  1638. continue;
  1639. }
  1640. //
  1641. // If we got here, then there is an overlap, and we need to bugcheck
  1642. //
  1643. (*BugCheck)++;
  1644. }
  1645. }
  1646. VOID
  1647. ACPIRangeValidatePciResources(
  1648. IN PDEVICE_EXTENSION DeviceExtension,
  1649. IN PIO_RESOURCE_REQUIREMENTS_LIST IoResList
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. This routine is called to make sure that the resource that we will
  1654. hand of to PCI have a chance of making the system boot.
  1655. This is what the list will allow
  1656. MEM - A0000 - DFFFF,
  1657. <Physical Base> - 4GB
  1658. IO - Any
  1659. BUS - Any
  1660. The code checks to make sure that the Length = Max - Min + 1, and that
  1661. the Alignment value is correct
  1662. Arguments:
  1663. IoResList - The list to check
  1664. Return Value:
  1665. Nothing
  1666. --*/
  1667. {
  1668. NTSTATUS status;
  1669. PACPI_BIOS_MULTI_NODE e820Info;
  1670. PCM_PARTIAL_RESOURCE_DESCRIPTOR cmPartialDesc;
  1671. PCM_PARTIAL_RESOURCE_LIST cmPartialList;
  1672. PIO_RESOURCE_LIST ioList;
  1673. PKEY_VALUE_PARTIAL_INFORMATION_ALIGN64 keyInfo;
  1674. ULONG bugCheck = 0;
  1675. ULONG i;
  1676. ULONG j;
  1677. ULONGLONG length;
  1678. ULONG size;
  1679. if (IoResList == NULL) {
  1680. ACPIPrint( (
  1681. ACPI_PRINT_CRITICAL,
  1682. "ACPIRangeValidPciResources: No IoResList\n"
  1683. ) );
  1684. KeBugCheckEx(
  1685. ACPI_BIOS_ERROR,
  1686. ACPI_ROOT_PCI_RESOURCE_FAILURE,
  1687. (ULONG_PTR) DeviceExtension,
  1688. 2,
  1689. 0
  1690. );
  1691. }
  1692. //
  1693. // Read the key for the AcpiConfigurationData
  1694. //
  1695. status = OSReadAcpiConfigurationData( &keyInfo );
  1696. if (!NT_SUCCESS(status)) {
  1697. ACPIPrint( (
  1698. ACPI_PRINT_CRITICAL,
  1699. "ACPIRangeValidatePciResources: Cannot get Information %08lx\n",
  1700. status
  1701. ) );
  1702. return;
  1703. }
  1704. //
  1705. // Crack the structure to get the E820Table entry
  1706. //
  1707. cmPartialList = (PCM_PARTIAL_RESOURCE_LIST) (keyInfo->Data);
  1708. cmPartialDesc = &(cmPartialList->PartialDescriptors[0]);
  1709. e820Info = (PACPI_BIOS_MULTI_NODE) ( (PUCHAR) cmPartialDesc +
  1710. sizeof(CM_PARTIAL_RESOURCE_LIST) );
  1711. //
  1712. // Walk the resource requirements list
  1713. //
  1714. ioList = &(IoResList->List[0]);
  1715. for (i = 0; i < IoResList->AlternativeLists; i++) {
  1716. //
  1717. // Walk the IO list
  1718. //
  1719. for (j = 0; j < ioList->Count; j++) {
  1720. if (ioList->Descriptors[j].Type == CmResourceTypePort ||
  1721. ioList->Descriptors[j].Type == CmResourceTypeMemory) {
  1722. length = ioList->Descriptors[j].u.Port.MaximumAddress.QuadPart -
  1723. ioList->Descriptors[j].u.Port.MinimumAddress.QuadPart + 1;
  1724. if (length > MAXULONG) {
  1725. ACPIPrint( (
  1726. ACPI_PRINT_CRITICAL,
  1727. "ACPI: Invalid IO/Mem Length > MAXULONG)\n"
  1728. "ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
  1729. j,
  1730. ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
  1731. ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
  1732. length,
  1733. ioList->Descriptors[j].u.Memory.Alignment
  1734. ) );
  1735. bugCheck++;
  1736. }
  1737. //
  1738. // Does the length match?
  1739. //
  1740. if (length != ioList->Descriptors[j].u.Port.Length) {
  1741. ACPIPrint( (
  1742. ACPI_PRINT_CRITICAL,
  1743. "ACPI: Invalid IO/Mem Length - ( (Max - Min + 1) != Length)\n"
  1744. "ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
  1745. j,
  1746. ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
  1747. ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
  1748. ioList->Descriptors[j].u.Memory.Length,
  1749. ioList->Descriptors[j].u.Memory.Alignment
  1750. ) );
  1751. bugCheck++;
  1752. }
  1753. //
  1754. // Is the alignment non-zero?
  1755. //
  1756. if (ioList->Descriptors[j].u.Port.Alignment == 0) {
  1757. ACPIPrint( (
  1758. ACPI_PRINT_CRITICAL,
  1759. "ACPI: Invalid IO/Mem Alignment"
  1760. "ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
  1761. j,
  1762. ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
  1763. ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
  1764. ioList->Descriptors[j].u.Memory.Length,
  1765. ioList->Descriptors[j].u.Memory.Alignment
  1766. ) );
  1767. bugCheck++;
  1768. }
  1769. //
  1770. // The alignment cannot intersect with the min value
  1771. //
  1772. if (ioList->Descriptors[j].u.Port.MinimumAddress.LowPart &
  1773. (ioList->Descriptors[j].u.Port.Alignment - 1) ) {
  1774. ACPIPrint( (
  1775. ACPI_PRINT_CRITICAL,
  1776. "ACPI: Invalid IO/Mem Alignment - (Min & (Align - 1) )\n"
  1777. "ACPI: PCI Entry %d Min:%I64x Max:%I64x Length:%lx Align:%lx\n",
  1778. j,
  1779. ioList->Descriptors[j].u.Memory.MinimumAddress.QuadPart,
  1780. ioList->Descriptors[j].u.Memory.MaximumAddress.QuadPart,
  1781. ioList->Descriptors[j].u.Memory.Length,
  1782. ioList->Descriptors[j].u.Memory.Alignment
  1783. ) );
  1784. bugCheck++;
  1785. }
  1786. }
  1787. if (ioList->Descriptors[j].Type == CmResourceTypeBusNumber) {
  1788. length = ioList->Descriptors[j].u.BusNumber.MaxBusNumber -
  1789. ioList->Descriptors[j].u.BusNumber.MinBusNumber + 1;
  1790. //
  1791. // Does the length match?
  1792. //
  1793. if (length != ioList->Descriptors[j].u.BusNumber.Length) {
  1794. ACPIPrint( (
  1795. ACPI_PRINT_CRITICAL,
  1796. "ACPI: Invalid BusNumber Length - ( (Max - Min + 1) != Length)\n"
  1797. "ACPI: PCI Entry %d Min:%x Max:%x Length:%lx\n",
  1798. j,
  1799. ioList->Descriptors[j].u.BusNumber.MinBusNumber,
  1800. ioList->Descriptors[j].u.BusNumber.MaxBusNumber,
  1801. ioList->Descriptors[j].u.BusNumber.Length
  1802. ) );
  1803. bugCheck++;
  1804. }
  1805. }
  1806. if (ioList->Descriptors[j].Type == CmResourceTypeMemory) {
  1807. ACPIRangeValidatePciMemoryResource(
  1808. ioList,
  1809. j,
  1810. e820Info,
  1811. &bugCheck
  1812. );
  1813. }
  1814. }
  1815. //
  1816. // Next list
  1817. //
  1818. size = sizeof(IO_RESOURCE_LIST) +
  1819. ( (ioList->Count - 1) * sizeof(IO_RESOURCE_DESCRIPTOR) );
  1820. ioList = (PIO_RESOURCE_LIST) ( ( (PUCHAR) ioList ) + size );
  1821. }
  1822. //
  1823. // Do we errors?
  1824. //
  1825. if (bugCheck) {
  1826. ACPIPrint( (
  1827. ACPI_PRINT_CRITICAL,
  1828. "ACPI:\n"
  1829. "ACPI: FATAL BIOS ERROR - Need new BIOS to fix PCI problems\n"
  1830. "ACPI:\n"
  1831. "ACPI: This machine will not boot after 8/26/98!!!!\n"
  1832. ) );
  1833. //
  1834. // No, well, bugcheck
  1835. //
  1836. KeBugCheckEx(
  1837. ACPI_BIOS_ERROR,
  1838. ACPI_ROOT_PCI_RESOURCE_FAILURE,
  1839. (ULONG_PTR) DeviceExtension,
  1840. (ULONG_PTR) IoResList,
  1841. (ULONG_PTR) e820Info
  1842. );
  1843. }
  1844. //
  1845. // Free the E820 info
  1846. //
  1847. ExFreePool( keyInfo );
  1848. }