Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1072 lines
26 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. mpaddr.c
  6. Abstract:
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. */
  13. #include "halp.h"
  14. #include "apic.inc"
  15. #include "pcmp_nt.inc"
  16. #include "pci.h"
  17. #if DEBUGGING
  18. #include "stdio.h"
  19. #endif
  20. #define STATIC // functions used internal to this module
  21. #define KEY_VALUE_BUFFER_SIZE 1024
  22. #if DBG
  23. extern ULONG HalDebug;
  24. #endif
  25. extern struct HalpMpInfo HalpMpInfoTable;
  26. extern USHORT HalpIoCompatibleRangeList0[];
  27. extern USHORT HalpIoCompatibleRangeList1[];
  28. extern BOOLEAN HalpPciLockSettings;
  29. extern WCHAR HalpSzSystem[];
  30. struct PcMpTable *PcMpTablePtr;
  31. BOOLEAN
  32. HalpTranslateIsaBusAddress (
  33. IN PVOID BusHandler,
  34. IN PVOID RootHandler,
  35. IN PHYSICAL_ADDRESS BusAddress,
  36. IN OUT PULONG AddressSpace,
  37. OUT PPHYSICAL_ADDRESS TranslatedAddress
  38. );
  39. ULONG
  40. HalpNoBusData (
  41. IN PVOID BusHandler,
  42. IN PVOID RootHandler,
  43. IN ULONG SlotNumber,
  44. IN PVOID Buffer,
  45. IN ULONG Offset,
  46. IN ULONG Length
  47. );
  48. HalpGetEisaData (
  49. IN PVOID BusHandler,
  50. IN PVOID RootHandler,
  51. IN ULONG SlotNumber,
  52. IN PVOID Buffer,
  53. IN ULONG Offset,
  54. IN ULONG Length
  55. );
  56. NTSTATUS
  57. HalpAdjustEisaResourceList (
  58. IN PVOID BusHandler,
  59. IN PVOID RootHandler,
  60. IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
  61. );
  62. ULONG
  63. HalpGetEisaInterruptVector (
  64. IN PVOID BusHandler,
  65. IN PVOID RootHandler,
  66. IN ULONG BusInterruptLevel,
  67. IN ULONG BusInterruptVector,
  68. OUT PKIRQL Irql,
  69. OUT PKAFFINITY Affinity
  70. );
  71. // --------------------------------------------------------------------
  72. VOID
  73. HalpInitBusAddressMapInfo (
  74. VOID
  75. );
  76. STATIC PSUPPORTED_RANGES
  77. HalpBuildBusAddressMap (
  78. IN UCHAR MpsBusId
  79. );
  80. PBUS_HANDLER
  81. HalpLookupCreateHandlerForBus (
  82. IN PPCMPBUSTRANS pBusType,
  83. IN ULONG BusNo
  84. );
  85. VOID
  86. HalpInheritBusAddressMapInfo (
  87. VOID
  88. );
  89. BOOLEAN
  90. HalpMPSBusId2NtBusId (
  91. IN UCHAR ApicBusId,
  92. OUT PPCMPBUSTRANS *ppBusType,
  93. OUT PULONG BusNo
  94. );
  95. STATIC PSUPPORTED_RANGES
  96. HalpMergeRangesFromParent (
  97. PSUPPORTED_RANGES CurrentList,
  98. UCHAR MpsBusId
  99. );
  100. #if DEBUGGING
  101. VOID
  102. HalpDisplayBusInformation (
  103. PBUS_HANDLER Bus
  104. );
  105. #endif
  106. //
  107. // Internal prototypes
  108. //
  109. struct {
  110. ULONG Offset;
  111. UCHAR MpsType;
  112. } HalpMpsRangeList[] = {
  113. FIELD_OFFSET (SUPPORTED_RANGES, IO), MPS_ADDRESS_MAP_IO,
  114. FIELD_OFFSET (SUPPORTED_RANGES, Memory), MPS_ADDRESS_MAP_MEMORY,
  115. FIELD_OFFSET (SUPPORTED_RANGES, PrefetchMemory),MPS_ADDRESS_MAP_PREFETCH_MEMORY,
  116. FIELD_OFFSET (SUPPORTED_RANGES, Dma), MPS_ADDRESS_MAP_UNDEFINED,
  117. 0, MPS_ADDRESS_MAP_UNDEFINED
  118. };
  119. #define RANGE_LIST(a,i) ((PSUPPORTED_RANGE) ((PUCHAR) a + HalpMpsRangeList[i].Offset))
  120. #ifdef ALLOC_PRAGMA
  121. #pragma alloc_text(INIT,HalpInitBusAddressMapInfo)
  122. #pragma alloc_text(INIT,HalpBuildBusAddressMap)
  123. #pragma alloc_text(INIT,HalpInheritBusAddressMapInfo)
  124. #pragma alloc_text(INIT,HalpMergeRangesFromParent)
  125. #pragma alloc_text(INIT,HalpLookupCreateHandlerForBus)
  126. #pragma alloc_text(PAGE,HalpAllocateNewRangeList)
  127. #pragma alloc_text(PAGE,HalpFreeRangeList)
  128. #pragma alloc_text(PAGE,HalpMpsGetParentBus)
  129. #pragma alloc_text(PAGE,HalpMpsBusIsRootBus)
  130. #endif
  131. VOID
  132. HalpInitBusAddressMapInfo (
  133. VOID
  134. )
  135. /*++
  136. Routine Description:
  137. Reads MPS bus addressing mapping table, and builds/replaces the
  138. supported address range mapping for the given bus.
  139. Note there's a little slop in this function as it doesn't reclaim
  140. memory allocated before this function is called, which it replaces
  141. pointers too.
  142. --*/
  143. {
  144. ULONG BusNo;
  145. PPCMPBUSTRANS pBusType;
  146. PMPS_EXTENTRY ExtTable2, ExtTable;
  147. PBUS_HANDLER Handler;
  148. PSUPPORTED_RANGES Addresses;
  149. ULONG i;
  150. BOOLEAN Processed;
  151. //
  152. // Check for any address mapping information for the buses
  153. //
  154. // Note: We assume that if any MPS bus address map information
  155. // is found for a bus, that the MPS bios will supply all the
  156. // valid IO, Memory, and prefetch memory addresses for that BUS.
  157. // The bios can not supply some address tyeps for a given bus
  158. // without supplying them all.
  159. //
  160. ExtTable = HalpMpInfoTable.ExtensionTable;
  161. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  162. //
  163. // Is this an address map entry?
  164. //
  165. if (ExtTable->Type == EXTTYPE_BUS_ADDRESS_MAP) {
  166. //
  167. // See if this bus has already been processed
  168. //
  169. Processed = FALSE;
  170. ExtTable2 = HalpMpInfoTable.ExtensionTable;
  171. while (ExtTable2 < ExtTable) {
  172. if (ExtTable2->Type == EXTTYPE_BUS_ADDRESS_MAP &&
  173. ExtTable2->u.AddressMap.BusId == ExtTable->u.AddressMap.BusId) {
  174. Processed = TRUE;
  175. break;
  176. }
  177. ExtTable2 = (PMPS_EXTENTRY) (((PUCHAR) ExtTable2) + ExtTable2->Length);
  178. }
  179. //
  180. // Determine the NT bus this map info is for
  181. //
  182. if (!Processed &&
  183. HalpMPSBusId2NtBusId (ExtTable->u.AddressMap.BusId, &pBusType, &BusNo)) {
  184. //
  185. // Lookup the bushander for the bus
  186. //
  187. Handler = HalpLookupCreateHandlerForBus (pBusType, BusNo);
  188. if (Handler) {
  189. //
  190. // NOTE: Until we get better kernel PnP support, for now
  191. // limit the ability of the system to move already BIOS
  192. // initialized devices. This is needed because the exteneded
  193. // express BIOS can't give the OS any breathing space when
  194. // it hands bus supported ranges, and there's currently not
  195. // an interface to the kernel to obtain current PCI device
  196. // settings. (fixed in the future.)
  197. //
  198. HalpPciLockSettings = TRUE;
  199. //
  200. // Build BusAddress Map for this MPS bus
  201. //
  202. Addresses = HalpBuildBusAddressMap (ExtTable->u.AddressMap.BusId);
  203. //
  204. // Consoladate ranges
  205. //
  206. HalpConsolidateRanges (Addresses);
  207. //
  208. // Use current ranges for any undefined MPS ranges
  209. //
  210. for (i=0; HalpMpsRangeList[i].Offset; i++) {
  211. if (HalpMpsRangeList[i].MpsType == MPS_ADDRESS_MAP_UNDEFINED) {
  212. *RANGE_LIST(Addresses,i) = *RANGE_LIST(Handler->BusAddresses, i);
  213. }
  214. }
  215. //
  216. // Set bus'es support addresses
  217. //
  218. Handler->BusAddresses = Addresses;
  219. } else {
  220. DBGMSG ("HAL: Initialize BUS address map - bus not an registered NT bus\n");
  221. }
  222. }
  223. }
  224. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  225. }
  226. }
  227. STATIC PSUPPORTED_RANGES
  228. HalpBuildBusAddressMap (
  229. IN UCHAR MpsBusId
  230. )
  231. /*++
  232. Routine Description:
  233. Builds a SUPPORT_RANGES list for the supplied Mps Bus Id, by
  234. MPS bus addressing mapping descriptors.
  235. Note this function does not include any information contained
  236. in the MPS bus hierarchy descriptors.
  237. Arguments:
  238. MpsBusId - mps bus id of bus to build address map for.
  239. Return:
  240. The bus'es supported ranges as defined by the MPS bus
  241. address mapping descriptors
  242. --*/
  243. {
  244. PMPS_EXTENTRY ExtTable;
  245. PSUPPORTED_RANGES Addresses;
  246. PSUPPORTED_RANGE HRange, Range;
  247. ULONG i, j, k;
  248. ULONG Base, Limit, AddressSpace;
  249. PUSHORT CompatibleList;
  250. Addresses = HalpAllocateNewRangeList();
  251. ExtTable = HalpMpInfoTable.ExtensionTable;
  252. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  253. //
  254. // Is this an address map entry for the proper bus?
  255. //
  256. if (ExtTable->Type == EXTTYPE_BUS_ADDRESS_MAP &&
  257. ExtTable->u.AddressMap.BusId == MpsBusId) {
  258. //
  259. // Find range type
  260. //
  261. for (i=0; HalpMpsRangeList[i].Offset; i++) {
  262. if (HalpMpsRangeList[i].MpsType == ExtTable->u.AddressMap.Type) {
  263. HRange = RANGE_LIST(Addresses, i);
  264. break;
  265. }
  266. }
  267. AddressSpace = HalpMpsRangeList[i].MpsType == MPS_ADDRESS_MAP_IO ? 1 : 0;
  268. if (HalpMpsRangeList[i].Offset) {
  269. HalpAddRange (
  270. HRange,
  271. AddressSpace,
  272. 0, // SystemBase
  273. ExtTable->u.AddressMap.Base,
  274. ExtTable->u.AddressMap.Base + ExtTable->u.AddressMap.Length - 1
  275. );
  276. } else {
  277. DBGMSG ("HALMPS: Unkown address range type in MPS table\n");
  278. }
  279. }
  280. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  281. }
  282. //
  283. // See if the BIOS wants to modify the buses supported addresses with
  284. // some pre-defined default information. (yes, another case where the
  285. // bios wants to be lazy.)
  286. //
  287. ExtTable = HalpMpInfoTable.ExtensionTable;
  288. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  289. //
  290. // Is this an CompatibleMap entry for the proper bus?
  291. //
  292. if (ExtTable->Type == EXTTYPE_BUS_COMPATIBLE_MAP &&
  293. ExtTable->u.CompatibleMap.BusId == MpsBusId) {
  294. //
  295. // All currently defined default tables are for IO ranges,
  296. // we'll use that assumption here.
  297. //
  298. i = 0;
  299. ASSERT (HalpMpsRangeList[i].MpsType == MPS_ADDRESS_MAP_IO);
  300. HRange = RANGE_LIST(Addresses, i);
  301. AddressSpace = 1;
  302. CompatibleList = NULL;
  303. switch (ExtTable->u.CompatibleMap.List) {
  304. case 0: CompatibleList = HalpIoCompatibleRangeList0; break;
  305. case 1: CompatibleList = HalpIoCompatibleRangeList1; break;
  306. default: DBGMSG ("HAL: Unknown compatible range list\n"); continue; break;
  307. }
  308. for (j=0; j < 0x10; j++) {
  309. for (k=0; CompatibleList[k]; k += 2) {
  310. Base = (j << 12) | CompatibleList[k];
  311. Limit = (j << 12) | CompatibleList[k+1];
  312. if (ExtTable->u.CompatibleMap.Modifier) {
  313. HalpRemoveRange (HRange, Base, Limit);
  314. } else {
  315. HalpAddRange (HRange, AddressSpace, 0, Base, Limit);
  316. }
  317. }
  318. }
  319. }
  320. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  321. }
  322. return Addresses;
  323. }
  324. NTSTATUS
  325. HalpAddEisaBus (
  326. PBUS_HANDLER Bus
  327. )
  328. /*++
  329. Routine Description:
  330. Adds another EISA bus handler to the system.
  331. Note: this is used for ISA buses as well - they are added as eisa
  332. buses, then cloned into isa bus handlers
  333. --*/
  334. {
  335. Bus->GetBusData = HalpGetEisaData;
  336. Bus->GetInterruptVector = HalpGetEisaInterruptVector;
  337. Bus->AdjustResourceList = HalpAdjustEisaResourceList;
  338. Bus->BusAddresses->Version = BUS_SUPPORTED_RANGE_VERSION;
  339. Bus->BusAddresses->Dma.Limit = 7;
  340. Bus->BusAddresses->Memory.Limit = 0xFFFFFFFF;
  341. Bus->BusAddresses->IO.Limit = 0xFFFF;
  342. Bus->BusAddresses->IO.SystemAddressSpace = 1;
  343. Bus->BusAddresses->PrefetchMemory.Base = 1;
  344. return STATUS_SUCCESS;
  345. }
  346. NTSTATUS
  347. HalpAddPciBus (
  348. PBUS_HANDLER Bus
  349. )
  350. {
  351. //
  352. // The firmware should have informed NT how many PCI buses
  353. // there where at NtDetect time
  354. //
  355. DBGMSG ("HAL: BIOS problem. PCI bus must be report via IS_PCI_PRESENT bios call\n");
  356. return STATUS_UNSUCCESSFUL;
  357. }
  358. PBUS_HANDLER
  359. HalpLookupCreateHandlerForBus (
  360. IN PPCMPBUSTRANS pBusType,
  361. IN ULONG BusNo
  362. )
  363. {
  364. NTSTATUS Status;
  365. PBUS_HANDLER Handler;
  366. Handler = HaliHandlerForBus (pBusType->NtType, BusNo);
  367. if (!Handler && pBusType->NewInstance) {
  368. //
  369. // This bus does not exist, but we know how to add it.
  370. //
  371. Status = HalRegisterBusHandler (
  372. pBusType->NtType,
  373. pBusType->NtConfig,
  374. BusNo,
  375. Internal, // parent bus
  376. 0,
  377. pBusType->BusExtensionSize,
  378. pBusType->NewInstance,
  379. &Handler
  380. );
  381. if (!NT_SUCCESS(Status)) {
  382. Handler = NULL;
  383. }
  384. }
  385. return Handler;
  386. }
  387. VOID
  388. HalpDetectInvalidAddressOverlaps(
  389. VOID
  390. )
  391. {
  392. ULONG i, j, k;
  393. PBUS_HANDLER Bus1, Bus2;
  394. PSUPPORTED_RANGE Entry;
  395. PSUPPORTED_RANGES NewRange;
  396. //
  397. // Find root PCI buses and detect invalid address overlaps
  398. //
  399. for(i=0; Bus1 = HaliHandlerForBus(PCIBus, i); ++i) {
  400. if (((Bus1->ParentHandler) &&
  401. (Bus1->ParentHandler->InterfaceType != Internal)) ||
  402. !(Bus1->BusAddresses)) {
  403. continue;
  404. }
  405. for(j=i+1; Bus2 = HaliHandlerForBus(PCIBus, j); ++j) {
  406. if (((Bus2->ParentHandler) &&
  407. (Bus2->ParentHandler->InterfaceType != Internal)) ||
  408. !(Bus2->BusAddresses)) {
  409. continue;
  410. }
  411. NewRange = HalpMergeRanges(Bus1->BusAddresses, Bus2->BusAddresses);
  412. HalpConsolidateRanges(NewRange);
  413. for(k=0; HalpMpsRangeList[k].Offset; k++) {
  414. Entry = RANGE_LIST(NewRange, k);
  415. while (Entry) {
  416. if (Entry->Limit != 0) {
  417. // KeBugCheck(HAL_INITIALIZATION_FAILED);
  418. DbgPrint("HalpDetectInvalidAddressOverlaps: Address Overlap Detected\n");
  419. break;
  420. } else {
  421. Entry = Entry->Next;
  422. }
  423. }
  424. }
  425. HalpFreeRangeList(NewRange);
  426. }
  427. }
  428. }
  429. VOID
  430. HalpInheritBusAddressMapInfo (
  431. VOID
  432. )
  433. /*++
  434. Routine Description:
  435. Reads MPS bus hierarchy descriptors and inherits any implied bus
  436. address mapping information.
  437. Note there's a little slop in this function as it doesn't reclaim
  438. memory allocated before this function is called, which it replaces
  439. pointers too.
  440. --*/
  441. {
  442. ULONG BusNo, i, j;
  443. PPCMPBUSTRANS pBusType;
  444. PMPS_EXTENTRY ExtTable;
  445. PBUS_HANDLER Bus, Bus2;
  446. PSUPPORTED_RANGES Addresses;
  447. PUCHAR p;
  448. //
  449. // Search for any bus hierarchy descriptors and inherit supported address
  450. // ranges accordingly.
  451. //
  452. ExtTable = HalpMpInfoTable.ExtensionTable;
  453. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  454. //
  455. // Is this a bus hierarchy descriptor?
  456. //
  457. if (ExtTable->Type == EXTTYPE_BUS_HIERARCHY) {
  458. //
  459. // Determine the NT bus
  460. //
  461. if (HalpMPSBusId2NtBusId (ExtTable->u.BusHierarchy.BusId, &pBusType, &BusNo)) {
  462. Bus = HalpLookupCreateHandlerForBus (pBusType, BusNo);
  463. if (Bus) {
  464. //
  465. // Get ranges from parent
  466. //
  467. Addresses = HalpMergeRangesFromParent (
  468. Bus->BusAddresses,
  469. ExtTable->u.BusHierarchy.ParentBusId
  470. );
  471. //
  472. // Set bus'es support addresses
  473. //
  474. Bus->BusAddresses = HalpConsolidateRanges (Addresses);
  475. } else {
  476. DBGMSG ("HAL: Inherit BUS address map - bus not an registered NT bus\n");
  477. }
  478. } else {
  479. DBGMSG ("HAL: Inherit BUS address map - unkown MPS bus type\n");
  480. }
  481. }
  482. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  483. }
  484. //
  485. // Clone EISA bus ranges to matching ISA buses
  486. //
  487. BusNo = 0;
  488. for (; ;) {
  489. Bus = HaliHandlerForBus(Eisa, BusNo);
  490. Bus2 = HaliHandlerForBus(Isa , BusNo);
  491. if (!Bus) {
  492. break;
  493. }
  494. if (!Bus2) {
  495. //
  496. // Matching ISA bus didn't exist, create it
  497. //
  498. HalRegisterBusHandler (
  499. Isa,
  500. ConfigurationSpaceUndefined,
  501. BusNo,
  502. Eisa, // parent bus
  503. BusNo,
  504. 0,
  505. NULL,
  506. &Bus2
  507. );
  508. Bus2->GetBusData = HalpNoBusData;
  509. Bus2->TranslateBusAddress = HalpTranslateIsaBusAddress;
  510. }
  511. //
  512. // Copy its parent bus ranges
  513. //
  514. Addresses = HalpCopyRanges (Bus->BusAddresses);
  515. //
  516. // Pull out memory ranges above the isa 24 bit supported ranges
  517. //
  518. HalpRemoveRange (
  519. &Addresses->Memory,
  520. 0x1000000,
  521. 0x7FFFFFFFFFFFFFFF
  522. );
  523. HalpRemoveRange (
  524. &Addresses->PrefetchMemory,
  525. 0x1000000,
  526. 0x7FFFFFFFFFFFFFFF
  527. );
  528. Bus2->BusAddresses = HalpConsolidateRanges (Addresses);
  529. BusNo += 1;
  530. }
  531. //
  532. // Inherit any implied interrupt routing from parent PCI buses
  533. //
  534. HalpMPSPCIChildren ();
  535. HalpDetectInvalidAddressOverlaps();
  536. #if DBG
  537. if (HalDebug) {
  538. HalpDisplayAllBusRanges ();
  539. }
  540. #endif
  541. }
  542. STATIC PSUPPORTED_RANGES
  543. HalpMergeRangesFromParent (
  544. IN PSUPPORTED_RANGES CurrentList,
  545. IN UCHAR MpsBusId
  546. )
  547. /*++
  548. Routine Description:
  549. Shrinks this CurrentList to include only the ranges also
  550. supported by the supplied MPS bus id.
  551. Arguments:
  552. CurrentList - Current supported range list
  553. MpsBusId - mps bus id of bus to merge with
  554. Return:
  555. The bus'es supported ranges as defined by the orignal list,
  556. shrunk by all parents buses supported ranges as defined by
  557. the MPS hierarchy descriptors
  558. --*/
  559. {
  560. ULONG BusNo;
  561. PPCMPBUSTRANS pBusType;
  562. PMPS_EXTENTRY ExtTable;
  563. PBUS_HANDLER Bus;
  564. PSUPPORTED_RANGES NewList, MergeList, MpsBusList;
  565. BOOLEAN FoundParentBus;
  566. ULONG i;
  567. FoundParentBus = FALSE;
  568. MergeList = NULL;
  569. MpsBusList = NULL;
  570. //
  571. // Determine the NT bus
  572. //
  573. if (HalpMPSBusId2NtBusId (MpsBusId, &pBusType, &BusNo)) {
  574. //
  575. // Lookup the bushander for the bus
  576. //
  577. Bus = HaliHandlerForBus (pBusType->NtType, BusNo);
  578. if (Bus) {
  579. MergeList = Bus->BusAddresses;
  580. }
  581. }
  582. //
  583. // If NT bus not found, use supported range list from MPS bus
  584. // address map descriptors
  585. //
  586. if (!MergeList) {
  587. MpsBusList = HalpBuildBusAddressMap(MpsBusId);
  588. MergeList = MpsBusList;
  589. }
  590. //
  591. // If no list to merge with use CurrentList
  592. //
  593. if (!MergeList) {
  594. return CurrentList;
  595. }
  596. if (!CurrentList) {
  597. //
  598. // If no CurrentList, then nothing to merge with
  599. //
  600. NewList = HalpCopyRanges (MergeList);
  601. } else {
  602. //
  603. // Merge lists together and build a new list
  604. //
  605. NewList = HalpMergeRanges (
  606. CurrentList,
  607. MergeList
  608. );
  609. //
  610. // MPS doesn't define DMA ranges, so we don't
  611. // merge those down.. Add valid DMA ranges back
  612. //
  613. HalpAddRangeList (&NewList->Dma, &CurrentList->Dma);
  614. }
  615. //
  616. // See if bus has parent bus listed in the bus hierarchy descriptors
  617. //
  618. ExtTable = HalpMpInfoTable.ExtensionTable;
  619. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  620. if (ExtTable->Type == EXTTYPE_BUS_HIERARCHY &&
  621. ExtTable->u.BusHierarchy.BusId == MpsBusId) {
  622. //
  623. // BIOS can only list one parent per bus
  624. //
  625. ASSERT (FoundParentBus == FALSE);
  626. FoundParentBus = TRUE;
  627. //
  628. // Merge current list with parent's supported range list
  629. //
  630. CurrentList = NewList;
  631. NewList = HalpMergeRangesFromParent (
  632. CurrentList,
  633. ExtTable->u.BusHierarchy.ParentBusId
  634. );
  635. //
  636. // Free old list
  637. //
  638. HalpFreeRangeList (CurrentList);
  639. }
  640. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  641. }
  642. //
  643. // Clean up
  644. //
  645. if (MpsBusList) {
  646. HalpFreeRangeList (MpsBusList);
  647. }
  648. return NewList;
  649. }
  650. NTSTATUS
  651. HalpMpsGetParentBus(
  652. IN UCHAR MpsBus,
  653. OUT UCHAR *ParentMpsBus
  654. )
  655. {
  656. PMPS_EXTENTRY ExtTable;
  657. PAGED_CODE();
  658. ExtTable = HalpMpInfoTable.ExtensionTable;
  659. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  660. //
  661. // Is this a bus hierarchy descriptor?
  662. //
  663. if (ExtTable->Type == EXTTYPE_BUS_HIERARCHY) {
  664. if (ExtTable->u.BusHierarchy.BusId == MpsBus) {
  665. *ParentMpsBus = ExtTable->u.BusHierarchy.ParentBusId;
  666. return STATUS_SUCCESS;
  667. }
  668. }
  669. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  670. }
  671. return STATUS_NOT_FOUND;
  672. }
  673. BOOLEAN
  674. HalpMpsBusIsRootBus(
  675. IN UCHAR MpsBus
  676. )
  677. //
  678. // The criteria for a Root Bus are as follows:
  679. //
  680. // 1.1 and 1.4 BIOS:
  681. //
  682. // 1) The bus is number 0.
  683. //
  684. //
  685. // 1.4 BIOS only:
  686. //
  687. // 2) The bus does not have a parent.
  688. //
  689. // 3) The bus has address descriptors, if
  690. // there are any present in the machine.
  691. //
  692. //
  693. // 4) Last resort. Scan all possible parent busses
  694. // looking for a bridge that generates this bus.
  695. //
  696. #define BRIDGE_HEADER_BUFFER_SIZE (FIELD_OFFSET(PCI_COMMON_CONFIG, u.type1.SubordinateBus) + 1)
  697. {
  698. NTSTATUS status;
  699. UCHAR parentBus;
  700. PMPS_EXTENTRY ExtTable;
  701. BOOLEAN biosContainsAddressInfo = FALSE;
  702. UCHAR parentPci, childPci;
  703. PCI_SLOT_NUMBER bridgeSlot;
  704. PCI_COMMON_CONFIG pciData;
  705. ULONG bytesRead, d, f;
  706. PPCMPBUSTRANS busType;
  707. ULONG busNumber;
  708. PAGED_CODE();
  709. if (MpsBus == 0) {
  710. return TRUE;
  711. }
  712. //
  713. // Check to see if this MPS bus, though not
  714. // itself numbered 0, represents a bus that
  715. // is numbered 0.
  716. //
  717. if (HalpMPSBusId2NtBusId(MpsBus,
  718. &busType,
  719. &busNumber)) {
  720. if (busNumber == 0) {
  721. return TRUE;
  722. }
  723. }
  724. if (PcMpTablePtr->Revision >= 4) {
  725. if (NT_SUCCESS(HalpMpsGetParentBus(MpsBus,&parentBus))) {
  726. return FALSE;
  727. }
  728. ExtTable = HalpMpInfoTable.ExtensionTable;
  729. while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
  730. if ((ExtTable->Type == EXTTYPE_BUS_ADDRESS_MAP) ||
  731. (ExtTable->Type == EXTTYPE_BUS_COMPATIBLE_MAP)) {
  732. biosContainsAddressInfo = TRUE;
  733. if (ExtTable->u.AddressMap.BusId == MpsBus) {
  734. //
  735. // This entry corresponds to the bus that
  736. // we care about.
  737. //
  738. return TRUE;
  739. }
  740. }
  741. ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
  742. }
  743. //
  744. // Compaq machines have their own special ways to be busted. So,
  745. // when dealing with Compaq, never believe their MP table at all.
  746. // Go straight to probing the hardware.
  747. //
  748. if (!strstr(PcMpTablePtr->OemId, "COMPAQ")) {
  749. //
  750. // If this is not Compaq, assume that probing the hardware
  751. // is not yet necessary.
  752. //
  753. if (biosContainsAddressInfo) {
  754. //
  755. // Some bus in this machine contained address
  756. // info, but ours didn't.
  757. //
  758. return FALSE;
  759. }
  760. //
  761. // We can't figure out much from the MPS tables.
  762. //
  763. status = HalpPci2MpsBusNumber(MpsBus,
  764. &childPci);
  765. //
  766. // This wasn't a PCI bus. Guess that it is a root.
  767. //
  768. if (!NT_SUCCESS(status)) {
  769. return TRUE;
  770. }
  771. }
  772. }
  773. //
  774. // This is a PCI bus, so scan the other PCI busses looking
  775. // for it's parent.
  776. //
  777. childPci = MpsBus;
  778. parentPci = childPci - 1;
  779. while (TRUE) {
  780. //
  781. // Find the bridge.
  782. //
  783. bridgeSlot.u.AsULONG = 0;
  784. for (d = 0; d < PCI_MAX_DEVICES; d++) {
  785. for (f = 0; f < PCI_MAX_FUNCTION; f++) {
  786. bridgeSlot.u.bits.DeviceNumber = d;
  787. bridgeSlot.u.bits.FunctionNumber = f;
  788. bytesRead = HalGetBusDataByOffset(PCIConfiguration,
  789. parentPci,
  790. bridgeSlot.u.AsULONG,
  791. &pciData,
  792. 0,
  793. BRIDGE_HEADER_BUFFER_SIZE);
  794. if (bytesRead == (ULONG)BRIDGE_HEADER_BUFFER_SIZE) {
  795. if ((pciData.VendorID != PCI_INVALID_VENDORID) &&
  796. (PCI_CONFIGURATION_TYPE((&pciData)) != PCI_DEVICE_TYPE)) {
  797. //
  798. // This is a bridge of some sort.
  799. //
  800. if (pciData.u.type1.SecondaryBus == childPci) {
  801. //
  802. // It is also the bridge that creates the
  803. // PCI bus. Thus this isn't a root.
  804. return FALSE;
  805. }
  806. }
  807. }
  808. }
  809. }
  810. //
  811. // No bridge found. Must be a root.
  812. //
  813. if (parentPci == 0) {
  814. return TRUE;
  815. }
  816. parentPci--;
  817. }
  818. }