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.

1092 lines
28 KiB

  1. /*++
  2. Copyright (c) 1996-2000 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. This module contains the initialization code for PCI.SYS.
  7. Author:
  8. Forrest Foltz (forrestf) 22-May-1996
  9. Revision History:
  10. --*/
  11. #include "pcip.h"
  12. NTSTATUS
  13. DriverEntry(
  14. IN PDRIVER_OBJECT DriverObject,
  15. IN PUNICODE_STRING RegistryPath
  16. );
  17. VOID
  18. PciDriverUnload(
  19. IN PDRIVER_OBJECT DriverObject
  20. );
  21. NTSTATUS
  22. PciBuildHackTable(
  23. IN HANDLE HackTableKey
  24. );
  25. NTSTATUS
  26. PciGetIrqRoutingTableFromRegistry(
  27. PPCI_IRQ_ROUTING_TABLE *RoutingTable
  28. );
  29. NTSTATUS
  30. PciGetDebugPorts(
  31. IN HANDLE ServiceHandle
  32. );
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text(INIT, DriverEntry)
  35. #pragma alloc_text(INIT, PciBuildHackTable)
  36. #pragma alloc_text(INIT, PciGetIrqRoutingTableFromRegistry)
  37. #pragma alloc_text(INIT, PciGetDebugPorts)
  38. #pragma alloc_text(PAGE, PciDriverUnload)
  39. #endif
  40. PDRIVER_OBJECT PciDriverObject;
  41. BOOLEAN PciLockDeviceResources;
  42. ULONG PciSystemWideHackFlags;
  43. ULONG PciEnableNativeModeATA;
  44. //
  45. // List of FDOs created by this driver.
  46. //
  47. SINGLE_LIST_ENTRY PciFdoExtensionListHead;
  48. LONG PciRootBusCount;
  49. //
  50. // PciAssignBusNumbers - this flag indicates whether we should try to assign
  51. // bus numbers to an unconfigured bridge. It is set once we know if the enumerator
  52. // of the PCI bus provides sufficient support.
  53. //
  54. BOOLEAN PciAssignBusNumbers = FALSE;
  55. //
  56. // This locks all PCI's global data structures
  57. //
  58. FAST_MUTEX PciGlobalLock;
  59. //
  60. // This locks changes to bus numbers
  61. //
  62. FAST_MUTEX PciBusLock;
  63. //
  64. // Table of hacks for broken hardware read from the registry at init.
  65. // Protected by PciGlobalSpinLock and in none paged pool as it is needed at
  66. // dispatch level
  67. //
  68. PPCI_HACK_TABLE_ENTRY PciHackTable = NULL;
  69. // Will point to PCI IRQ Routing Table if one was found in the registry.
  70. PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable = NULL;
  71. //
  72. // Debug ports we support
  73. //
  74. PCI_DEBUG_PORT PciDebugPorts[MAX_DEBUGGING_DEVICES_SUPPORTED];
  75. ULONG PciDebugPortsCount;
  76. #define PATH_CCS L"\\Registry\\Machine\\System\\CurrentControlSet"
  77. #define KEY_BIOS_INFO L"Control\\BiosInfo\\PCI"
  78. #define VALUE_PCI_LOCK L"PCILock"
  79. #define KEY_PNP_PCI L"Control\\PnP\\PCI"
  80. #define VALUE_PCI_HACKFLAGS L"HackFlags"
  81. #define VALUE_ENABLE_NATA L"EnableNativeModeATA"
  82. #define KEY_CONTROL L"Control"
  83. #define VALUE_OSLOADOPT L"SystemStartOptions"
  84. #define KEY_MULTIFUNCTION L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter"
  85. #define KEY_IRQ_ROUTING_TABLE L"RealModeIrqRoutingTable\\0"
  86. #define VALUE_IDENTIFIER L"Identifier"
  87. #define VALUE_CONFIGURATION_DATA L"Configuration Data"
  88. #define PCIIR_IDENTIFIER L"PCI BIOS"
  89. #define HACKFMT_VENDORDEV (sizeof(L"VVVVDDDD") - sizeof(UNICODE_NULL))
  90. #define HACKFMT_VENDORDEVREVISION (sizeof(L"VVVVDDDDRR") - sizeof(UNICODE_NULL))
  91. #define HACKFMT_SUBSYSTEM (sizeof(L"VVVVDDDDSSSSssss") - sizeof(UNICODE_NULL))
  92. #define HACKFMT_SUBSYSTEMREVISION (sizeof(L"VVVVDDDDSSSSssssRR") - sizeof(UNICODE_NULL))
  93. #define HACKFMT_MAX_LENGTH HACKFMT_SUBSYSTEMREVISION
  94. #define HACKFMT_DEVICE_OFFSET 4
  95. #define HACKFMT_SUBVENDOR_OFFSET 8
  96. #define HACKFMT_SUBSYSTEM_OFFSET 12
  97. NTSTATUS
  98. DriverEntry(
  99. IN PDRIVER_OBJECT DriverObject,
  100. IN PUNICODE_STRING RegistryPath
  101. )
  102. /*++
  103. Routine Description:
  104. Entrypoint needed to initialize the PCI bus enumerator.
  105. Arguments:
  106. DriverObject - Pointer to the driver object created by the system.
  107. RegistryPath - Pointer to the unicode registry service path.
  108. Return Value:
  109. NT status.
  110. --*/
  111. {
  112. NTSTATUS status;
  113. ULONG length;
  114. PWCHAR osLoadOptions;
  115. HANDLE ccsHandle = NULL, serviceKey = NULL, paramsKey = NULL, debugKey = NULL;
  116. PULONG registryValue;
  117. ULONG registryValueLength;
  118. OBJECT_ATTRIBUTES attributes;
  119. //
  120. // Fill in the driver object
  121. //
  122. DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp;
  123. DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp;
  124. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp;
  125. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp;
  126. DriverObject->DriverUnload = PciDriverUnload;
  127. DriverObject->DriverExtension->AddDevice = PciAddDevice;
  128. PciDriverObject = DriverObject;
  129. //
  130. // Open our service key and retrieve the hack table
  131. //
  132. InitializeObjectAttributes(&attributes,
  133. RegistryPath,
  134. OBJ_CASE_INSENSITIVE,
  135. NULL,
  136. NULL
  137. );
  138. status = ZwOpenKey(&serviceKey,
  139. KEY_READ,
  140. &attributes
  141. );
  142. if (!NT_SUCCESS(status)) {
  143. return status;
  144. }
  145. //
  146. // Get the Hack table from the registry
  147. //
  148. if (!PciOpenKey(L"Parameters", serviceKey, &paramsKey, &status)) {
  149. goto exit;
  150. }
  151. status = PciBuildHackTable(paramsKey);
  152. if (!NT_SUCCESS(status)) {
  153. goto exit;
  154. }
  155. //
  156. // Get any info about debugging ports from the registry so we don't perturb
  157. // them
  158. //
  159. if (PciOpenKey(L"Debug", serviceKey, &debugKey, &status)) {
  160. status = PciGetDebugPorts(debugKey);
  161. if (!NT_SUCCESS(status)) {
  162. goto exit;
  163. }
  164. }
  165. //
  166. // Initialize the list of FDO Extensions.
  167. //
  168. PciFdoExtensionListHead.Next = NULL;
  169. PciRootBusCount = 0;
  170. ExInitializeFastMutex(&PciGlobalLock);
  171. ExInitializeFastMutex(&PciBusLock);
  172. //
  173. // Need access to the CurrentControlSet for various
  174. // initialization chores.
  175. //
  176. if (!PciOpenKey(PATH_CCS, NULL, &ccsHandle, &status)) {
  177. goto exit;
  178. }
  179. //
  180. // Get OSLOADOPTIONS and see if PCILOCK was specified.
  181. // (Unless the driver is build to force PCILOCK).
  182. // (Note: Can't check for leading '/', it was stripped
  183. // before getting put in the registry).
  184. //
  185. PciLockDeviceResources = FALSE;
  186. if (NT_SUCCESS(PciGetRegistryValue(VALUE_OSLOADOPT,
  187. KEY_CONTROL,
  188. ccsHandle,
  189. &osLoadOptions,
  190. &length))) {
  191. //
  192. // Unfortunately, there isn't a wcsstrn (length limited
  193. // version of wcsstr). If this is ever used more than
  194. // once, it should be moved to its own function in utils.c.
  195. //
  196. // Search for PCILOCK in the returned string.
  197. //
  198. ULONG ln = length >> 1;
  199. PWCHAR cp = osLoadOptions;
  200. PWCHAR t = L"PCILOCK";
  201. PWCHAR s1, s2;
  202. ULONG lt = wcslen(t);
  203. ASSERT(length < 0x10000);
  204. while (ln && *cp) {
  205. //
  206. // Can desired string exist in the remaining length?
  207. //
  208. if (ln < lt) {
  209. //
  210. // No, give up.
  211. //
  212. break;
  213. }
  214. s1 = cp;
  215. s2 = t;
  216. while (*s1 && *s2 && (*s1 == *s2)) {
  217. s1++, s2++;
  218. }
  219. if (!*s2) {
  220. //
  221. // Match!
  222. //
  223. PciLockDeviceResources = TRUE;
  224. break;
  225. }
  226. cp++, ln--;
  227. }
  228. ExFreePool(osLoadOptions);
  229. }
  230. if (!PciLockDeviceResources) {
  231. PULONG pciLockValue;
  232. ULONG pciLockLength;
  233. if (NT_SUCCESS(PciGetRegistryValue( VALUE_PCI_LOCK,
  234. KEY_BIOS_INFO,
  235. ccsHandle,
  236. &pciLockValue,
  237. &pciLockLength))) {
  238. if (pciLockLength == 4 && *pciLockValue == 1) {
  239. PciLockDeviceResources = TRUE;
  240. }
  241. ExFreePool(pciLockValue);
  242. }
  243. }
  244. PciSystemWideHackFlags = 0;
  245. if (NT_SUCCESS(PciGetRegistryValue( VALUE_PCI_HACKFLAGS,
  246. KEY_PNP_PCI,
  247. ccsHandle,
  248. &registryValue,
  249. &registryValueLength))) {
  250. if (registryValueLength == sizeof(ULONG)) {
  251. PciSystemWideHackFlags = *registryValue;
  252. }
  253. ExFreePool(registryValue);
  254. }
  255. PciEnableNativeModeATA = 0;
  256. if (NT_SUCCESS(PciGetRegistryValue( VALUE_ENABLE_NATA,
  257. KEY_PNP_PCI,
  258. ccsHandle,
  259. &registryValue,
  260. &registryValueLength))) {
  261. if (registryValueLength == sizeof(ULONG)) {
  262. PciEnableNativeModeATA = *registryValue;
  263. }
  264. ExFreePool(registryValue);
  265. }
  266. //
  267. // Build some global data structures
  268. //
  269. status = PciBuildDefaultExclusionLists();
  270. if (!NT_SUCCESS(status)) {
  271. return status;
  272. }
  273. //
  274. // If we don't find an IRQ routing table, no UI number information
  275. // will be returned for the PDOs using this mechanism. ACPI may
  276. // still filter in UI numbers.
  277. //
  278. PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable);
  279. //
  280. // Override the functions that used to be in the HAL but are now in the
  281. // PCI driver
  282. //
  283. PciHookHal();
  284. //
  285. // Enable the hardware verifier code if appropriate.
  286. //
  287. PciVerifierInit(DriverObject);
  288. status = STATUS_SUCCESS;
  289. exit:
  290. if (ccsHandle) {
  291. ZwClose(ccsHandle);
  292. }
  293. if (serviceKey) {
  294. ZwClose(serviceKey);
  295. }
  296. if (paramsKey) {
  297. ZwClose(paramsKey);
  298. }
  299. if (debugKey) {
  300. ZwClose(debugKey);
  301. }
  302. return status;
  303. }
  304. VOID
  305. PciDriverUnload(
  306. IN PDRIVER_OBJECT DriverObject
  307. )
  308. /*++
  309. Routine Description:
  310. Entrypoint used to unload the PCI driver. Does nothing, the
  311. PCI driver is never unloaded.
  312. Arguments:
  313. DriverObject - Pointer to the driver object created by the system.
  314. Return Value:
  315. None.
  316. --*/
  317. {
  318. //
  319. // Disable the hardware verifier code if appropriate.
  320. //
  321. PciVerifierUnload(DriverObject);
  322. //
  323. // Unallocate anything we can find.
  324. //
  325. RtlFreeRangeList(&PciIsaBitExclusionList);
  326. RtlFreeRangeList(&PciVgaAndIsaBitExclusionList);
  327. //
  328. // Free IRQ routing table if we have one
  329. //
  330. if (PciIrqRoutingTable != NULL) {
  331. ExFreePool(PciIrqRoutingTable);
  332. }
  333. //
  334. // Attempt to remove our hooks in case we actually get unloaded.
  335. //
  336. PciUnhookHal();
  337. }
  338. NTSTATUS
  339. PciBuildHackTable(
  340. IN HANDLE HackTableKey
  341. )
  342. {
  343. NTSTATUS status;
  344. PKEY_FULL_INFORMATION keyInfo = NULL;
  345. ULONG hackCount, size, index;
  346. USHORT temp;
  347. PPCI_HACK_TABLE_ENTRY entry;
  348. ULONGLONG data;
  349. PKEY_VALUE_FULL_INFORMATION valueInfo = NULL;
  350. ULONG valueInfoSize = sizeof(KEY_VALUE_FULL_INFORMATION)
  351. + HACKFMT_MAX_LENGTH +
  352. + sizeof(ULONGLONG);
  353. //
  354. // Get the key info so we know how many hack values there are.
  355. // This does not change during system initialization.
  356. //
  357. status = ZwQueryKey(HackTableKey,
  358. KeyFullInformation,
  359. NULL,
  360. 0,
  361. &size
  362. );
  363. if (status != STATUS_BUFFER_TOO_SMALL) {
  364. ASSERT(!NT_SUCCESS(status));
  365. goto cleanup;
  366. }
  367. ASSERT(size > 0);
  368. keyInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, size);
  369. if (!keyInfo) {
  370. status = STATUS_INSUFFICIENT_RESOURCES;
  371. goto cleanup;
  372. }
  373. status = ZwQueryKey(HackTableKey,
  374. KeyFullInformation,
  375. keyInfo,
  376. size,
  377. &size
  378. );
  379. if (!NT_SUCCESS(status)) {
  380. goto cleanup;
  381. }
  382. hackCount = keyInfo->Values;
  383. ExFreePool(keyInfo);
  384. keyInfo = NULL;
  385. //
  386. // Allocate and initialize the hack table
  387. //
  388. PciHackTable = ExAllocatePool(NonPagedPool,
  389. (hackCount + 1) * sizeof(PCI_HACK_TABLE_ENTRY)
  390. );
  391. if (!PciHackTable) {
  392. status = STATUS_INSUFFICIENT_RESOURCES;
  393. goto cleanup;
  394. }
  395. //
  396. // Allocate a valueInfo buffer big enough for the biggest valid
  397. // format and a ULONGLONG worth of data.
  398. //
  399. valueInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, valueInfoSize);
  400. if (!valueInfo) {
  401. status = STATUS_INSUFFICIENT_RESOURCES;
  402. goto cleanup;
  403. }
  404. entry = PciHackTable;
  405. for (index = 0; index < hackCount; index++) {
  406. status = ZwEnumerateValueKey(HackTableKey,
  407. index,
  408. KeyValueFullInformation,
  409. valueInfo,
  410. valueInfoSize,
  411. &size
  412. );
  413. if (!NT_SUCCESS(status)) {
  414. if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) {
  415. //
  416. // All out data is of fixed length and the buffer is big enough
  417. // so this can't be for us.
  418. //
  419. continue;
  420. } else {
  421. goto cleanup;
  422. }
  423. }
  424. //
  425. // Get pointer to the data if its of the right type
  426. //
  427. if ((valueInfo->Type == REG_BINARY) &&
  428. (valueInfo->DataLength == sizeof(ULONGLONG))) {
  429. data = *(ULONGLONG UNALIGNED *)(((PUCHAR)valueInfo) + valueInfo->DataOffset);
  430. } else {
  431. //
  432. // We only deal in ULONGLONGs
  433. //
  434. continue;
  435. }
  436. //
  437. // Now see if the name is formatted like we expect it to be:
  438. // VVVVDDDD
  439. // VVVVDDDDRR
  440. // VVVVDDDDSSSSssss
  441. // VVVVDDDDSSSSssssRR
  442. if ((valueInfo->NameLength != HACKFMT_VENDORDEV) &&
  443. (valueInfo->NameLength != HACKFMT_VENDORDEVREVISION) &&
  444. (valueInfo->NameLength != HACKFMT_SUBSYSTEM) &&
  445. (valueInfo->NameLength != HACKFMT_SUBSYSTEMREVISION)) {
  446. //
  447. // This isn't ours
  448. //
  449. PciDebugPrint(
  450. PciDbgInformative,
  451. "Skipping hack entry with invalid length name\n"
  452. );
  453. continue;
  454. }
  455. //
  456. // This looks plausable - try to parse it and fill in a hack table
  457. // entry
  458. //
  459. RtlZeroMemory(entry, sizeof(PCI_HACK_TABLE_ENTRY));
  460. //
  461. // Look for DeviceID and VendorID (VVVVDDDD)
  462. //
  463. if (!PciStringToUSHORT(valueInfo->Name, &entry->VendorID)) {
  464. continue;
  465. }
  466. if (!PciStringToUSHORT(valueInfo->Name + HACKFMT_DEVICE_OFFSET,
  467. &entry->DeviceID)) {
  468. continue;
  469. }
  470. //
  471. // Look for SubsystemVendorID/SubSystemID (SSSSssss)
  472. //
  473. if ((valueInfo->NameLength == HACKFMT_SUBSYSTEM) ||
  474. (valueInfo->NameLength == HACKFMT_SUBSYSTEMREVISION)) {
  475. if (!PciStringToUSHORT(valueInfo->Name + HACKFMT_SUBVENDOR_OFFSET,
  476. &entry->SubVendorID)) {
  477. continue;
  478. }
  479. if (!PciStringToUSHORT(valueInfo->Name + HACKFMT_SUBSYSTEM_OFFSET,
  480. &entry->SubSystemID)) {
  481. continue;
  482. }
  483. entry->Flags |= PCI_HACK_FLAG_SUBSYSTEM;
  484. }
  485. //
  486. // Look for RevisionID (RR)
  487. //
  488. if ((valueInfo->NameLength == HACKFMT_VENDORDEVREVISION) ||
  489. (valueInfo->NameLength == HACKFMT_SUBSYSTEMREVISION)) {
  490. if (PciStringToUSHORT(valueInfo->Name +
  491. (valueInfo->NameLength/sizeof(WCHAR) - 4), &temp)) {
  492. entry->RevisionID = temp & 0xFF;
  493. entry->Flags |= PCI_HACK_FLAG_REVISION;
  494. } else {
  495. continue;
  496. }
  497. }
  498. ASSERT(entry->VendorID != 0xFFFF);
  499. //
  500. // Fill in the entry
  501. //
  502. entry->HackFlags = data;
  503. PciDebugPrint(
  504. PciDbgInformative,
  505. "Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
  506. entry->VendorID, entry->DeviceID
  507. );
  508. if (entry->Flags & PCI_HACK_FLAG_SUBSYSTEM) {
  509. PciDebugPrint(
  510. PciDbgInformative,
  511. "SybSys:0x%04x SubVendor:0x%04x ",
  512. entry->SubSystemID, entry->SubVendorID
  513. );
  514. }
  515. if (entry->Flags & PCI_HACK_FLAG_REVISION) {
  516. PciDebugPrint(
  517. PciDbgInformative,
  518. "Revision:0x%02x",
  519. (ULONG) entry->RevisionID
  520. );
  521. }
  522. PciDebugPrint(
  523. PciDbgInformative,
  524. " = 0x%I64x\n",
  525. entry->HackFlags
  526. );
  527. entry++;
  528. }
  529. ASSERT(entry < (PciHackTable + hackCount + 1));
  530. //
  531. // Terminate the table with an invalid VendorID
  532. //
  533. entry->VendorID = 0xFFFF;
  534. ExFreePool(valueInfo);
  535. return STATUS_SUCCESS;
  536. cleanup:
  537. ASSERT(!NT_SUCCESS(status));
  538. if (keyInfo) {
  539. ExFreePool(keyInfo);
  540. }
  541. if (valueInfo) {
  542. ExFreePool(valueInfo);
  543. }
  544. if (PciHackTable) {
  545. ExFreePool(PciHackTable);
  546. PciHackTable = NULL;
  547. }
  548. return status;
  549. }
  550. NTSTATUS
  551. PciGetIrqRoutingTableFromRegistry(
  552. PPCI_IRQ_ROUTING_TABLE *RoutingTable
  553. )
  554. /*++
  555. Routine Description:
  556. Retrieve the IRQ routing table from the registry if present so it
  557. can be used to determine the UI Number (slot #) that will be used
  558. later when answering capabilities queries on the PDOs.
  559. Searches HKLM\Hardware\Description\System\MultiFunctionAdapter for
  560. a subkey with an "Identifier" value equal to "PCI BIOS". It then looks at
  561. "RealModeIrqRoutingTable\0" from this subkey to find actual irq routing
  562. table value. This value has a CM_FULL_RESOURCE_DESCRIPTOR in front of it.
  563. Hals that suppirt irq routing tables have a similar routine.
  564. Arguments:
  565. RoutingTable - Pointer to a pointer to the routing table returned if any
  566. Return Value:
  567. NTSTATUS - failure indicates inability to get irq routing table
  568. information from the registry.
  569. --*/
  570. {
  571. PUCHAR irqTable = NULL;
  572. PKEY_FULL_INFORMATION multiKeyInformation = NULL;
  573. PKEY_BASIC_INFORMATION keyInfo = NULL;
  574. PKEY_VALUE_PARTIAL_INFORMATION identifierValueInfo = NULL;
  575. UNICODE_STRING unicodeString;
  576. HANDLE keyMultifunction = NULL, keyTable = NULL;
  577. ULONG i, length, maxKeyLength, identifierValueLen;
  578. BOOLEAN result;
  579. NTSTATUS status;
  580. //
  581. // Open the multifunction key
  582. //
  583. result = PciOpenKey(KEY_MULTIFUNCTION,
  584. NULL,
  585. &keyMultifunction,
  586. &status);
  587. if (!result) {
  588. goto Cleanup;
  589. }
  590. //
  591. // Do allocation of buffers up front
  592. //
  593. //
  594. // Determine maximum size of a keyname under the multifunction key
  595. //
  596. status = ZwQueryKey(keyMultifunction,
  597. KeyFullInformation,
  598. NULL,
  599. sizeof(multiKeyInformation),
  600. &length);
  601. if (status != STATUS_BUFFER_TOO_SMALL) {
  602. goto Cleanup;
  603. }
  604. multiKeyInformation = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  605. if (multiKeyInformation == NULL) {
  606. status = STATUS_INSUFFICIENT_RESOURCES;
  607. goto Cleanup;
  608. }
  609. status = ZwQueryKey(keyMultifunction,
  610. KeyFullInformation,
  611. multiKeyInformation,
  612. length,
  613. &length);
  614. if (!NT_SUCCESS(status)) {
  615. goto Cleanup;
  616. }
  617. // includes space for a terminating null that will be added later.
  618. maxKeyLength = multiKeyInformation->MaxNameLen +
  619. sizeof(KEY_BASIC_INFORMATION) + sizeof(WCHAR);
  620. //
  621. // Allocate buffer used for storing subkeys that we are enumerated
  622. // under multifunction.
  623. //
  624. keyInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, maxKeyLength);
  625. if (keyInfo == NULL) {
  626. status = STATUS_INSUFFICIENT_RESOURCES;
  627. goto Cleanup;
  628. }
  629. //
  630. // Allocate buffer large enough to store a value containing REG_SZ
  631. // 'PCI BIOS'. We hope to find such a value under one of the
  632. // multifunction subkeys
  633. //
  634. identifierValueLen = sizeof(PCIIR_IDENTIFIER) +
  635. sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  636. identifierValueInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, identifierValueLen);
  637. if (identifierValueInfo == NULL) {
  638. status = STATUS_INSUFFICIENT_RESOURCES;
  639. goto Cleanup;
  640. }
  641. //
  642. // Enumerate subkeys of multifunction key looking for keys with an
  643. // Identifier value of "PCI BIOS". If we find one, look for the
  644. // irq routing table in the tree below.
  645. //
  646. i = 0;
  647. do {
  648. status = ZwEnumerateKey(keyMultifunction,
  649. i,
  650. KeyBasicInformation,
  651. keyInfo,
  652. maxKeyLength,
  653. &length);
  654. if (NT_SUCCESS(status)) {
  655. //
  656. // Found a key, now we need to open it and check the
  657. // 'Identifier' value to see if it is 'PCI BIOS'
  658. //
  659. keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  660. result = PciOpenKey(keyInfo->Name,
  661. keyMultifunction,
  662. &keyTable,
  663. &status);
  664. if (result) {
  665. //
  666. // Checking 'Identifier' value to see if it contains 'PCI BIOS'
  667. //
  668. RtlInitUnicodeString(&unicodeString, VALUE_IDENTIFIER);
  669. status = ZwQueryValueKey(keyTable,
  670. &unicodeString,
  671. KeyValuePartialInformation,
  672. identifierValueInfo,
  673. identifierValueLen,
  674. &length);
  675. if (NT_SUCCESS(status) &&
  676. RtlEqualMemory((PCHAR)identifierValueInfo->Data,
  677. PCIIR_IDENTIFIER,
  678. identifierValueInfo->DataLength))
  679. {
  680. //
  681. // This is the PCI BIOS key. Try to get PCI IRQ
  682. // routing table. This is the key we were looking
  683. // for so regardless of succss, break out.
  684. //
  685. status = PciGetRegistryValue(VALUE_CONFIGURATION_DATA,
  686. KEY_IRQ_ROUTING_TABLE,
  687. keyTable,
  688. &irqTable,
  689. &length);
  690. ZwClose(keyTable);
  691. break;
  692. }
  693. ZwClose(keyTable);
  694. }
  695. } else {
  696. //
  697. // If not NT_SUCCESS, only alowable value is
  698. // STATUS_NO_MORE_ENTRIES,... otherwise, someone
  699. // is playing with the keys as we enumerate
  700. //
  701. ASSERT(status == STATUS_NO_MORE_ENTRIES);
  702. break;
  703. }
  704. i++;
  705. }
  706. while (status != STATUS_NO_MORE_ENTRIES);
  707. if (NT_SUCCESS(status) && irqTable) {
  708. //
  709. // The routing table is stored as a resource and thus we need
  710. // to trim off the CM_FULL_RESOURCE_DESCRIPTOR that
  711. // lives in front of the actual table.
  712. //
  713. //
  714. // Perform sanity checks on the table.
  715. //
  716. if (length < (sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
  717. sizeof(PCI_IRQ_ROUTING_TABLE))) {
  718. ExFreePool(irqTable);
  719. status = STATUS_UNSUCCESSFUL;
  720. goto Cleanup;
  721. }
  722. length -= sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  723. if (((PPCI_IRQ_ROUTING_TABLE) (irqTable + sizeof(CM_FULL_RESOURCE_DESCRIPTOR)))->TableSize > length) {
  724. ExFreePool(irqTable);
  725. status = STATUS_UNSUCCESSFUL;
  726. goto Cleanup;
  727. }
  728. //
  729. // Create a new table minus the header.
  730. //
  731. *RoutingTable = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  732. if (*RoutingTable) {
  733. RtlMoveMemory(*RoutingTable,
  734. ((PUCHAR) irqTable) + sizeof(CM_FULL_RESOURCE_DESCRIPTOR),
  735. length);
  736. status = STATUS_SUCCESS;
  737. } else {
  738. status = STATUS_INSUFFICIENT_RESOURCES;
  739. }
  740. ExFreePool(irqTable);
  741. }
  742. Cleanup:
  743. if (identifierValueInfo != NULL) {
  744. ExFreePool(identifierValueInfo);
  745. }
  746. if (keyInfo != NULL) {
  747. ExFreePool(keyInfo);
  748. }
  749. if (multiKeyInformation != NULL) {
  750. ExFreePool(multiKeyInformation);
  751. }
  752. if (keyMultifunction != NULL) {
  753. ZwClose(keyMultifunction);
  754. }
  755. return status;
  756. }
  757. NTSTATUS
  758. PciGetDebugPorts(
  759. IN HANDLE ServiceHandle
  760. )
  761. /*++
  762. Routine Description:
  763. Looks in the PCI service key for debug port info and puts in into
  764. the PciDebugPorts global table.
  765. Arguments:
  766. ServiceHandle - handle to the PCI service key passed into DriverEntry
  767. Return Value:
  768. Status
  769. --*/
  770. {
  771. NTSTATUS status;
  772. ULONG index;
  773. WCHAR indexString[4];
  774. PULONG buffer = NULL;
  775. ULONG segment, bus, device, function, length;
  776. for (index = 0; index < MAX_DEBUGGING_DEVICES_SUPPORTED; index++) {
  777. _snwprintf(indexString, sizeof(indexString)/sizeof(WCHAR), L"%d", index);
  778. status = PciGetRegistryValue(L"Bus",
  779. indexString,
  780. ServiceHandle,
  781. &buffer,
  782. &length
  783. );
  784. if (!NT_SUCCESS(status)) {
  785. continue;
  786. }
  787. //
  788. // This is formatted as 31:8 Segment Number, 7:0 Bus Number
  789. //
  790. segment = (*buffer & 0xFFFFFF00) >> 8;
  791. bus = *buffer & 0x000000FF;
  792. ExFreePool(buffer);
  793. buffer = NULL;
  794. status = PciGetRegistryValue(L"Slot",
  795. indexString,
  796. ServiceHandle,
  797. &buffer,
  798. &length
  799. );
  800. if (!NT_SUCCESS(status)) {
  801. goto exit;
  802. }
  803. //
  804. // This is formatted as 7:5 Function Number, 4:0 Device Number
  805. //
  806. device = *buffer & 0x0000001F;
  807. function = (*buffer & 0x000000E0) >> 5;
  808. ExFreePool(buffer);
  809. buffer = NULL;
  810. PciDebugPrint(PciDbgInformative,
  811. "Debug device @ Segment %x, %x.%x.%x\n",
  812. segment,
  813. bus,
  814. device,
  815. function
  816. );
  817. //
  818. // We don't currently handle segment numbers for config space...
  819. //
  820. ASSERT(segment == 0);
  821. PciDebugPorts[index].Bus = bus;
  822. PciDebugPorts[index].Slot.u.bits.DeviceNumber = device;
  823. PciDebugPorts[index].Slot.u.bits.FunctionNumber = function;
  824. //
  825. // Remember we are using the debug port
  826. //
  827. PciDebugPortsCount++;
  828. }
  829. status = STATUS_SUCCESS;
  830. exit:
  831. if (buffer) {
  832. ExFreePool(buffer);
  833. }
  834. return status;
  835. }