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.

2016 lines
61 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pmpcibus.c
  5. Abstract:
  6. Implements simplified PCI configuration
  7. read and write functions for use in
  8. an ACPI HAL.
  9. Author:
  10. Jake Oshins (jakeo) 1-Dec-1997
  11. Chris Hyser (chrish@fc.hp.com) 23-Jun-1997
  12. Neal Vu (neal.vu@intel.com) 11-Jul-2000
  13. Environment:
  14. Kernel mode only.
  15. Revision History:
  16. --*/
  17. #include "halp.h"
  18. #include "pci.h"
  19. #include "pcip.h"
  20. #define MAX(a, b) \
  21. ((a) > (b) ? (a) : (b))
  22. #define MIN(a, b) \
  23. ((a) < (b) ? (a) : (b))
  24. NTSTATUS
  25. HalpSearchForPciDebuggingDevice(
  26. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice,
  27. IN ULONG StartBusNumber,
  28. IN ULONG EndBusNumber,
  29. IN ULONG MinMem,
  30. IN ULONG MaxMem,
  31. IN USHORT MinIo,
  32. IN USHORT MaxIo,
  33. IN BOOLEAN ConfigureBridges
  34. );
  35. PCIPBUSDATA HalpFakePciBusData = {
  36. {
  37. PCI_DATA_TAG,//Tag
  38. PCI_DATA_VERSION,//Version
  39. (PciReadWriteConfig)HalpReadPCIConfig,//ReadConfig
  40. (PciReadWriteConfig) HalpWritePCIConfig,//WriteConfig
  41. (PciPin2Line)HalpPCIPin2ISALine,//Pin2Line
  42. (PciLine2Pin)HalpPCIISALine2Pin,//Line2Pin
  43. {0},//ParentSlot
  44. NULL,NULL,NULL,NULL//Reserved[4]
  45. },
  46. {0},//Config
  47. PCI_MAX_DEVICES,//MaxDevice
  48. };
  49. BUS_HANDLER HalpFakePciBusHandler = {
  50. BUS_HANDLER_VERSION,//Version
  51. PCIBus,//InterfaceType
  52. PCIConfiguration,//ConfigurationType
  53. 0,//BusNumber
  54. NULL,//DeviceObject
  55. NULL,//ParentHandler
  56. (PPCIBUSDATA)&HalpFakePciBusData,//BusData
  57. 0,//DeviceControlExtensionSize
  58. NULL,//BusAddresses
  59. {0},//Reserved[4]
  60. (PGETSETBUSDATA)HalpGetPCIData,//GetBusData
  61. (PGETSETBUSDATA)HalpSetPCIData,//SetBusData
  62. NULL,//AdjustResourceList
  63. (PASSIGNSLOTRESOURCES)HalpAssignPCISlotResources,//AssignSlotResources
  64. NULL,//GetInterruptVector
  65. NULL,//TranslateBusAddress
  66. };
  67. ULONG HalpMinPciBus = 0;
  68. ULONG HalpMaxPciBus = 0;
  69. #define MAX_DEBUGGING_DEVICES_SUPPORTED 2
  70. PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[MAX_DEBUGGING_DEVICES_SUPPORTED] = {0};
  71. PVOID
  72. HalpGetAcpiTablePhase0(
  73. IN PLOADER_PARAMETER_BLOCK LoaderBlock,
  74. IN ULONG Signature
  75. );
  76. VOID
  77. HalpFindFreeResourceLimits(
  78. IN ULONG Bus,
  79. IN OUT ULONG *MinIo,
  80. IN OUT ULONG *MaxIo,
  81. IN OUT ULONG *MinMem,
  82. IN OUT ULONG *MaxMem,
  83. IN OUT ULONG *MinBus,
  84. IN OUT ULONG *MaxBus
  85. );
  86. NTSTATUS
  87. HalpSetupUnconfiguredDebuggingDevice(
  88. IN ULONG Bus,
  89. IN ULONG Slot,
  90. IN ULONG IoMin,
  91. IN ULONG IoMax,
  92. IN ULONG MemMin,
  93. IN ULONG MemMax,
  94. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
  95. );
  96. NTSTATUS
  97. HalpConfigurePciBridge(
  98. IN PDEBUG_DEVICE_DESCRIPTOR PciDevice,
  99. IN ULONG Bus,
  100. IN ULONG Slot,
  101. IN ULONG IoMin,
  102. IN ULONG IoMax,
  103. IN ULONG MemMin,
  104. IN ULONG MemMax,
  105. IN ULONG BusMin,
  106. IN ULONG BusMax,
  107. IN OUT PPCI_COMMON_CONFIG PciData
  108. );
  109. VOID
  110. HalpUnconfigurePciBridge(
  111. IN ULONG Bus,
  112. IN ULONG Slot
  113. );
  114. VOID
  115. HalpRegisterKdSupportFunctions(
  116. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  117. );
  118. VOID
  119. HalpRegisterPciDebuggingDeviceInfo(
  120. VOID
  121. );
  122. ULONG
  123. HalpPhase0GetPciDataByOffset (
  124. ULONG BusNumber,
  125. ULONG SlotNumber,
  126. PVOID Buffer,
  127. ULONG Offset,
  128. ULONG Length
  129. );
  130. ULONG
  131. HalpPhase0SetPciDataByOffset (
  132. ULONG BusNumber,
  133. ULONG SlotNumber,
  134. PVOID Buffer,
  135. ULONG Offset,
  136. ULONG Length
  137. );
  138. NTSTATUS
  139. HalpReleasePciDeviceForDebugging(
  140. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
  141. );
  142. NTSTATUS
  143. HalpSetupPciDeviceForDebugging(
  144. IN PLOADER_PARAMETER_BLOCK LoaderBlock, OPTIONAL
  145. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
  146. );
  147. #ifdef ALLOC_PRAGMA
  148. #pragma alloc_text(INIT,HalpInitializePciBus)
  149. #pragma alloc_text(INIT,HalpRegisterKdSupportFunctions)
  150. #pragma alloc_text(INIT,HalpRegisterPciDebuggingDeviceInfo)
  151. #pragma alloc_text(PAGELK,HalpConfigurePciBridge)
  152. #pragma alloc_text(PAGELK,HalpFindFreeResourceLimits)
  153. #pragma alloc_text(PAGELK,HalpPhase0GetPciDataByOffset)
  154. #pragma alloc_text(PAGELK,HalpPhase0SetPciDataByOffset)
  155. #pragma alloc_text(PAGELK,HalpReleasePciDeviceForDebugging)
  156. #pragma alloc_text(PAGELK,HalpSearchForPciDebuggingDevice)
  157. #pragma alloc_text(PAGELK,HalpSetupPciDeviceForDebugging)
  158. #pragma alloc_text(PAGELK,HalpSetupUnconfiguredDebuggingDevice)
  159. #pragma alloc_text(PAGELK,HalpUnconfigurePciBridge)
  160. #endif
  161. VOID
  162. HalpInitializePciBus (
  163. VOID
  164. )
  165. {
  166. PPCIPBUSDATA BusData;
  167. UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
  168. RtlZeroMemory(&HalpFakePciBusHandler, sizeof(BUS_HANDLER));
  169. HalpFakePciBusHandler.Version = BUS_HANDLER_VERSION;
  170. HalpFakePciBusHandler.InterfaceType = PCIBus;
  171. HalpFakePciBusHandler.ConfigurationType = PCIConfiguration;
  172. //
  173. // Fill in PCI handlers
  174. //
  175. HalpFakePciBusHandler.GetBusData = (PGETSETBUSDATA) HalpGetPCIData;
  176. HalpFakePciBusHandler.SetBusData = (PGETSETBUSDATA) HalpSetPCIData;
  177. HalpFakePciBusHandler.AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources;
  178. HalpFakePciBusHandler.BusData = &HalpFakePciBusData;
  179. BusData = (PPCIPBUSDATA) HalpFakePciBusHandler.BusData;
  180. //
  181. // Fill in common PCI data
  182. //
  183. BusData->CommonData.Tag = PCI_DATA_TAG;
  184. BusData->CommonData.Version = PCI_DATA_VERSION;
  185. BusData->CommonData.ReadConfig = (PciReadWriteConfig) HalpReadPCIConfig;
  186. BusData->CommonData.WriteConfig = (PciReadWriteConfig) HalpWritePCIConfig;
  187. BusData->CommonData.Pin2Line = (PciPin2Line) HalpPCIPin2ISALine;
  188. BusData->CommonData.Line2Pin = (PciLine2Pin) HalpPCIISALine2Pin;
  189. //
  190. // Set defaults
  191. //
  192. BusData->MaxDevice = PCI_MAX_DEVICES;
  193. //
  194. // There used to be a switch statment on HwType which installed
  195. // different handlers based on PCI Configuration Type. This
  196. // has been removed since SAL is always used for IA64.
  197. //
  198. }
  199. ULONG
  200. HaliPciInterfaceReadConfig(
  201. IN PVOID Context,
  202. IN UCHAR BusOffset,
  203. IN ULONG Slot,
  204. IN PVOID Buffer,
  205. IN ULONG Offset,
  206. IN ULONG Length
  207. )
  208. {
  209. PCI_SLOT_NUMBER slotNum;
  210. BUS_HANDLER busHand;
  211. UNREFERENCED_PARAMETER(Context);
  212. slotNum.u.AsULONG = Slot;
  213. //
  214. // Fake a bus handler.
  215. //
  216. RtlCopyMemory(&busHand, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
  217. //
  218. // Calculate the right bus number.
  219. //
  220. busHand.BusNumber = BusOffset;
  221. HalpReadPCIConfig(&busHand,
  222. slotNum,
  223. Buffer,
  224. Offset,
  225. Length
  226. );
  227. //
  228. // This is a hack. The legacy HAL interfaces need to be able
  229. // to distinguish between busses that exist and busses that
  230. // don't. And many users of the legacy interfaces implicitly
  231. // assume that PCI busses are tightly packed. (i.e. All busses
  232. // between the lowest numbered one and the highest numbered one
  233. // exist.) So here we are keeping track of the highest numbered
  234. // bus that we have seen so far.
  235. //
  236. if ((Length >= 2) &&
  237. (((PPCI_COMMON_CONFIG)Buffer)->VendorID != PCI_INVALID_VENDORID)) {
  238. //
  239. // This is a valid device.
  240. //
  241. if (busHand.BusNumber > HalpMaxPciBus) {
  242. //
  243. // This is the highest numbered bus we have
  244. // yet seen.
  245. //
  246. HalpMaxPciBus = busHand.BusNumber;
  247. }
  248. }
  249. return Length;
  250. }
  251. ULONG
  252. HaliPciInterfaceWriteConfig(
  253. IN PVOID Context,
  254. IN UCHAR BusOffset,
  255. IN ULONG Slot,
  256. IN PVOID Buffer,
  257. IN ULONG Offset,
  258. IN ULONG Length
  259. )
  260. {
  261. PCI_SLOT_NUMBER slotNum;
  262. BUS_HANDLER busHand;
  263. UNREFERENCED_PARAMETER(Context);
  264. slotNum.u.AsULONG = Slot;
  265. //
  266. // Fake a bus handler.
  267. //
  268. RtlCopyMemory(&busHand, &HalpFakePciBusHandler, sizeof(BUS_HANDLER));
  269. //
  270. // Calculate the right bus number.
  271. //
  272. busHand.BusNumber = BusOffset;
  273. HalpWritePCIConfig(&busHand,
  274. slotNum,
  275. Buffer,
  276. Offset,
  277. Length
  278. );
  279. return Length;
  280. }
  281. VOID
  282. HalpPCIPin2ISALine (
  283. IN PBUS_HANDLER BusHandler,
  284. IN PBUS_HANDLER RootHandler,
  285. IN PCI_SLOT_NUMBER SlotNumber,
  286. IN PPCI_COMMON_CONFIG PciData
  287. )
  288. /*++
  289. This function maps the device's InterruptPin to an InterruptLine
  290. value.
  291. On the current PC implementations, the bios has already filled in
  292. InterruptLine as it's ISA value and there's no portable way to
  293. change it.
  294. On a DBG build we adjust InterruptLine just to ensure driver's
  295. don't connect to it without translating it on the PCI bus.
  296. --*/
  297. {
  298. if (!PciData->u.type0.InterruptPin) {
  299. return ;
  300. }
  301. HalDebugPrint(( HAL_INFO, "HAL: HalpPCIPin2ISALine - non-zero InterruptPin value\n" ));
  302. }
  303. VOID
  304. HalpPCIISALine2Pin (
  305. IN PBUS_HANDLER BusHandler,
  306. IN PBUS_HANDLER RootHandler,
  307. IN PCI_SLOT_NUMBER SlotNumber,
  308. IN PPCI_COMMON_CONFIG PciNewData,
  309. IN PPCI_COMMON_CONFIG PciOldData
  310. )
  311. /*++
  312. This functions maps the device's InterruptLine to it's
  313. device specific InterruptPin value.
  314. On the current PC implementations, this information is
  315. fixed by the BIOS. Just make sure the value isn't being
  316. editted since PCI doesn't tell us how to dynically
  317. connect the interrupt.
  318. --*/
  319. {
  320. if (!PciNewData->u.type0.InterruptPin) {
  321. return ;
  322. }
  323. }
  324. VOID
  325. HalpSetMaxLegacyPciBusNumber(
  326. IN ULONG BusNumber
  327. )
  328. /*++
  329. Routine Description:
  330. This routine bumps the Legacy PCI bus maximum up to whatever
  331. is passed in. This may be necessary because the ACPI driver
  332. needs to run a configuration cycle to a PCI device before the
  333. PCI driver loads. This happens mostly in the context of a
  334. _REG method.
  335. Arguments:
  336. BusNumber - max PCI bus number
  337. Return Value:
  338. none
  339. --*/
  340. {
  341. if (BusNumber > HalpMaxPciBus) {
  342. HalpMaxPciBus = BusNumber;
  343. }
  344. }
  345. ULONG
  346. HalpPhase0SetPciDataByOffset (
  347. ULONG BusNumber,
  348. ULONG SlotNumber,
  349. PVOID Buffer,
  350. ULONG Offset,
  351. ULONG Length
  352. )
  353. /*++
  354. Routine Description:
  355. This routine writes to PCI configuration space prior to bus handler
  356. installation.
  357. Arguments:
  358. BusNumber PCI Bus Number. This is the 8 bit BUS Number which is
  359. bits 23-16 of the Configuration Address. In support of
  360. multiple top level busses, the upper 24 bits of this
  361. argument will supply the index into the table of
  362. configuration address registers.
  363. SlotNumber PCI Slot Number, 8 bits composed of the 5 bit device
  364. number (bits 15-11 of the configuration address) and
  365. the 3 bit function number (10-8).
  366. Buffer Address of source data.
  367. Offset Number of bytes to skip from base of PCI config area.
  368. Length Number of bytes to write
  369. Return Value:
  370. Returns length of data written.
  371. Notes:
  372. Caller is responsible for acquiring any necessary PCI config
  373. spinlocks.
  374. --*/
  375. {
  376. PCI_TYPE1_CFG_BITS ConfigAddress;
  377. ULONG ReturnLength;
  378. PCI_SLOT_NUMBER slot;
  379. PUCHAR Bfr = (PUCHAR)Buffer;
  380. SAL_PAL_RETURN_VALUES RetVals;
  381. SAL_STATUS Stat;
  382. ASSERT(!(Offset & ~0xff));
  383. ASSERT(Length);
  384. ASSERT((Offset + Length) <= 256);
  385. if ( Length + Offset > 256 ) {
  386. if ( Offset > 256 ) {
  387. return 0;
  388. }
  389. Length = 256 - Offset;
  390. }
  391. ReturnLength = Length;
  392. slot.u.AsULONG = SlotNumber;
  393. ConfigAddress.u.AsULONG = 0;
  394. ConfigAddress.u.bits.BusNumber = BusNumber;
  395. ConfigAddress.u.bits.DeviceNumber = slot.u.bits.DeviceNumber;
  396. ConfigAddress.u.bits.FunctionNumber = slot.u.bits.FunctionNumber;
  397. ConfigAddress.u.bits.RegisterNumber = (Offset & 0xfc) >> 2;
  398. //ConfigAddress.u.bits.Enable = TRUE; // This is actually segment on IA64
  399. if ( Offset & 0x3 ) {
  400. //
  401. // Access begins at a non-register boundary in the config
  402. // space. We need to read the register containing the data
  403. // and rewrite only the changed data. (I wonder if this
  404. // ever really happens?)
  405. //
  406. ULONG SubOffset = Offset & 0x3;
  407. ULONG SubLength = 4 - SubOffset;
  408. union {
  409. ULONG All;
  410. UCHAR Bytes[4];
  411. } Tmp;
  412. if ( SubLength > Length ) {
  413. SubLength = Length;
  414. }
  415. //
  416. // Adjust Length (remaining) and (new) Offset by amount covered
  417. // in this first word.
  418. //
  419. Length -= SubLength;
  420. Offset += SubLength;
  421. //
  422. // Get the first word (register), replace only those bytes that
  423. // need to be changed, then write the whole thing back out again.
  424. //
  425. Stat = HalpSalCall(SAL_PCI_CONFIG_READ, ConfigAddress.u.AsULONG, 4, 0, 0, 0, 0, 0, &RetVals);
  426. if (Stat < 0 ) {
  427. return(0);
  428. }
  429. Tmp.All = (ULONG)RetVals.ReturnValues[1];
  430. while ( SubLength-- ) {
  431. Tmp.Bytes[SubOffset++] = *Bfr++;
  432. }
  433. Stat = HalpSalCall(SAL_PCI_CONFIG_WRITE, ConfigAddress.u.AsULONG, 4, Tmp.All, 0, 0, 0, 0, &RetVals);
  434. if (Stat < 0 ) {
  435. return(0);
  436. }
  437. //
  438. // Aim ConfigAddressRegister at the next word (register).
  439. //
  440. ConfigAddress.u.bits.RegisterNumber++;
  441. }
  442. //
  443. // Do the majority of the transfer 4 bytes at a time.
  444. //
  445. while ( Length > sizeof(ULONG) ) {
  446. ULONG Tmp = *(PULONG)Bfr;
  447. Stat = HalpSalCall(SAL_PCI_CONFIG_WRITE, ConfigAddress.u.AsULONG, 4, Tmp, 0, 0, 0, 0, &RetVals);
  448. if (Stat < 0 ) {
  449. return(ReturnLength - Length);
  450. }
  451. ConfigAddress.u.bits.RegisterNumber++;
  452. Bfr += sizeof(ULONG);
  453. Length -= sizeof(ULONG);
  454. }
  455. //
  456. // Do bytes in last register.
  457. //
  458. if ( Length ) {
  459. union {
  460. ULONG All;
  461. UCHAR Bytes[4];
  462. } Tmp;
  463. ULONG i = 0;
  464. while ( Length-- ) {
  465. Tmp.Bytes[i++] = *(PUCHAR)Bfr++;
  466. }
  467. Stat = HalpSalCall(SAL_PCI_CONFIG_WRITE, ConfigAddress.u.AsULONG, 4, Tmp.All, 0, 0, 0, 0, &RetVals);
  468. if (Stat < 0 ) {
  469. return(ReturnLength - i);
  470. }
  471. }
  472. return ReturnLength;
  473. }
  474. ULONG
  475. HalpPhase0GetPciDataByOffset (
  476. ULONG BusNumber,
  477. ULONG SlotNumber,
  478. PVOID Buffer,
  479. ULONG Offset,
  480. ULONG Length
  481. )
  482. /*++
  483. Routine Description:
  484. This routine reads PCI config space prior to bus handlder installation.
  485. Arguments:
  486. BusNumber PCI Bus Number. This is the 8 bit BUS Number which is
  487. bits 23-16 of the Configuration Address. In support of
  488. multiple top level busses, the upper 24 bits of this
  489. argument will supply the index into the table of
  490. configuration address registers.
  491. SlotNumber PCI Slot Number, 8 bits composed of the 5 bit device
  492. number (bits 15-11 of the configuration address) and
  493. the 3 bit function number (10-8).
  494. Buffer Address of source data.
  495. Offset Number of bytes to skip from base of PCI config area.
  496. Length Number of bytes to write
  497. Return Value:
  498. Amount of data read.
  499. --*/
  500. {
  501. PCI_TYPE1_CFG_BITS ConfigAddress;
  502. PCI_TYPE1_CFG_BITS ConfigAddressTemp;
  503. ULONG ReturnLength;
  504. ULONG i;
  505. PCI_SLOT_NUMBER slot;
  506. union {
  507. ULONG All;
  508. UCHAR Bytes[4];
  509. } Tmp;
  510. SAL_PAL_RETURN_VALUES RetVals;
  511. SAL_STATUS Stat;
  512. ASSERT(!(Offset & ~0xff));
  513. ASSERT(Length);
  514. ASSERT((Offset + Length) <= 256);
  515. if ( Length + Offset > 256 ) {
  516. if ( Offset > 256 ) {
  517. return 0;
  518. }
  519. Length = 256 - Offset;
  520. }
  521. ReturnLength = Length;
  522. slot.u.AsULONG = SlotNumber;
  523. ConfigAddress.u.AsULONG = 0;
  524. ConfigAddress.u.bits.BusNumber = BusNumber;
  525. ConfigAddress.u.bits.DeviceNumber = slot.u.bits.DeviceNumber;
  526. ConfigAddress.u.bits.FunctionNumber = slot.u.bits.FunctionNumber;
  527. ConfigAddress.u.bits.RegisterNumber = (Offset & 0xfc) >> 2;
  528. //ConfigAddress.u.bits.Enable = TRUE; // This is actually segment on IA64
  529. //
  530. // If we are being asked to read data when function != 0, check
  531. // first to see if this device decares itself as a multi-function
  532. // device. If it doesn't, don't do this read.
  533. //
  534. if (ConfigAddress.u.bits.FunctionNumber != 0) {
  535. ConfigAddressTemp.u.AsULONG = 0;
  536. ConfigAddressTemp.u.bits.RegisterNumber = 3; // contains header type
  537. ConfigAddressTemp.u.bits.FunctionNumber = 0; // look at base package
  538. ConfigAddressTemp.u.bits.DeviceNumber = ConfigAddress.u.bits.DeviceNumber;
  539. ConfigAddressTemp.u.bits.BusNumber = ConfigAddress.u.bits.BusNumber;
  540. //ConfigAddress.u.bits.Enable = TRUE; // This is actually segment on IA64
  541. Stat = HalpSalCall(SAL_PCI_CONFIG_READ, ConfigAddress.u.AsULONG, 4, 0, 0, 0, 0, 0, &RetVals);
  542. if (Stat < 0 ) {
  543. return(ReturnLength - Length);
  544. }
  545. Tmp.All = (ULONG)RetVals.ReturnValues[1];
  546. if (!(Tmp.Bytes[2] & 0x80)) { // if the Header type field's multi-function bit is not set
  547. for (i = 0; i < Length; i++) {
  548. *((PUCHAR)Buffer)++ = 0xff; // Make this read as if the device isn't populated
  549. }
  550. return Length;
  551. }
  552. }
  553. i = Offset & 0x3;
  554. while ( Length ) {
  555. //
  556. // Make SAL call
  557. //
  558. Stat = HalpSalCall(SAL_PCI_CONFIG_READ, ConfigAddress.u.AsULONG, 4, 0, 0, 0, 0, 0, &RetVals);
  559. if (Stat < 0 ) {
  560. return(ReturnLength - Length);
  561. }
  562. Tmp.All = (ULONG)RetVals.ReturnValues[1];
  563. while ( (i < 4) && Length) {
  564. *((PUCHAR)Buffer)++ = Tmp.Bytes[i];
  565. i++;
  566. Length--;
  567. }
  568. i = 0;
  569. ConfigAddress.u.bits.RegisterNumber++;
  570. }
  571. return ReturnLength;
  572. }
  573. NTSTATUS
  574. HalpSetupPciDeviceForDebugging(
  575. IN PLOADER_PARAMETER_BLOCK LoaderBlock, OPTIONAL
  576. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
  577. )
  578. /*++
  579. Routine Description:
  580. This routine finds and initializes a PCI device to be
  581. used for communicating with a debugger.
  582. The caller fills in as much of DEBUG_DEVICE_DESCRIPTOR
  583. as it cares to, filling unused fields with (-1).
  584. This routine attempts to find a matching PCI device. It
  585. matches first based on Bus and Slot, if the caller has
  586. provided them. Then it matches on VendorID/DeviceID, if
  587. the caller has provided them. Last, it matches on
  588. BaseClass/SubClass.
  589. This routine will fill in any unused fields in the structure
  590. so that the caller can know specifically which PCI
  591. device matched the criteria.
  592. If the matching PCI device is not enabled, or it is
  593. behind a PCI to PCI bridge that is not enabled, this
  594. routine makes a best-effort attempt to find a safe
  595. configuration that allows the device (and possibly bridges)
  596. to function, and enables them.
  597. If the PCI device implements memory mapped Base Address
  598. registers, this function will create a virtual to physical
  599. mapping for the memory ranges implied by the Base Address
  600. Registers and fill in the TranslatedAddress field with
  601. virtual pointers to the bases of the ranges. It will then
  602. fill in the Type field with CmResourceTypeMemory. And
  603. the Valid field with be TRUE.
  604. If the PCI device implements I/O port Base Address registers,
  605. this function will put the translated port address in
  606. TranslatedAddress, setting the Type field to CmResourceTypePort
  607. and the Valid field to TRUE.
  608. If the PCI device does not implement a specific Base Address
  609. Register, the Valid field will be FALSE.
  610. Arguments:
  611. PciDevice - Structure indicating the device
  612. Return Value:
  613. STATUS_SUCCESS if the device is configured and usable.
  614. STATUS_NO_MORE_MATCHES if no device matched the criteria.
  615. STATUS_INSUFFICIENT_RESOURCES if the memory requirements
  616. couldn't be met.
  617. STATUS_UNSUCCESSFUL if the routine failed for other reasons.
  618. --*/
  619. {
  620. NTSTATUS status;
  621. PCI_SLOT_NUMBER slot;
  622. ULONG i, j;
  623. ULONG maxPhys;
  624. status = HalpSearchForPciDebuggingDevice(
  625. PciDevice,
  626. 0,
  627. 0xff,
  628. 0x10000000,
  629. 0xfc000000,
  630. 0x1000,
  631. 0xffff,
  632. FALSE);
  633. if (!NT_SUCCESS(status)) {
  634. //
  635. // We didn't find the device using a conservative
  636. // search. Try a more invasive one.
  637. //
  638. status = HalpSearchForPciDebuggingDevice(
  639. PciDevice,
  640. 0,
  641. 0xff,
  642. 0x10000000,
  643. 0xfc000000,
  644. 0x1000,
  645. 0xffff,
  646. TRUE);
  647. }
  648. //
  649. // Record the Bus/Dev/Func so that we can stuff it in the
  650. // registry later.
  651. //
  652. if (NT_SUCCESS(status)) {
  653. slot.u.AsULONG = PciDevice->Slot;
  654. for (i = 0;
  655. i < MAX_DEBUGGING_DEVICES_SUPPORTED;
  656. i++) {
  657. if ((HalpPciDebuggingDevice[i].u.bits.Reserved1 == TRUE) &&
  658. (HalpPciDebuggingDevice[i].u.bits.FunctionNumber ==
  659. slot.u.bits.FunctionNumber) &&
  660. (HalpPciDebuggingDevice[i].u.bits.DeviceNumber ==
  661. slot.u.bits.DeviceNumber) &&
  662. (HalpPciDebuggingDevice[i].u.bits.BusNumber ==
  663. PciDevice->Bus)) {
  664. //
  665. // This device has already been set up for
  666. // debugging. Thus we should refuse to set
  667. // it up again.
  668. //
  669. return STATUS_UNSUCCESSFUL;
  670. }
  671. }
  672. for (i = 0;
  673. i < MAX_DEBUGGING_DEVICES_SUPPORTED;
  674. i++) {
  675. if (HalpPciDebuggingDevice[i].u.bits.Reserved1 == FALSE) {
  676. //
  677. // This slot is available.
  678. //
  679. HalpPciDebuggingDevice[i].u.bits.FunctionNumber =
  680. slot.u.bits.FunctionNumber;
  681. HalpPciDebuggingDevice[i].u.bits.DeviceNumber =
  682. slot.u.bits.DeviceNumber;
  683. HalpPciDebuggingDevice[i].u.bits.BusNumber = PciDevice->Bus;
  684. HalpPciDebuggingDevice[i].u.bits.Reserved1 = TRUE;
  685. break;
  686. }
  687. }
  688. }
  689. //
  690. // Check to see if the caller wants any memory.
  691. //
  692. if (PciDevice->Memory.Length != 0) {
  693. if (!LoaderBlock) {
  694. return STATUS_INVALID_PARAMETER_1;
  695. }
  696. if (PciDevice->Memory.MaxEnd.QuadPart == 0) {
  697. PciDevice->Memory.MaxEnd.QuadPart = -1;
  698. }
  699. maxPhys = PciDevice->Memory.MaxEnd.HighPart ? 0xffffffff : PciDevice->Memory.MaxEnd.LowPart;
  700. maxPhys -= PciDevice->Memory.Length;
  701. //
  702. // The HAL APIs will always return page-aligned
  703. // memory. So ignore Aligned for now.
  704. //
  705. maxPhys = (ULONG)(ULONG_PTR)PAGE_ALIGN(maxPhys);
  706. maxPhys += ADDRESS_AND_SIZE_TO_SPAN_PAGES(maxPhys, PciDevice->Memory.Length);
  707. PciDevice->Memory.Start.HighPart = 0;
  708. PciDevice->Memory.Start.LowPart = (ULONG)(ULONG_PTR)
  709. HalpAllocPhysicalMemory(LoaderBlock,
  710. maxPhys,
  711. ADDRESS_AND_SIZE_TO_SPAN_PAGES(maxPhys, PciDevice->Memory.Length),
  712. FALSE);
  713. if (!PciDevice->Memory.Start.LowPart) {
  714. return STATUS_INSUFFICIENT_RESOURCES;
  715. }
  716. PciDevice->Memory.VirtualAddress =
  717. HalpMapPhysicalMemory(PciDevice->Memory.Start,
  718. ADDRESS_AND_SIZE_TO_SPAN_PAGES(maxPhys, PciDevice->Memory.Length),
  719. MmNonCached);
  720. }
  721. return status;
  722. }
  723. VOID
  724. HalpFindFreeResourceLimits(
  725. IN ULONG Bus,
  726. IN OUT ULONG *MinIo,
  727. IN OUT ULONG *MaxIo,
  728. IN OUT ULONG *MinMem,
  729. IN OUT ULONG *MaxMem,
  730. IN OUT ULONG *MinBus,
  731. IN OUT ULONG *MaxBus
  732. )
  733. {
  734. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  735. PPCI_COMMON_CONFIG pciData;
  736. UCHAR bus, dev, func, bytesRead;
  737. PCI_SLOT_NUMBER pciSlot, targetSlot;
  738. ULONG newMinMem, newMaxMem;
  739. ULONG newMinIo, newMaxIo;
  740. ULONG newMinBus, newMaxBus;
  741. UCHAR barNo;
  742. pciData = (PPCI_COMMON_CONFIG)buffer;
  743. pciSlot.u.AsULONG = 0;
  744. newMinMem = *MinMem;
  745. newMaxMem = *MaxMem;
  746. newMinIo = *MinIo;
  747. newMaxIo = *MaxIo;
  748. newMinBus = *MinBus;
  749. newMaxBus = *MaxBus;
  750. for (dev = 0; dev < PCI_MAX_DEVICES; dev++) {
  751. for (func = 0; func < PCI_MAX_FUNCTION; func++) {
  752. pciSlot.u.bits.DeviceNumber = dev;
  753. pciSlot.u.bits.FunctionNumber = func;
  754. bytesRead = (UCHAR)HalpPhase0GetPciDataByOffset(Bus,
  755. pciSlot.u.AsULONG,
  756. pciData,
  757. 0,
  758. PCI_COMMON_HDR_LENGTH);
  759. if (bytesRead == 0) continue;
  760. if (pciData->VendorID != PCI_INVALID_VENDORID) {
  761. switch (PCI_CONFIGURATION_TYPE(pciData)) {
  762. case PCI_DEVICE_TYPE:
  763. //
  764. // While we scan across the bus, keep track
  765. // of the minimum decoder values that we've seen.
  766. // This will be used if we have to configure the
  767. // device. This relies on the fact that most BIOSes
  768. // assign addresses from the top down.
  769. //
  770. for (barNo = 0; barNo < PCI_TYPE0_ADDRESSES; barNo++) {
  771. if (pciData->u.type0.BaseAddresses[barNo] &
  772. PCI_ADDRESS_IO_SPACE) {
  773. if (pciData->u.type0.BaseAddresses[barNo] &
  774. PCI_ADDRESS_IO_ADDRESS_MASK) {
  775. //
  776. // This BAR is implemented
  777. //
  778. if ((pciData->u.type0.BaseAddresses[barNo] &
  779. PCI_ADDRESS_IO_ADDRESS_MASK) <
  780. ((newMaxIo + newMinIo) / 2)) {
  781. //
  782. // This BAR is at the bottom of the range.
  783. // Bump up the min.
  784. //
  785. newMinIo = (USHORT)MAX (newMinIo,
  786. (pciData->u.type0.BaseAddresses[barNo] &
  787. PCI_ADDRESS_IO_ADDRESS_MASK) + 0x100);
  788. } else {
  789. //
  790. // This BAR is not at the bottom of the range.
  791. // Bump down the max.
  792. //
  793. newMaxIo = (USHORT)MIN (newMaxIo,
  794. pciData->u.type0.BaseAddresses[barNo] &
  795. PCI_ADDRESS_IO_ADDRESS_MASK);
  796. }
  797. }
  798. } else {
  799. if (pciData->u.type0.BaseAddresses[barNo] &
  800. PCI_ADDRESS_MEMORY_ADDRESS_MASK) {
  801. //
  802. // The BAR is populated.
  803. //
  804. if ((pciData->u.type0.BaseAddresses[barNo] &
  805. PCI_ADDRESS_MEMORY_ADDRESS_MASK) <
  806. ((newMaxMem / 2) + (newMinMem / 2))) {
  807. //
  808. // This BAR is at the bottom of the range.
  809. // Bump up the min.
  810. //
  811. newMinMem = MAX (newMinMem,
  812. (pciData->u.type0.BaseAddresses[barNo] &
  813. PCI_ADDRESS_MEMORY_ADDRESS_MASK) + 0x10000);
  814. } else {
  815. //
  816. // This BAR is not at the bottom of the range.
  817. // Bump down the max.
  818. //
  819. newMaxMem = MIN (newMaxMem,
  820. (pciData->u.type0.BaseAddresses[barNo] &
  821. PCI_ADDRESS_MEMORY_ADDRESS_MASK));
  822. }
  823. }
  824. }
  825. }
  826. break;
  827. case PCI_CARDBUS_BRIDGE_TYPE:
  828. case PCI_BRIDGE_TYPE:
  829. {
  830. ULONG bridgeMemMin = 0, bridgeMemMax = 0;
  831. USHORT bridgeIoMin, bridgeIoMax;
  832. if ((pciData->u.type1.SecondaryBus != 0) &&
  833. (pciData->u.type1.SubordinateBus !=0) &&
  834. (pciData->Command & PCI_ENABLE_MEMORY_SPACE) &&
  835. (pciData->Command & PCI_ENABLE_IO_SPACE)) {
  836. bridgeMemMin = PciBridgeMemory2Base(pciData->u.type1.MemoryBase);
  837. bridgeMemMax = PciBridgeMemory2Limit(pciData->u.type1.MemoryLimit);
  838. bridgeIoMin = (USHORT)PciBridgeIO2Base(pciData->u.type1.IOBase, 0);
  839. bridgeIoMax = (USHORT)PciBridgeIO2Limit(pciData->u.type1.IOLimit, 0);
  840. //
  841. // Keep track of address space allocation.
  842. //
  843. if (bridgeIoMin > ((newMaxIo + newMinIo) / 2)) {
  844. newMaxIo = MIN(newMaxIo, bridgeIoMin);
  845. }
  846. if (bridgeIoMax < ((newMaxIo + newMinIo) / 2)) {
  847. newMinIo = MAX(newMinIo, bridgeIoMax) + 1;
  848. }
  849. if (bridgeMemMin > ((newMaxMem + newMinMem) / 2)) {
  850. newMaxMem = MIN(newMaxMem, bridgeMemMin);
  851. }
  852. if (bridgeMemMax < ((newMaxMem + newMinMem) / 2)) {
  853. newMinMem = MAX(newMinMem, bridgeMemMax) + 1;
  854. }
  855. //
  856. // Keep track of bus numbers.
  857. //
  858. if (pciData->u.type1.PrimaryBus > ((newMaxBus + newMinBus) / 2)) {
  859. newMaxBus = MIN(newMaxBus, pciData->u.type1.PrimaryBus);
  860. }
  861. if (pciData->u.type1.SubordinateBus < ((newMaxBus + newMinBus) / 2)) {
  862. newMinBus = MAX(newMinBus, pciData->u.type1.SubordinateBus) + 1;
  863. }
  864. }
  865. break;
  866. default:
  867. break;
  868. }
  869. }
  870. if (!PCI_MULTIFUNCTION_DEVICE(pciData) &&
  871. (func == 0)) {
  872. break;
  873. }
  874. }
  875. }
  876. }
  877. *MinMem = newMinMem;
  878. *MaxMem = newMaxMem;
  879. *MinIo = newMinIo;
  880. *MaxIo = newMaxIo;
  881. *MinBus = newMinBus;
  882. *MaxBus = newMaxBus;
  883. }
  884. NTSTATUS
  885. HalpSetupUnconfiguredDebuggingDevice(
  886. IN ULONG Bus,
  887. IN ULONG Slot,
  888. IN ULONG IoMin,
  889. IN ULONG IoMax,
  890. IN ULONG MemMin,
  891. IN ULONG MemMax,
  892. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
  893. )
  894. {
  895. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  896. PPCI_COMMON_CONFIG pciData;
  897. ULONG barLength, bytesRead;
  898. ULONG barContents = 0;
  899. PHYSICAL_ADDRESS physicalAddress;
  900. PCI_SLOT_NUMBER pciSlot;
  901. UCHAR barNo;
  902. pciSlot.u.AsULONG = Slot;
  903. pciData = (PPCI_COMMON_CONFIG)buffer;
  904. bytesRead = (UCHAR)HalpPhase0GetPciDataByOffset(Bus,
  905. pciSlot.u.AsULONG,
  906. pciData,
  907. 0,
  908. PCI_COMMON_HDR_LENGTH);
  909. ASSERT(bytesRead != 0);
  910. PciDevice->Bus = Bus;
  911. PciDevice->Slot = pciSlot.u.AsULONG;
  912. PciDevice->VendorID = pciData->VendorID;
  913. PciDevice->DeviceID = pciData->DeviceID;
  914. PciDevice->BaseClass = pciData->BaseClass;
  915. PciDevice->SubClass = pciData->SubClass;
  916. //DbgPrint("Configuring device between %x - %x\n",
  917. // MemMin, MemMax);
  918. //
  919. // Cycle through the BARs, turning them on if necessary,
  920. // and mapping them.
  921. //
  922. for (barNo = 0; barNo < PCI_TYPE0_ADDRESSES; barNo++) {
  923. barContents = 0xffffffff;
  924. PciDevice->BaseAddress[barNo].Valid = FALSE;
  925. HalpPhase0SetPciDataByOffset(Bus,
  926. pciSlot.u.AsULONG,
  927. &barContents,
  928. 0x10 + (4 * barNo),
  929. 4);
  930. HalpPhase0GetPciDataByOffset(Bus,
  931. pciSlot.u.AsULONG,
  932. &barContents,
  933. 0x10 + (4 * barNo),
  934. 4);
  935. if (pciData->u.type0.BaseAddresses[barNo] &
  936. PCI_ADDRESS_IO_SPACE) {
  937. //
  938. // This is an I/O BAR.
  939. //
  940. if (!(pciData->u.type0.BaseAddresses[barNo] &
  941. PCI_ADDRESS_IO_ADDRESS_MASK)) {
  942. //
  943. // And it's empty.
  944. //
  945. barLength = (((USHORT)barContents & PCI_ADDRESS_IO_ADDRESS_MASK) - 1) ^
  946. 0xffff;
  947. //
  948. // Try to fit this I/O window half-way between the min and the max.
  949. //
  950. if ((ULONG)(IoMax - IoMin) >= (barLength * 3)) {
  951. //
  952. // There is plenty of room, make a safe guess. Try
  953. // to put it half-way between the upper and lower
  954. // bounds, rounding up to the next natural alignment.
  955. //
  956. pciData->u.type0.BaseAddresses[barNo] =
  957. (((IoMax + IoMin) / 2) + barLength) & (barLength -1);
  958. } else if (barLength >= (IoMax -
  959. ((IoMin & (barLength -1)) ?
  960. ((IoMin + barLength) & (barLength -1)) :
  961. IoMin))) {
  962. //
  963. // Space is tight, make a not-so-safe guess. Try
  964. // to put it at the bottom of the range, rounded
  965. // up the the next natural alignment.
  966. //
  967. pciData->u.type0.BaseAddresses[barNo] =
  968. ((IoMin & (barLength -1)) ?
  969. ((IoMin + barLength) & (barLength -1)) :
  970. IoMin);
  971. }
  972. IoMin = (USHORT)pciData->u.type0.BaseAddresses[barNo];
  973. }
  974. pciData->Command |= PCI_ENABLE_IO_SPACE;
  975. PciDevice->BaseAddress[barNo].Type = CmResourceTypePort;
  976. PciDevice->BaseAddress[barNo].Valid = TRUE;
  977. PciDevice->BaseAddress[barNo].TranslatedAddress =
  978. (PUCHAR)(ULONG_PTR)(pciData->u.type0.BaseAddresses[barNo] &
  979. PCI_ADDRESS_IO_ADDRESS_MASK);
  980. PciDevice->BaseAddress[barNo].Length = barLength;
  981. } else {
  982. //
  983. // This is a memory BAR.
  984. //
  985. barLength = ((barContents & PCI_ADDRESS_MEMORY_ADDRESS_MASK) - 1) ^
  986. 0xffffffff;
  987. if (!(pciData->u.type0.BaseAddresses[barNo] &
  988. PCI_ADDRESS_MEMORY_ADDRESS_MASK)) {
  989. //
  990. // And it's empty.
  991. //
  992. if (barLength == 0) continue;
  993. //
  994. // Try to fit this memory window half-way between the min and the max.
  995. //
  996. if ((ULONG)(MemMax - MemMin) >= (barLength * 3)) {
  997. //
  998. // There is plenty of room, make a safe guess. Try
  999. // to put it half-way between the upper and lower
  1000. // bounds, rounding up to the next natural alignment.
  1001. //
  1002. pciData->u.type0.BaseAddresses[barNo] =
  1003. (ULONG)(((MemMax + MemMin) / 2)
  1004. + barLength) & ~(barLength -1);
  1005. } else if (barLength >= (ULONG)(MemMax -
  1006. ((MemMin & ~(barLength -1)) ?
  1007. ((MemMin + barLength) & ~(barLength-1)) :
  1008. MemMin))) {
  1009. //
  1010. // Space is tight, make a not-so-safe guess. Try
  1011. // to put it at the bottom of the range, rounded
  1012. // up the the next natural alignment.
  1013. //
  1014. pciData->u.type0.BaseAddresses[barNo] =
  1015. (ULONG)((MemMin & ~(barLength -1)) ?
  1016. ((MemMin + barLength) & ~(barLength -1)) :
  1017. MemMin);
  1018. }
  1019. MemMin = pciData->u.type0.BaseAddresses[barNo] &
  1020. PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1021. }
  1022. pciData->Command |= PCI_ENABLE_MEMORY_SPACE;
  1023. physicalAddress.HighPart = 0;
  1024. physicalAddress.LowPart = pciData->u.type0.BaseAddresses[barNo]
  1025. & PCI_ADDRESS_MEMORY_ADDRESS_MASK;
  1026. PciDevice->BaseAddress[barNo].Type = CmResourceTypeMemory;
  1027. PciDevice->BaseAddress[barNo].Valid = TRUE;
  1028. PciDevice->BaseAddress[barNo].TranslatedAddress =
  1029. HalpMapPhysicalMemory(physicalAddress,
  1030. ADDRESS_AND_SIZE_TO_SPAN_PAGES(physicalAddress.LowPart, barLength),
  1031. MmNonCached);
  1032. PciDevice->BaseAddress[barNo].Length = barLength;
  1033. }
  1034. }
  1035. pciData->Command |= PCI_ENABLE_BUS_MASTER;
  1036. //
  1037. // Write back any changes we made.
  1038. //
  1039. HalpPhase0SetPciDataByOffset(Bus,
  1040. pciSlot.u.AsULONG,
  1041. pciData,
  1042. 0,
  1043. 0x40);
  1044. return STATUS_SUCCESS;
  1045. }
  1046. NTSTATUS
  1047. HalpSearchForPciDebuggingDevice(
  1048. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice,
  1049. IN ULONG StartBusNumber,
  1050. IN ULONG EndBusNumber,
  1051. IN ULONG MinMem,
  1052. IN ULONG MaxMem,
  1053. IN USHORT MinIo,
  1054. IN USHORT MaxIo,
  1055. IN BOOLEAN ConfigureBridges
  1056. )
  1057. /*++
  1058. Routine Description:
  1059. This routine is a helper function for
  1060. HalpSetupPciDeviceForDebugging.
  1061. Arguments:
  1062. PciDevice - Structure indicating the device
  1063. Return Value:
  1064. STATUS_SUCCESS if the device is configured and usable.
  1065. STATUS_NO_MORE_MATCHES if no device matched the criteria.
  1066. STATUS_UNSUCCESSFUL if the routine fails for other reasons.
  1067. --*/
  1068. #define TARGET_DEVICE_NOT_FOUND 0x10000
  1069. {
  1070. NTSTATUS status;
  1071. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  1072. PPCI_COMMON_CONFIG pciData;
  1073. UCHAR bus, dev, func, bytesRead;
  1074. PCI_SLOT_NUMBER pciSlot, targetSlot;
  1075. ULONG newMinMem, newMaxMem;
  1076. ULONG newMinIo, newMaxIo;
  1077. ULONG newMinBus, newMaxBus;
  1078. UCHAR barNo;
  1079. BOOLEAN unconfigureBridge = FALSE;
  1080. pciData = (PPCI_COMMON_CONFIG)buffer;
  1081. pciSlot.u.AsULONG = 0;
  1082. newMinMem = MinMem;
  1083. newMaxMem = MaxMem;
  1084. newMinIo = MinIo;
  1085. newMaxIo = MaxIo;
  1086. newMinBus = StartBusNumber;
  1087. newMaxBus = EndBusNumber;
  1088. bus = (UCHAR)StartBusNumber;
  1089. //DbgPrint("HalpSearchForPciDebuggingDevice:\n"
  1090. // "\tMem: %x-%x\n"
  1091. // "\tI/O: %x-%x\n"
  1092. // "\tBus: %x-%x\n"
  1093. // "\t%s Configuring Bridges\n",
  1094. // MinMem, MaxMem,
  1095. // MinIo, MaxIo,
  1096. // StartBusNumber, EndBusNumber,
  1097. // ConfigureBridges ? "" : "Not");
  1098. //
  1099. // This bit stays set to 1 until we find the device.
  1100. //
  1101. targetSlot.u.bits.Reserved = TARGET_DEVICE_NOT_FOUND;
  1102. while (TRUE) {
  1103. UCHAR nextBus;
  1104. nextBus = bus + 1;
  1105. HalpFindFreeResourceLimits(bus,
  1106. &newMinIo,
  1107. &newMaxIo,
  1108. &newMinMem,
  1109. &newMaxMem,
  1110. &newMinBus,
  1111. &newMaxBus
  1112. );
  1113. for (dev = 0; dev < PCI_MAX_DEVICES; dev++) {
  1114. for (func = 0; func < PCI_MAX_FUNCTION; func++) {
  1115. pciSlot.u.bits.DeviceNumber = dev;
  1116. pciSlot.u.bits.FunctionNumber = func;
  1117. bytesRead = (UCHAR)HalpPhase0GetPciDataByOffset(bus,
  1118. pciSlot.u.AsULONG,
  1119. pciData,
  1120. 0,
  1121. PCI_COMMON_HDR_LENGTH);
  1122. if (bytesRead == 0) continue;
  1123. if (pciData->VendorID != PCI_INVALID_VENDORID) {
  1124. //DbgPrint("%04x:%04x - %x/%x/%x - \tSlot: %x\n",
  1125. // pciData->VendorID,
  1126. // pciData->DeviceID,
  1127. // pciData->BaseClass,
  1128. // pciData->SubClass,
  1129. // pciData->ProgIf,
  1130. // pciSlot.u.AsULONG);
  1131. switch (PCI_CONFIGURATION_TYPE(pciData)) {
  1132. case PCI_DEVICE_TYPE:
  1133. //
  1134. // Match first on Bus/Dev/Func
  1135. //
  1136. if ((PciDevice->Bus == bus) &&
  1137. (PciDevice->Slot == pciSlot.u.AsULONG)) {
  1138. //DbgPrint("\n\nMatched on Bus/Slot\n\n");
  1139. return HalpSetupUnconfiguredDebuggingDevice(
  1140. bus,
  1141. pciSlot.u.AsULONG,
  1142. newMinIo,
  1143. newMaxIo,
  1144. newMinMem,
  1145. newMaxMem,
  1146. PciDevice
  1147. );
  1148. }
  1149. if ((PciDevice->Bus == MAXULONG) &&
  1150. (PciDevice->Slot == MAXULONG)) {
  1151. //
  1152. // Bus and Slot weren't specified. Match
  1153. // on VID/DID.
  1154. //
  1155. if ((pciData->VendorID == PciDevice->VendorID) &&
  1156. (pciData->DeviceID == PciDevice->DeviceID)) {
  1157. //DbgPrint("\n\nMatched on Vend/Dev\n\n");
  1158. return HalpSetupUnconfiguredDebuggingDevice(
  1159. bus,
  1160. pciSlot.u.AsULONG,
  1161. newMinIo,
  1162. newMaxIo,
  1163. newMinMem,
  1164. newMaxMem,
  1165. PciDevice
  1166. );
  1167. }
  1168. if ((PciDevice->VendorID == MAXUSHORT) &&
  1169. (PciDevice->DeviceID == MAXUSHORT)) {
  1170. //
  1171. // VID/DID weren't specified. Match
  1172. // on class codes.
  1173. //
  1174. if ((pciData->BaseClass == PciDevice->BaseClass) &&
  1175. (pciData->SubClass == PciDevice->SubClass)) {
  1176. //DbgPrint("\n\nMatched on Base/Sub\n\n");
  1177. //
  1178. // Further match on Programming Interface,
  1179. // if specified.
  1180. //
  1181. if ((PciDevice->ProgIf != MAXUCHAR) &&
  1182. (PciDevice->ProgIf != pciData->ProgIf)) {
  1183. break;
  1184. }
  1185. //DbgPrint("\n\nMatched on programming interface\n\n");
  1186. return HalpSetupUnconfiguredDebuggingDevice(
  1187. bus,
  1188. pciSlot.u.AsULONG,
  1189. newMinIo,
  1190. newMaxIo,
  1191. newMinMem,
  1192. newMaxMem,
  1193. PciDevice
  1194. );
  1195. }
  1196. }
  1197. }
  1198. break;
  1199. case PCI_CARDBUS_BRIDGE_TYPE:
  1200. //
  1201. // Cardbus bridge stuff here
  1202. //
  1203. case PCI_BRIDGE_TYPE:
  1204. {
  1205. ULONG bridgeMemMin = 0, bridgeMemMax = 0;
  1206. USHORT bridgeIoMin, bridgeIoMax;
  1207. //DbgPrint("Found a PCI to PCI bridge\n");
  1208. if (!((pciData->u.type1.SecondaryBus != 0) &&
  1209. (pciData->u.type1.SubordinateBus !=0) &&
  1210. (pciData->Command & PCI_ENABLE_MEMORY_SPACE) &&
  1211. (pciData->Command & PCI_ENABLE_IO_SPACE))) {
  1212. //
  1213. // The bridge is unconfigured.
  1214. //
  1215. if (ConfigureBridges){
  1216. //
  1217. // We should configure it now.
  1218. //
  1219. status = HalpConfigurePciBridge(
  1220. PciDevice,
  1221. bus,
  1222. pciSlot.u.AsULONG,
  1223. newMinIo,
  1224. newMaxIo,
  1225. newMinMem,
  1226. newMaxMem,
  1227. MAX((UCHAR)newMinBus, (bus + 1)),
  1228. newMaxBus,
  1229. pciData
  1230. );
  1231. if (!NT_SUCCESS(status)) {
  1232. break;
  1233. }
  1234. unconfigureBridge = TRUE;
  1235. } else {
  1236. //
  1237. // We aren't configuring bridges
  1238. // on this pass.
  1239. //
  1240. break;
  1241. }
  1242. }
  1243. bridgeMemMin = PciBridgeMemory2Base(pciData->u.type1.MemoryBase);
  1244. bridgeMemMax = PciBridgeMemory2Limit(pciData->u.type1.MemoryLimit);
  1245. bridgeIoMin = (USHORT)PciBridgeIO2Base(pciData->u.type1.IOBase, 0);
  1246. bridgeIoMax = (USHORT)PciBridgeIO2Limit(pciData->u.type1.IOLimit, 0);
  1247. //DbgPrint("Configured: I/O %x-%x Mem %x-%x\n",
  1248. // bridgeIoMin, bridgeIoMax,
  1249. // bridgeMemMin, bridgeMemMax);
  1250. //
  1251. // Recurse.
  1252. //
  1253. status = HalpSearchForPciDebuggingDevice(
  1254. PciDevice,
  1255. (ULONG)pciData->u.type1.SecondaryBus,
  1256. (ULONG)pciData->u.type1.SubordinateBus,
  1257. bridgeMemMin,
  1258. bridgeMemMax,
  1259. bridgeIoMin,
  1260. bridgeIoMax,
  1261. ConfigureBridges);
  1262. if (NT_SUCCESS(status)) {
  1263. return status;
  1264. }
  1265. if (!unconfigureBridge) {
  1266. //
  1267. // Bump up the bus number so that we don't
  1268. // scan down the busses we just recursed into.
  1269. //
  1270. nextBus = pciData->u.type1.SubordinateBus + 1;
  1271. } else {
  1272. HalpUnconfigurePciBridge(bus,
  1273. pciSlot.u.AsULONG);
  1274. }
  1275. }
  1276. break;
  1277. default:
  1278. break;
  1279. }
  1280. }
  1281. if (!PCI_MULTIFUNCTION_DEVICE(pciData) &&
  1282. (func == 0)) {
  1283. break;
  1284. }
  1285. }
  1286. }
  1287. if (nextBus >= EndBusNumber) {
  1288. break;
  1289. }
  1290. bus = nextBus;
  1291. }
  1292. return STATUS_NOT_FOUND;
  1293. }
  1294. NTSTATUS
  1295. HalpReleasePciDeviceForDebugging(
  1296. IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice
  1297. )
  1298. /*++
  1299. Routine Description:
  1300. This routine de-allocates any resources acquired in
  1301. HalpSetupPciDeviceForDebugging.
  1302. Arguments:
  1303. PciDevice - Structure indicating the device
  1304. Return Value:
  1305. --*/
  1306. {
  1307. ULONG i;
  1308. for (i = 0; i < PCI_TYPE0_ADDRESSES; i++) {
  1309. if (PciDevice->BaseAddress[i].Valid &&
  1310. PciDevice->BaseAddress[i].Type == CmResourceTypeMemory) {
  1311. PciDevice->BaseAddress[i].Valid = FALSE;
  1312. HalpUnmapVirtualAddress(PciDevice->BaseAddress[i].TranslatedAddress,
  1313. ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  1314. PciDevice->BaseAddress[i].TranslatedAddress,
  1315. PciDevice->BaseAddress[i].Length));
  1316. }
  1317. }
  1318. return STATUS_SUCCESS;
  1319. }
  1320. VOID
  1321. HalpRegisterKdSupportFunctions(
  1322. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  1323. )
  1324. /*++
  1325. Routine Description:
  1326. This routine fills in the HalPrivateDispatchTable
  1327. with the functions needed for debugging through
  1328. PCI devices.
  1329. Arguments:
  1330. LoaderBlock - The Loader Block
  1331. Return Value:
  1332. --*/
  1333. {
  1334. KdSetupPciDeviceForDebugging = HalpSetupPciDeviceForDebugging;
  1335. KdReleasePciDeviceForDebugging = HalpReleasePciDeviceForDebugging;
  1336. KdGetAcpiTablePhase0 = HalpGetAcpiTablePhase0;
  1337. KdMapPhysicalMemory64 = HalpMapPhysicalMemory64;
  1338. KdCheckPowerButton = HalpCheckPowerButton;
  1339. }
  1340. VOID
  1341. HalpRegisterPciDebuggingDeviceInfo(
  1342. VOID
  1343. )
  1344. {
  1345. OBJECT_ATTRIBUTES ObjectAttributes;
  1346. UNICODE_STRING UnicodeString;
  1347. HANDLE BaseHandle = NULL;
  1348. HANDLE Handle = NULL;
  1349. ULONG disposition;
  1350. ULONG bus;
  1351. UCHAR i;
  1352. PCI_SLOT_NUMBER slot;
  1353. NTSTATUS status;
  1354. BOOLEAN debuggerFound = FALSE;
  1355. PAGED_CODE();
  1356. for (i = 0;
  1357. i < MAX_DEBUGGING_DEVICES_SUPPORTED;
  1358. i++) {
  1359. if (HalpPciDebuggingDevice[i].u.bits.Reserved1 == TRUE) {
  1360. //
  1361. // Must be using a PCI device for a debugger.
  1362. //
  1363. debuggerFound = TRUE;
  1364. }
  1365. }
  1366. if (!debuggerFound) {
  1367. return;
  1368. }
  1369. //
  1370. // Open PCI service key.
  1371. //
  1372. RtlInitUnicodeString (&UnicodeString,
  1373. L"\\REGISTRY\\MACHINE\\SYSTEM\\CURRENTCONTROLSET\\SERVICES\\PCI");
  1374. InitializeObjectAttributes(&ObjectAttributes,
  1375. &UnicodeString,
  1376. OBJ_CASE_INSENSITIVE,
  1377. NULL,
  1378. (PSECURITY_DESCRIPTOR) NULL);
  1379. status = ZwOpenKey (&BaseHandle,
  1380. KEY_READ,
  1381. &ObjectAttributes);
  1382. if (!NT_SUCCESS(status)) {
  1383. return;
  1384. }
  1385. // Get the right key
  1386. RtlInitUnicodeString (&UnicodeString,
  1387. L"Debug");
  1388. InitializeObjectAttributes(&ObjectAttributes,
  1389. &UnicodeString,
  1390. OBJ_CASE_INSENSITIVE,
  1391. BaseHandle,
  1392. (PSECURITY_DESCRIPTOR) NULL);
  1393. status = ZwCreateKey (&Handle,
  1394. KEY_READ,
  1395. &ObjectAttributes,
  1396. 0,
  1397. (PUNICODE_STRING) NULL,
  1398. REG_OPTION_VOLATILE,
  1399. &disposition);
  1400. ZwClose(BaseHandle);
  1401. BaseHandle = Handle;
  1402. ASSERT(disposition == REG_CREATED_NEW_KEY);
  1403. if (!NT_SUCCESS(status)) {
  1404. return;
  1405. }
  1406. for (i = 0;
  1407. i < MAX_DEBUGGING_DEVICES_SUPPORTED;
  1408. i++) {
  1409. if (HalpPciDebuggingDevice[i].u.bits.Reserved1 == TRUE) {
  1410. //
  1411. // This entry is populated. Create a key for it.
  1412. //
  1413. RtlInitUnicodeString (&UnicodeString,
  1414. L"0");
  1415. (*(PCHAR)&(UnicodeString.Buffer[0])) += i;
  1416. InitializeObjectAttributes(&ObjectAttributes,
  1417. &UnicodeString,
  1418. OBJ_CASE_INSENSITIVE,
  1419. BaseHandle,
  1420. (PSECURITY_DESCRIPTOR) NULL);
  1421. status = ZwCreateKey (&Handle,
  1422. KEY_READ,
  1423. &ObjectAttributes,
  1424. 0,
  1425. (PUNICODE_STRING) NULL,
  1426. REG_OPTION_VOLATILE,
  1427. &disposition);
  1428. ASSERT(disposition == REG_CREATED_NEW_KEY);
  1429. //
  1430. // Fill in the values below this key.
  1431. //
  1432. bus = HalpPciDebuggingDevice[i].u.bits.BusNumber;
  1433. RtlInitUnicodeString (&UnicodeString,
  1434. L"Bus");
  1435. status = ZwSetValueKey (Handle,
  1436. &UnicodeString,
  1437. 0,
  1438. REG_DWORD,
  1439. &bus,
  1440. sizeof(ULONG));
  1441. //ASSERT(NT_SUCCESS(status));
  1442. slot.u.AsULONG = 0;
  1443. slot.u.bits.FunctionNumber = HalpPciDebuggingDevice[i].u.bits.FunctionNumber;
  1444. slot.u.bits.DeviceNumber = HalpPciDebuggingDevice[i].u.bits.DeviceNumber;
  1445. RtlInitUnicodeString (&UnicodeString,
  1446. L"Slot");
  1447. status = ZwSetValueKey (Handle,
  1448. &UnicodeString,
  1449. 0,
  1450. REG_DWORD,
  1451. &slot.u.AsULONG,
  1452. sizeof(ULONG));
  1453. //ASSERT(NT_SUCCESS(status));
  1454. ZwClose(Handle);
  1455. }
  1456. }
  1457. ZwClose(BaseHandle);
  1458. return;
  1459. }
  1460. NTSTATUS
  1461. HalpConfigurePciBridge(
  1462. IN PDEBUG_DEVICE_DESCRIPTOR PciDevice,
  1463. IN ULONG Bus,
  1464. IN ULONG Slot,
  1465. IN ULONG IoMin,
  1466. IN ULONG IoMax,
  1467. IN ULONG MemMin,
  1468. IN ULONG MemMax,
  1469. IN ULONG BusMin,
  1470. IN ULONG BusMax,
  1471. IN OUT PPCI_COMMON_CONFIG PciData
  1472. )
  1473. {
  1474. USHORT memUnits = 0;
  1475. ULONG memSize;
  1476. PciData->u.type1.PrimaryBus = (UCHAR)Bus;
  1477. PciData->u.type1.SecondaryBus = (UCHAR)BusMin;
  1478. PciData->u.type1.SubordinateBus = (UCHAR)(MIN(BusMax, (BusMin + 2)));
  1479. PciData->Command &= ~PCI_ENABLE_BUS_MASTER;
  1480. //DbgPrint("HalpConfigurePciBridge: P: %x S: %x S: %x\n"
  1481. // "\tI/O %x-%x Mem %x-%x Bus %x-%x\n",
  1482. // PciData->u.type1.PrimaryBus,
  1483. // PciData->u.type1.SecondaryBus,
  1484. // PciData->u.type1.SubordinateBus,
  1485. // IoMin, IoMax,
  1486. // MemMin, MemMax,
  1487. // BusMin, BusMax);
  1488. //
  1489. // Only enable I/O on the bridge if we are looking for
  1490. // something besides a 1394 controller.
  1491. //
  1492. if (!((PciDevice->BaseClass == PCI_CLASS_SERIAL_BUS_CTLR) &&
  1493. (PciDevice->SubClass == PCI_SUBCLASS_SB_IEEE1394))) {
  1494. if (((IoMax & 0xf000) - (IoMin & 0xf000)) >= 0X1000) {
  1495. //
  1496. // There is enough I/O space here to enable
  1497. // an I/O window.
  1498. //
  1499. PciData->u.type1.IOBase =
  1500. (UCHAR)((IoMax & 0xf000) >> 12) - 1;
  1501. PciData->u.type1.IOLimit = PciData->u.type1.IOBase;
  1502. PciData->Command |= PCI_ENABLE_IO_SPACE;
  1503. PciData->Command |= PCI_ENABLE_BUS_MASTER;
  1504. }
  1505. }
  1506. //
  1507. // Enable a memory window if possible.
  1508. //
  1509. memSize = ((MemMax + 1) & 0xfff00000) - (MemMin & 0xfff00000);
  1510. if (memSize >= 0x100000) {
  1511. memUnits = 1;
  1512. }
  1513. if (memSize >= 0x400000) {
  1514. memUnits = 4;
  1515. }
  1516. if (memUnits > 0) {
  1517. //
  1518. // There is enough space.
  1519. //
  1520. PciData->u.type1.MemoryBase =
  1521. (USHORT)((MemMax & 0xfff00000) >> 16) - (memUnits << 4);
  1522. PciData->u.type1.MemoryLimit = PciData->u.type1.MemoryBase + ((memUnits- 1) << 4);
  1523. PciData->Command |= PCI_ENABLE_MEMORY_SPACE;
  1524. PciData->Command |= PCI_ENABLE_BUS_MASTER;
  1525. }
  1526. if (PciData->Command & PCI_ENABLE_BUS_MASTER) {
  1527. HalpPhase0SetPciDataByOffset(Bus,
  1528. Slot,
  1529. PciData,
  1530. 0,
  1531. 0x24);
  1532. return STATUS_SUCCESS;
  1533. } else {
  1534. return STATUS_UNSUCCESSFUL;
  1535. }
  1536. }
  1537. VOID
  1538. HalpUnconfigurePciBridge(
  1539. IN ULONG Bus,
  1540. IN ULONG Slot
  1541. )
  1542. {
  1543. UCHAR buffer[0x20] = {0};
  1544. //
  1545. // Zero the command register.
  1546. //
  1547. HalpPhase0SetPciDataByOffset(Bus,
  1548. Slot,
  1549. buffer,
  1550. FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
  1551. 2);
  1552. //
  1553. // Zero the address space and bus number registers.
  1554. //
  1555. HalpPhase0SetPciDataByOffset(Bus,
  1556. Slot,
  1557. buffer,
  1558. FIELD_OFFSET (PCI_COMMON_CONFIG, u),
  1559. 0x20);
  1560. }