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.

1454 lines
39 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. #include <ntacpi.h>
  13. NTSTATUS
  14. DriverEntry(
  15. IN PDRIVER_OBJECT DriverObject,
  16. IN PUNICODE_STRING RegistryPath
  17. );
  18. VOID
  19. PciDriverUnload(
  20. IN PDRIVER_OBJECT DriverObject
  21. );
  22. NTSTATUS
  23. PciBuildHackTable(
  24. IN HANDLE HackTableKey
  25. );
  26. NTSTATUS
  27. PciGetIrqRoutingTableFromRegistry(
  28. PPCI_IRQ_ROUTING_TABLE *RoutingTable
  29. );
  30. NTSTATUS
  31. PciGetDebugPorts(
  32. IN HANDLE ServiceHandle
  33. );
  34. NTSTATUS
  35. PciAcpiFindRsdt(
  36. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  37. );
  38. PVOID
  39. PciGetAcpiTable(
  40. IN ULONG Signature
  41. );
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(INIT, DriverEntry)
  44. #pragma alloc_text(INIT, PciBuildHackTable)
  45. #pragma alloc_text(INIT, PciGetIrqRoutingTableFromRegistry)
  46. #pragma alloc_text(INIT, PciGetDebugPorts)
  47. #pragma alloc_text(INIT, PciAcpiFindRsdt)
  48. #pragma alloc_text(INIT, PciGetAcpiTable)
  49. #pragma alloc_text(PAGE, PciDriverUnload)
  50. #endif
  51. PDRIVER_OBJECT PciDriverObject;
  52. BOOLEAN PciLockDeviceResources;
  53. ULONG PciSystemWideHackFlags;
  54. ULONG PciEnableNativeModeATA;
  55. //
  56. // List of FDOs created by this driver.
  57. //
  58. SINGLE_LIST_ENTRY PciFdoExtensionListHead;
  59. LONG PciRootBusCount;
  60. //
  61. // PciAssignBusNumbers - this flag indicates whether we should try to assign
  62. // bus numbers to an unconfigured bridge. It is set once we know if the enumerator
  63. // of the PCI bus provides sufficient support.
  64. //
  65. BOOLEAN PciAssignBusNumbers = FALSE;
  66. //
  67. // PciRunningDatacenter - set to TRUE if we are running on the Datacenter SKU
  68. //
  69. BOOLEAN PciRunningDatacenter = FALSE;
  70. //
  71. // This locks all PCI's global data structures
  72. //
  73. FAST_MUTEX PciGlobalLock;
  74. //
  75. // This locks changes to bus numbers
  76. //
  77. FAST_MUTEX PciBusLock;
  78. //
  79. // Table of hacks for broken hardware read from the registry at init.
  80. // Protected by PciGlobalSpinLock and in none paged pool as it is needed at
  81. // dispatch level
  82. //
  83. PPCI_HACK_TABLE_ENTRY PciHackTable = NULL;
  84. // Will point to PCI IRQ Routing Table if one was found in the registry.
  85. PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable = NULL;
  86. //
  87. // Debug ports we support
  88. //
  89. PCI_DEBUG_PORT PciDebugPorts[MAX_DEBUGGING_DEVICES_SUPPORTED];
  90. ULONG PciDebugPortsCount;
  91. //
  92. // Watchdog timer resource table
  93. //
  94. PWATCHDOG_TIMER_RESOURCE_TABLE WdTable;
  95. #define PATH_CCS L"\\Registry\\Machine\\System\\CurrentControlSet"
  96. #define KEY_BIOS_INFO L"Control\\BiosInfo\\PCI"
  97. #define VALUE_PCI_LOCK L"PCILock"
  98. #define KEY_PNP_PCI L"Control\\PnP\\PCI"
  99. #define VALUE_PCI_HACKFLAGS L"HackFlags"
  100. #define VALUE_ENABLE_NATA L"EnableNativeModeATA"
  101. #define KEY_CONTROL L"Control"
  102. #define VALUE_OSLOADOPT L"SystemStartOptions"
  103. #define KEY_MULTIFUNCTION L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultiFunctionAdapter"
  104. #define KEY_IRQ_ROUTING_TABLE L"RealModeIrqRoutingTable\\0"
  105. #define VALUE_IDENTIFIER L"Identifier"
  106. #define VALUE_CONFIGURATION_DATA L"Configuration Data"
  107. #define PCIIR_IDENTIFIER L"PCI BIOS"
  108. #define ACPI_BIOS_ID L"ACPI BIOS"
  109. #define HACKFMT_VENDORDEV (sizeof(L"VVVVDDDD") - sizeof(UNICODE_NULL))
  110. #define HACKFMT_VENDORDEVREVISION (sizeof(L"VVVVDDDDRR") - sizeof(UNICODE_NULL))
  111. #define HACKFMT_SUBSYSTEM (sizeof(L"VVVVDDDDSSSSssss") - sizeof(UNICODE_NULL))
  112. #define HACKFMT_SUBSYSTEMREVISION (sizeof(L"VVVVDDDDSSSSssssRR") - sizeof(UNICODE_NULL))
  113. #define HACKFMT_MAX_LENGTH HACKFMT_SUBSYSTEMREVISION
  114. #define HACKFMT_DEVICE_OFFSET 4
  115. #define HACKFMT_SUBVENDOR_OFFSET 8
  116. #define HACKFMT_SUBSYSTEM_OFFSET 12
  117. NTSTATUS
  118. DriverEntry(
  119. IN PDRIVER_OBJECT DriverObject,
  120. IN PUNICODE_STRING RegistryPath
  121. )
  122. /*++
  123. Routine Description:
  124. Entrypoint needed to initialize the PCI bus enumerator.
  125. Arguments:
  126. DriverObject - Pointer to the driver object created by the system.
  127. RegistryPath - Pointer to the unicode registry service path.
  128. Return Value:
  129. NT status.
  130. --*/
  131. {
  132. NTSTATUS status;
  133. ULONG length;
  134. PWCHAR osLoadOptions;
  135. HANDLE ccsHandle = NULL, serviceKey = NULL, paramsKey = NULL, debugKey = NULL;
  136. PULONG registryValue;
  137. ULONG registryValueLength;
  138. OBJECT_ATTRIBUTES attributes;
  139. UNICODE_STRING pciLockString, osLoadOptionsString;
  140. //
  141. // Fill in the driver object
  142. //
  143. DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp;
  144. DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp;
  145. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp;
  146. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp;
  147. DriverObject->DriverUnload = PciDriverUnload;
  148. DriverObject->DriverExtension->AddDevice = PciAddDevice;
  149. PciDriverObject = DriverObject;
  150. //
  151. // Open our service key and retrieve the hack table
  152. //
  153. InitializeObjectAttributes(&attributes,
  154. RegistryPath,
  155. OBJ_CASE_INSENSITIVE,
  156. NULL,
  157. NULL
  158. );
  159. status = ZwOpenKey(&serviceKey,
  160. KEY_READ,
  161. &attributes
  162. );
  163. if (!NT_SUCCESS(status)) {
  164. return status;
  165. }
  166. //
  167. // Get the Hack table from the registry
  168. //
  169. if (!PciOpenKey(L"Parameters", serviceKey, KEY_READ, &paramsKey, &status)) {
  170. goto exit;
  171. }
  172. status = PciBuildHackTable(paramsKey);
  173. if (!NT_SUCCESS(status)) {
  174. goto exit;
  175. }
  176. //
  177. // Get any info about debugging ports from the registry so we don't perturb
  178. // them
  179. //
  180. if (PciOpenKey(L"Debug", serviceKey, KEY_READ, &debugKey, &status)) {
  181. status = PciGetDebugPorts(debugKey);
  182. if (!NT_SUCCESS(status)) {
  183. goto exit;
  184. }
  185. }
  186. //
  187. // Initialize the list of FDO Extensions.
  188. //
  189. PciFdoExtensionListHead.Next = NULL;
  190. PciRootBusCount = 0;
  191. ExInitializeFastMutex(&PciGlobalLock);
  192. ExInitializeFastMutex(&PciBusLock);
  193. //
  194. // Need access to the CurrentControlSet for various
  195. // initialization chores.
  196. //
  197. if (!PciOpenKey(PATH_CCS, NULL, KEY_READ, &ccsHandle, &status)) {
  198. goto exit;
  199. }
  200. //
  201. // Get OSLOADOPTIONS and see if PCILOCK was specified.
  202. // (Unless the driver is build to force PCILOCK).
  203. // (Note: Can't check for leading '/', it was stripped
  204. // before getting put in the registry).
  205. //
  206. PciLockDeviceResources = FALSE;
  207. if (NT_SUCCESS(PciGetRegistryValue(VALUE_OSLOADOPT,
  208. KEY_CONTROL,
  209. ccsHandle,
  210. REG_SZ,
  211. &osLoadOptions,
  212. &length
  213. ))) {
  214. //
  215. // Build counted versions of the stings we need to search
  216. //
  217. PciConstStringToUnicodeString(&pciLockString, L"PCILOCK");
  218. //
  219. // We assume that the string coming from the registry is NUL terminated
  220. // and if this isn't the case, the MaximumLength in the counted string
  221. // prevents us from over running our buffer. If the string is larger
  222. // than MAX_USHORT bytes then we truncate it.
  223. //
  224. osLoadOptionsString.Buffer = osLoadOptions;
  225. osLoadOptionsString.Length = (USHORT)(length - sizeof(UNICODE_NULL));
  226. osLoadOptionsString.MaximumLength = (USHORT) length;
  227. if (PciUnicodeStringStrStr(&osLoadOptionsString, &pciLockString, TRUE)) {
  228. PciLockDeviceResources = TRUE;
  229. }
  230. ExFreePool(osLoadOptions);
  231. }
  232. if (!PciLockDeviceResources) {
  233. PULONG pciLockValue;
  234. ULONG pciLockLength;
  235. if (NT_SUCCESS(PciGetRegistryValue( VALUE_PCI_LOCK,
  236. KEY_BIOS_INFO,
  237. ccsHandle,
  238. REG_DWORD,
  239. &pciLockValue,
  240. &pciLockLength))) {
  241. if (pciLockLength == sizeof(ULONG) && *pciLockValue == 1) {
  242. PciLockDeviceResources = TRUE;
  243. }
  244. ExFreePool(pciLockValue);
  245. }
  246. }
  247. PciSystemWideHackFlags = 0;
  248. if (NT_SUCCESS(PciGetRegistryValue( VALUE_PCI_HACKFLAGS,
  249. KEY_PNP_PCI,
  250. ccsHandle,
  251. REG_DWORD,
  252. &registryValue,
  253. &registryValueLength))) {
  254. if (registryValueLength == sizeof(ULONG)) {
  255. PciSystemWideHackFlags = *registryValue;
  256. }
  257. ExFreePool(registryValue);
  258. }
  259. PciEnableNativeModeATA = 0;
  260. if (NT_SUCCESS(PciGetRegistryValue( VALUE_ENABLE_NATA,
  261. KEY_PNP_PCI,
  262. ccsHandle,
  263. REG_DWORD,
  264. &registryValue,
  265. &registryValueLength))) {
  266. if (registryValueLength == sizeof(ULONG)) {
  267. PciEnableNativeModeATA = *registryValue;
  268. }
  269. ExFreePool(registryValue);
  270. }
  271. //
  272. // Build some global data structures
  273. //
  274. status = PciBuildDefaultExclusionLists();
  275. if (!NT_SUCCESS(status)) {
  276. return status;
  277. }
  278. //
  279. // If we don't find an IRQ routing table, no UI number information
  280. // will be returned for the PDOs using this mechanism. ACPI may
  281. // still filter in UI numbers.
  282. //
  283. PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable);
  284. //
  285. // Override the functions that used to be in the HAL but are now in the
  286. // PCI driver
  287. //
  288. PciHookHal();
  289. //
  290. // Enable the hardware verifier code if appropriate.
  291. //
  292. PciVerifierInit(DriverObject);
  293. PciRunningDatacenter = PciIsDatacenter();
  294. if (PciRunningDatacenter) {
  295. PciDebugPrint(
  296. PciDbgInformative,
  297. "PCI running on datacenter build\n"
  298. );
  299. }
  300. //
  301. // Get the WD ACPI table
  302. //
  303. WdTable = (PWATCHDOG_TIMER_RESOURCE_TABLE) PciGetAcpiTable( WDTT_SIGNATURE );
  304. status = STATUS_SUCCESS;
  305. exit:
  306. if (ccsHandle) {
  307. ZwClose(ccsHandle);
  308. }
  309. if (serviceKey) {
  310. ZwClose(serviceKey);
  311. }
  312. if (paramsKey) {
  313. ZwClose(paramsKey);
  314. }
  315. if (debugKey) {
  316. ZwClose(debugKey);
  317. }
  318. return status;
  319. }
  320. VOID
  321. PciDriverUnload(
  322. IN PDRIVER_OBJECT DriverObject
  323. )
  324. /*++
  325. Routine Description:
  326. Entrypoint used to unload the PCI driver. Does nothing, the
  327. PCI driver is never unloaded.
  328. Arguments:
  329. DriverObject - Pointer to the driver object created by the system.
  330. Return Value:
  331. None.
  332. --*/
  333. {
  334. //
  335. // Disable the hardware verifier code if appropriate.
  336. //
  337. PciVerifierUnload(DriverObject);
  338. //
  339. // Unallocate anything we can find.
  340. //
  341. RtlFreeRangeList(&PciIsaBitExclusionList);
  342. RtlFreeRangeList(&PciVgaAndIsaBitExclusionList);
  343. //
  344. // Free IRQ routing table if we have one
  345. //
  346. if (PciIrqRoutingTable != NULL) {
  347. ExFreePool(PciIrqRoutingTable);
  348. }
  349. //
  350. // Attempt to remove our hooks in case we actually get unloaded.
  351. //
  352. PciUnhookHal();
  353. }
  354. NTSTATUS
  355. PciBuildHackTable(
  356. IN HANDLE HackTableKey
  357. )
  358. {
  359. NTSTATUS status;
  360. PKEY_FULL_INFORMATION keyInfo = NULL;
  361. ULONG hackCount, size, index;
  362. USHORT temp;
  363. PPCI_HACK_TABLE_ENTRY entry;
  364. ULONGLONG data;
  365. PKEY_VALUE_FULL_INFORMATION valueInfo = NULL;
  366. ULONG valueInfoSize = sizeof(KEY_VALUE_FULL_INFORMATION)
  367. + HACKFMT_MAX_LENGTH +
  368. + sizeof(ULONGLONG);
  369. //
  370. // Get the key info so we know how many hack values there are.
  371. // This does not change during system initialization.
  372. //
  373. status = ZwQueryKey(HackTableKey,
  374. KeyFullInformation,
  375. NULL,
  376. 0,
  377. &size
  378. );
  379. if (status != STATUS_BUFFER_TOO_SMALL) {
  380. PCI_ASSERT(!NT_SUCCESS(status));
  381. goto cleanup;
  382. }
  383. PCI_ASSERT(size > 0);
  384. keyInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, size);
  385. if (!keyInfo) {
  386. status = STATUS_INSUFFICIENT_RESOURCES;
  387. goto cleanup;
  388. }
  389. status = ZwQueryKey(HackTableKey,
  390. KeyFullInformation,
  391. keyInfo,
  392. size,
  393. &size
  394. );
  395. if (!NT_SUCCESS(status)) {
  396. goto cleanup;
  397. }
  398. hackCount = keyInfo->Values;
  399. ExFreePool(keyInfo);
  400. keyInfo = NULL;
  401. //
  402. // Allocate and initialize the hack table
  403. //
  404. PciHackTable = ExAllocatePool(NonPagedPool,
  405. (hackCount + 1) * sizeof(PCI_HACK_TABLE_ENTRY)
  406. );
  407. if (!PciHackTable) {
  408. status = STATUS_INSUFFICIENT_RESOURCES;
  409. goto cleanup;
  410. }
  411. //
  412. // Allocate a valueInfo buffer big enough for the biggest valid
  413. // format and a ULONGLONG worth of data.
  414. //
  415. valueInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, valueInfoSize);
  416. if (!valueInfo) {
  417. status = STATUS_INSUFFICIENT_RESOURCES;
  418. goto cleanup;
  419. }
  420. entry = PciHackTable;
  421. for (index = 0; index < hackCount; index++) {
  422. status = ZwEnumerateValueKey(HackTableKey,
  423. index,
  424. KeyValueFullInformation,
  425. valueInfo,
  426. valueInfoSize,
  427. &size
  428. );
  429. if (!NT_SUCCESS(status)) {
  430. if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL) {
  431. //
  432. // All out data is of fixed length and the buffer is big enough
  433. // so this can't be for us.
  434. //
  435. continue;
  436. } else {
  437. goto cleanup;
  438. }
  439. }
  440. //
  441. // Get pointer to the data if its of the right type
  442. //
  443. if ((valueInfo->Type == REG_BINARY) &&
  444. (valueInfo->DataLength == sizeof(ULONGLONG))) {
  445. data = *(ULONGLONG UNALIGNED *)(((PUCHAR)valueInfo) + valueInfo->DataOffset);
  446. } else {
  447. //
  448. // We only deal in ULONGLONGs
  449. //
  450. continue;
  451. }
  452. //
  453. // Now see if the name is formatted like we expect it to be:
  454. // VVVVDDDD
  455. // VVVVDDDDRR
  456. // VVVVDDDDSSSSssss
  457. // VVVVDDDDSSSSssssRR
  458. if ((valueInfo->NameLength != HACKFMT_VENDORDEV) &&
  459. (valueInfo->NameLength != HACKFMT_VENDORDEVREVISION) &&
  460. (valueInfo->NameLength != HACKFMT_SUBSYSTEM) &&
  461. (valueInfo->NameLength != HACKFMT_SUBSYSTEMREVISION)) {
  462. //
  463. // This isn't ours
  464. //
  465. PciDebugPrint(
  466. PciDbgInformative,
  467. "Skipping hack entry with invalid length name\n"
  468. );
  469. continue;
  470. }
  471. //
  472. // This looks plausable - try to parse it and fill in a hack table
  473. // entry
  474. //
  475. RtlZeroMemory(entry, sizeof(PCI_HACK_TABLE_ENTRY));
  476. //
  477. // Look for DeviceID and VendorID (VVVVDDDD)
  478. //
  479. if (!PciStringToUSHORT(valueInfo->Name, &entry->VendorID)) {
  480. continue;
  481. }
  482. if (!PciStringToUSHORT(valueInfo->Name + HACKFMT_DEVICE_OFFSET,
  483. &entry->DeviceID)) {
  484. continue;
  485. }
  486. //
  487. // Look for SubsystemVendorID/SubSystemID (SSSSssss)
  488. //
  489. if ((valueInfo->NameLength == HACKFMT_SUBSYSTEM) ||
  490. (valueInfo->NameLength == HACKFMT_SUBSYSTEMREVISION)) {
  491. if (!PciStringToUSHORT(valueInfo->Name + HACKFMT_SUBVENDOR_OFFSET,
  492. &entry->SubVendorID)) {
  493. continue;
  494. }
  495. if (!PciStringToUSHORT(valueInfo->Name + HACKFMT_SUBSYSTEM_OFFSET,
  496. &entry->SubSystemID)) {
  497. continue;
  498. }
  499. entry->Flags |= PCI_HACK_FLAG_SUBSYSTEM;
  500. }
  501. //
  502. // Look for RevisionID (RR)
  503. //
  504. if ((valueInfo->NameLength == HACKFMT_VENDORDEVREVISION) ||
  505. (valueInfo->NameLength == HACKFMT_SUBSYSTEMREVISION)) {
  506. if (PciStringToUSHORT(valueInfo->Name +
  507. (valueInfo->NameLength/sizeof(WCHAR) - 4), &temp)) {
  508. entry->RevisionID = (UCHAR)temp & 0xFF;
  509. entry->Flags |= PCI_HACK_FLAG_REVISION;
  510. } else {
  511. continue;
  512. }
  513. }
  514. PCI_ASSERT(entry->VendorID != 0xFFFF);
  515. //
  516. // Fill in the entry
  517. //
  518. entry->HackFlags = data;
  519. PciDebugPrint(
  520. PciDbgInformative,
  521. "Adding Hack entry for Vendor:0x%04x Device:0x%04x ",
  522. entry->VendorID, entry->DeviceID
  523. );
  524. if (entry->Flags & PCI_HACK_FLAG_SUBSYSTEM) {
  525. PciDebugPrint(
  526. PciDbgInformative,
  527. "SybSys:0x%04x SubVendor:0x%04x ",
  528. entry->SubSystemID, entry->SubVendorID
  529. );
  530. }
  531. if (entry->Flags & PCI_HACK_FLAG_REVISION) {
  532. PciDebugPrint(
  533. PciDbgInformative,
  534. "Revision:0x%02x",
  535. (ULONG) entry->RevisionID
  536. );
  537. }
  538. PciDebugPrint(
  539. PciDbgInformative,
  540. " = 0x%I64x\n",
  541. entry->HackFlags
  542. );
  543. entry++;
  544. }
  545. PCI_ASSERT(entry < (PciHackTable + hackCount + 1));
  546. //
  547. // Terminate the table with an invalid VendorID
  548. //
  549. entry->VendorID = 0xFFFF;
  550. ExFreePool(valueInfo);
  551. return STATUS_SUCCESS;
  552. cleanup:
  553. PCI_ASSERT(!NT_SUCCESS(status));
  554. if (keyInfo) {
  555. ExFreePool(keyInfo);
  556. }
  557. if (valueInfo) {
  558. ExFreePool(valueInfo);
  559. }
  560. if (PciHackTable) {
  561. ExFreePool(PciHackTable);
  562. PciHackTable = NULL;
  563. }
  564. return status;
  565. }
  566. NTSTATUS
  567. PciGetIrqRoutingTableFromRegistry(
  568. PPCI_IRQ_ROUTING_TABLE *RoutingTable
  569. )
  570. /*++
  571. Routine Description:
  572. Retrieve the IRQ routing table from the registry if present so it
  573. can be used to determine the UI Number (slot #) that will be used
  574. later when answering capabilities queries on the PDOs.
  575. Searches HKLM\Hardware\Description\System\MultiFunctionAdapter for
  576. a subkey with an "Identifier" value equal to "PCI BIOS". It then looks at
  577. "RealModeIrqRoutingTable\0" from this subkey to find actual irq routing
  578. table value. This value has a CM_FULL_RESOURCE_DESCRIPTOR in front of it.
  579. Hals that suppirt irq routing tables have a similar routine.
  580. Arguments:
  581. RoutingTable - Pointer to a pointer to the routing table returned if any
  582. Return Value:
  583. NTSTATUS - failure indicates inability to get irq routing table
  584. information from the registry.
  585. --*/
  586. {
  587. PUCHAR irqTable = NULL;
  588. PKEY_FULL_INFORMATION multiKeyInformation = NULL;
  589. PKEY_BASIC_INFORMATION keyInfo = NULL;
  590. PKEY_VALUE_PARTIAL_INFORMATION identifierValueInfo = NULL;
  591. UNICODE_STRING unicodeString;
  592. HANDLE keyMultifunction = NULL, keyTable = NULL;
  593. ULONG i, length, maxKeyLength, identifierValueLen;
  594. BOOLEAN result;
  595. NTSTATUS status;
  596. //
  597. // Open the multifunction key
  598. //
  599. result = PciOpenKey(KEY_MULTIFUNCTION,
  600. NULL,
  601. KEY_READ,
  602. &keyMultifunction,
  603. &status);
  604. if (!result) {
  605. goto Cleanup;
  606. }
  607. //
  608. // Do allocation of buffers up front
  609. //
  610. //
  611. // Determine maximum size of a keyname under the multifunction key
  612. //
  613. status = ZwQueryKey(keyMultifunction,
  614. KeyFullInformation,
  615. NULL,
  616. sizeof(multiKeyInformation),
  617. &length);
  618. if (status != STATUS_BUFFER_TOO_SMALL) {
  619. goto Cleanup;
  620. }
  621. multiKeyInformation = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  622. if (multiKeyInformation == NULL) {
  623. status = STATUS_INSUFFICIENT_RESOURCES;
  624. goto Cleanup;
  625. }
  626. status = ZwQueryKey(keyMultifunction,
  627. KeyFullInformation,
  628. multiKeyInformation,
  629. length,
  630. &length);
  631. if (!NT_SUCCESS(status)) {
  632. goto Cleanup;
  633. }
  634. // includes space for a terminating null that will be added later.
  635. maxKeyLength = multiKeyInformation->MaxNameLen +
  636. sizeof(KEY_BASIC_INFORMATION) + sizeof(WCHAR);
  637. //
  638. // Allocate buffer used for storing subkeys that we are enumerated
  639. // under multifunction.
  640. //
  641. keyInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, maxKeyLength);
  642. if (keyInfo == NULL) {
  643. status = STATUS_INSUFFICIENT_RESOURCES;
  644. goto Cleanup;
  645. }
  646. //
  647. // Allocate buffer large enough to store a value containing REG_SZ
  648. // 'PCI BIOS'. We hope to find such a value under one of the
  649. // multifunction subkeys
  650. //
  651. identifierValueLen = sizeof(PCIIR_IDENTIFIER) +
  652. sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  653. identifierValueInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, identifierValueLen);
  654. if (identifierValueInfo == NULL) {
  655. status = STATUS_INSUFFICIENT_RESOURCES;
  656. goto Cleanup;
  657. }
  658. //
  659. // Enumerate subkeys of multifunction key looking for keys with an
  660. // Identifier value of "PCI BIOS". If we find one, look for the
  661. // irq routing table in the tree below.
  662. //
  663. i = 0;
  664. do {
  665. status = ZwEnumerateKey(keyMultifunction,
  666. i,
  667. KeyBasicInformation,
  668. keyInfo,
  669. maxKeyLength,
  670. &length);
  671. if (NT_SUCCESS(status)) {
  672. //
  673. // Found a key, now we need to open it and check the
  674. // 'Identifier' value to see if it is 'PCI BIOS'
  675. //
  676. keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  677. result = PciOpenKey(keyInfo->Name,
  678. keyMultifunction,
  679. KEY_READ,
  680. &keyTable,
  681. &status);
  682. if (result) {
  683. //
  684. // Checking 'Identifier' value to see if it contains 'PCI BIOS'
  685. //
  686. RtlInitUnicodeString(&unicodeString, VALUE_IDENTIFIER);
  687. status = ZwQueryValueKey(keyTable,
  688. &unicodeString,
  689. KeyValuePartialInformation,
  690. identifierValueInfo,
  691. identifierValueLen,
  692. &length);
  693. if (NT_SUCCESS(status) &&
  694. RtlEqualMemory((PCHAR)identifierValueInfo->Data,
  695. PCIIR_IDENTIFIER,
  696. identifierValueInfo->DataLength))
  697. {
  698. //
  699. // This is the PCI BIOS key. Try to get PCI IRQ
  700. // routing table. This is the key we were looking
  701. // for so regardless of succss, break out.
  702. //
  703. status = PciGetRegistryValue(VALUE_CONFIGURATION_DATA,
  704. KEY_IRQ_ROUTING_TABLE,
  705. keyTable,
  706. REG_FULL_RESOURCE_DESCRIPTOR,
  707. &irqTable,
  708. &length);
  709. ZwClose(keyTable);
  710. break;
  711. }
  712. ZwClose(keyTable);
  713. }
  714. } else {
  715. //
  716. // If not NT_SUCCESS, only alowable value is
  717. // STATUS_NO_MORE_ENTRIES,... otherwise, someone
  718. // is playing with the keys as we enumerate
  719. //
  720. PCI_ASSERT(status == STATUS_NO_MORE_ENTRIES);
  721. break;
  722. }
  723. i++;
  724. } while (status != STATUS_NO_MORE_ENTRIES);
  725. if (NT_SUCCESS(status) && irqTable) {
  726. //
  727. // The routing table is stored as a resource and thus we need
  728. // to trim off the CM_FULL_RESOURCE_DESCRIPTOR that
  729. // lives in front of the actual table.
  730. //
  731. //
  732. // Perform sanity checks on the table.
  733. //
  734. if (length < (sizeof(CM_FULL_RESOURCE_DESCRIPTOR) +
  735. sizeof(PCI_IRQ_ROUTING_TABLE))) {
  736. ExFreePool(irqTable);
  737. status = STATUS_UNSUCCESSFUL;
  738. goto Cleanup;
  739. }
  740. length -= sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  741. if (((PPCI_IRQ_ROUTING_TABLE) (irqTable + sizeof(CM_FULL_RESOURCE_DESCRIPTOR)))->TableSize > length) {
  742. ExFreePool(irqTable);
  743. status = STATUS_UNSUCCESSFUL;
  744. goto Cleanup;
  745. }
  746. //
  747. // Create a new table minus the header.
  748. //
  749. *RoutingTable = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  750. if (*RoutingTable) {
  751. RtlMoveMemory(*RoutingTable,
  752. ((PUCHAR) irqTable) + sizeof(CM_FULL_RESOURCE_DESCRIPTOR),
  753. length);
  754. status = STATUS_SUCCESS;
  755. } else {
  756. status = STATUS_INSUFFICIENT_RESOURCES;
  757. }
  758. ExFreePool(irqTable);
  759. }
  760. Cleanup:
  761. if (identifierValueInfo != NULL) {
  762. ExFreePool(identifierValueInfo);
  763. }
  764. if (keyInfo != NULL) {
  765. ExFreePool(keyInfo);
  766. }
  767. if (multiKeyInformation != NULL) {
  768. ExFreePool(multiKeyInformation);
  769. }
  770. if (keyMultifunction != NULL) {
  771. ZwClose(keyMultifunction);
  772. }
  773. return status;
  774. }
  775. NTSTATUS
  776. PciGetDebugPorts(
  777. IN HANDLE ServiceHandle
  778. )
  779. /*++
  780. Routine Description:
  781. Looks in the PCI service key for debug port info and puts in into
  782. the PciDebugPorts global table.
  783. Arguments:
  784. ServiceHandle - handle to the PCI service key passed into DriverEntry
  785. Return Value:
  786. Status
  787. --*/
  788. {
  789. NTSTATUS status;
  790. ULONG index;
  791. WCHAR indexString[sizeof("999")];
  792. PULONG buffer = NULL;
  793. ULONG segment, bus, device, function, length;
  794. BOOLEAN ok;
  795. C_ASSERT(MAX_DEBUGGING_DEVICES_SUPPORTED <= 999);
  796. for (index = 0; index < MAX_DEBUGGING_DEVICES_SUPPORTED; index++) {
  797. ok = SUCCEEDED(StringCbPrintfW(indexString, sizeof(indexString), L"%d", index));
  798. ASSERT(ok);
  799. status = PciGetRegistryValue(L"Bus",
  800. indexString,
  801. ServiceHandle,
  802. REG_DWORD,
  803. &buffer,
  804. &length
  805. );
  806. if (!NT_SUCCESS(status) || length != sizeof(ULONG)) {
  807. continue;
  808. }
  809. //
  810. // This is formatted as 31:8 Segment Number, 7:0 Bus Number
  811. //
  812. segment = (*buffer & 0xFFFFFF00) >> 8;
  813. bus = *buffer & 0x000000FF;
  814. ExFreePool(buffer);
  815. buffer = NULL;
  816. status = PciGetRegistryValue(L"Slot",
  817. indexString,
  818. ServiceHandle,
  819. REG_DWORD,
  820. &buffer,
  821. &length
  822. );
  823. if (!NT_SUCCESS(status) || length != sizeof(ULONG)) {
  824. goto exit;
  825. }
  826. //
  827. // This is formatted as 7:5 Function Number, 4:0 Device Number
  828. //
  829. device = *buffer & 0x0000001F;
  830. function = (*buffer & 0x000000E0) >> 5;
  831. ExFreePool(buffer);
  832. buffer = NULL;
  833. PciDebugPrint(PciDbgInformative,
  834. "Debug device @ Segment %x, %x.%x.%x\n",
  835. segment,
  836. bus,
  837. device,
  838. function
  839. );
  840. //
  841. // We don't currently handle segment numbers for config space...
  842. //
  843. PCI_ASSERT(segment == 0);
  844. PciDebugPorts[index].Bus = bus;
  845. PciDebugPorts[index].Slot.u.bits.DeviceNumber = device;
  846. PciDebugPorts[index].Slot.u.bits.FunctionNumber = function;
  847. //
  848. // Remember we are using the debug port
  849. //
  850. PciDebugPortsCount++;
  851. }
  852. status = STATUS_SUCCESS;
  853. exit:
  854. if (buffer) {
  855. ExFreePool(buffer);
  856. }
  857. return status;
  858. }
  859. NTSTATUS
  860. PciAcpiFindRsdt (
  861. OUT PACPI_BIOS_MULTI_NODE *AcpiMulti
  862. )
  863. {
  864. PKEY_FULL_INFORMATION multiKeyInformation = NULL;
  865. PKEY_BASIC_INFORMATION keyInfo = NULL;
  866. PKEY_VALUE_PARTIAL_INFORMATION identifierValueInfo = NULL;
  867. UNICODE_STRING unicodeString;
  868. HANDLE keyMultifunction = NULL, keyTable = NULL;
  869. PCM_PARTIAL_RESOURCE_LIST prl = NULL;
  870. PCM_PARTIAL_RESOURCE_DESCRIPTOR prd;
  871. PACPI_BIOS_MULTI_NODE multiNode;
  872. ULONG multiNodeSize;
  873. ULONG i, length, maxKeyLength, identifierValueLen;
  874. BOOLEAN result;
  875. NTSTATUS status;
  876. //
  877. // Open the multifunction key
  878. //
  879. result = PciOpenKey(KEY_MULTIFUNCTION,
  880. NULL,
  881. KEY_READ,
  882. &keyMultifunction,
  883. &status);
  884. if (!result) {
  885. goto Cleanup;
  886. }
  887. //
  888. // Do allocation of buffers up front
  889. //
  890. //
  891. // Determine maximum size of a keyname under the multifunction key
  892. //
  893. status = ZwQueryKey(keyMultifunction,
  894. KeyFullInformation,
  895. NULL,
  896. sizeof(multiKeyInformation),
  897. &length);
  898. if (status != STATUS_BUFFER_TOO_SMALL) {
  899. goto Cleanup;
  900. }
  901. multiKeyInformation = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, length);
  902. if (multiKeyInformation == NULL) {
  903. status = STATUS_INSUFFICIENT_RESOURCES;
  904. goto Cleanup;
  905. }
  906. status = ZwQueryKey(keyMultifunction,
  907. KeyFullInformation,
  908. multiKeyInformation,
  909. length,
  910. &length);
  911. if (!NT_SUCCESS(status)) {
  912. goto Cleanup;
  913. }
  914. // includes space for a terminating null that will be added later.
  915. maxKeyLength = multiKeyInformation->MaxNameLen +
  916. sizeof(KEY_BASIC_INFORMATION) + sizeof(WCHAR);
  917. //
  918. // Allocate buffer used for storing subkeys that we are enumerated
  919. // under multifunction.
  920. //
  921. keyInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, maxKeyLength);
  922. if (keyInfo == NULL) {
  923. status = STATUS_INSUFFICIENT_RESOURCES;
  924. goto Cleanup;
  925. }
  926. //
  927. // Allocate buffer large enough to store a value containing REG_SZ
  928. // 'ACPI BIOS'. We hope to find such a value under one of the
  929. // multifunction subkeys
  930. //
  931. identifierValueLen = sizeof(ACPI_BIOS_ID) + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
  932. identifierValueInfo = ExAllocatePool(PagedPool | POOL_COLD_ALLOCATION, identifierValueLen);
  933. if (identifierValueInfo == NULL) {
  934. status = STATUS_INSUFFICIENT_RESOURCES;
  935. goto Cleanup;
  936. }
  937. //
  938. // Enumerate subkeys of multifunction key looking for keys with an
  939. // Identifier value of "ACPI BIOS". If we find one, look for the
  940. // irq routing table in the tree below.
  941. //
  942. i = 0;
  943. do {
  944. status = ZwEnumerateKey(keyMultifunction,
  945. i,
  946. KeyBasicInformation,
  947. keyInfo,
  948. maxKeyLength,
  949. &length);
  950. if (NT_SUCCESS(status)) {
  951. //
  952. // Found a key, now we need to open it and check the
  953. // 'Identifier' value to see if it is 'ACPI BIOS'
  954. //
  955. keyInfo->Name[keyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  956. result = PciOpenKey(keyInfo->Name,
  957. keyMultifunction,
  958. KEY_READ,
  959. &keyTable,
  960. &status);
  961. if (result) {
  962. //
  963. // Checking 'Identifier' value to see if it contains 'ACPI BIOS'
  964. //
  965. RtlInitUnicodeString(&unicodeString, VALUE_IDENTIFIER);
  966. status = ZwQueryValueKey(keyTable,
  967. &unicodeString,
  968. KeyValuePartialInformation,
  969. identifierValueInfo,
  970. identifierValueLen,
  971. &length);
  972. if (NT_SUCCESS(status) &&
  973. RtlEqualMemory((PCHAR)identifierValueInfo->Data,
  974. ACPI_BIOS_ID,
  975. identifierValueInfo->DataLength))
  976. {
  977. //
  978. // This is the ACPI BIOS key. Try to get Configuration Data
  979. // This is the key we were looking
  980. // for so regardless of success, break out.
  981. //
  982. ZwClose(keyTable);
  983. status = PciGetRegistryValue(VALUE_CONFIGURATION_DATA,
  984. keyInfo->Name,
  985. keyMultifunction,
  986. REG_FULL_RESOURCE_DESCRIPTOR,
  987. &prl,
  988. &length);
  989. break;
  990. }
  991. ZwClose(keyTable);
  992. }
  993. } else {
  994. //
  995. // If not NT_SUCCESS, only alowable value is
  996. // STATUS_NO_MORE_ENTRIES,... otherwise, someone
  997. // is playing with the keys as we enumerate
  998. //
  999. PCI_ASSERT(status == STATUS_NO_MORE_ENTRIES);
  1000. break;
  1001. }
  1002. i++;
  1003. }
  1004. while (status != STATUS_NO_MORE_ENTRIES);
  1005. if (NT_SUCCESS(status) && prl) {
  1006. prd = &prl->PartialDescriptors[0];
  1007. multiNode = (PACPI_BIOS_MULTI_NODE)((PCHAR) prd + sizeof(CM_PARTIAL_RESOURCE_LIST));
  1008. multiNodeSize = sizeof(ACPI_BIOS_MULTI_NODE) + ((ULONG)(multiNode->Count - 1) * sizeof(ACPI_E820_ENTRY));
  1009. *AcpiMulti = (PACPI_BIOS_MULTI_NODE) ExAllocatePool(NonPagedPool,multiNodeSize);
  1010. if (*AcpiMulti == NULL) {
  1011. status = STATUS_INSUFFICIENT_RESOURCES;
  1012. goto Cleanup;
  1013. }
  1014. RtlCopyMemory(*AcpiMulti, multiNode, multiNodeSize);
  1015. }
  1016. Cleanup:
  1017. if (identifierValueInfo != NULL) {
  1018. ExFreePool(identifierValueInfo);
  1019. }
  1020. if (keyInfo != NULL) {
  1021. ExFreePool(keyInfo);
  1022. }
  1023. if (multiKeyInformation != NULL) {
  1024. ExFreePool(multiKeyInformation);
  1025. }
  1026. if (keyMultifunction != NULL) {
  1027. ZwClose(keyMultifunction);
  1028. }
  1029. if (prl) {
  1030. ExFreePool(prl);
  1031. }
  1032. return status;
  1033. }
  1034. PVOID
  1035. PciGetAcpiTable(
  1036. IN ULONG Signature
  1037. )
  1038. /*++
  1039. Routine Description:
  1040. This routine will retrieve any table referenced in the ACPI
  1041. RSDT.
  1042. Arguments:
  1043. Signature - Target table signature
  1044. Return Value:
  1045. pointer to a copy of the table, or NULL if not found
  1046. --*/
  1047. {
  1048. PACPI_BIOS_MULTI_NODE multiNode;
  1049. NTSTATUS status;
  1050. ULONG entry, rsdtEntries;
  1051. PDESCRIPTION_HEADER header;
  1052. PHYSICAL_ADDRESS physicalAddr;
  1053. PRSDT rsdt;
  1054. ULONG rsdtSize;
  1055. PVOID table = NULL;
  1056. //
  1057. // Get the physical address of the RSDT from the Registry
  1058. //
  1059. status = PciAcpiFindRsdt(&multiNode);
  1060. if (!NT_SUCCESS(status)) {
  1061. DbgPrint("AcpiFindRsdt() Failed!\n");
  1062. return NULL;
  1063. }
  1064. //
  1065. // Map down header to get total RSDT table size
  1066. //
  1067. header = (PDESCRIPTION_HEADER) MmMapIoSpace(multiNode->RsdtAddress, sizeof(DESCRIPTION_HEADER), MmNonCached);
  1068. if (!header) {
  1069. return NULL;
  1070. }
  1071. rsdtSize = header->Length;
  1072. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  1073. //
  1074. // Map down entire RSDT table
  1075. //
  1076. rsdt = (PRSDT) MmMapIoSpace(multiNode->RsdtAddress, rsdtSize, MmNonCached);
  1077. ExFreePool(multiNode);
  1078. if (!rsdt) {
  1079. return NULL;
  1080. }
  1081. //
  1082. // Do a sanity check on the RSDT.
  1083. //
  1084. if ((rsdt->Header.Signature != RSDT_SIGNATURE) &&
  1085. (rsdt->Header.Signature != XSDT_SIGNATURE)) {
  1086. DbgPrint("RSDT table contains invalid signature\n");
  1087. goto GetAcpiTableEnd;
  1088. }
  1089. //
  1090. // Calculate the number of entries in the RSDT.
  1091. //
  1092. rsdtEntries = rsdt->Header.Signature == XSDT_SIGNATURE ?
  1093. NumTableEntriesFromXSDTPointer(rsdt) :
  1094. NumTableEntriesFromRSDTPointer(rsdt);
  1095. //
  1096. // Look down the pointer in each entry to see if it points to
  1097. // the table we are looking for.
  1098. //
  1099. for (entry = 0; entry < rsdtEntries; entry++) {
  1100. if (rsdt->Header.Signature == XSDT_SIGNATURE) {
  1101. physicalAddr = ((PXSDT)rsdt)->Tables[entry];
  1102. } else {
  1103. physicalAddr.HighPart = 0;
  1104. physicalAddr.LowPart = (ULONG)rsdt->Tables[entry];
  1105. }
  1106. //
  1107. // Map down the header, check the signature
  1108. //
  1109. header = (PDESCRIPTION_HEADER) MmMapIoSpace(physicalAddr, sizeof(DESCRIPTION_HEADER), MmNonCached);
  1110. if (!header) {
  1111. goto GetAcpiTableEnd;
  1112. }
  1113. if (header->Signature == Signature) {
  1114. table = ExAllocatePool( PagedPool, header->Length );
  1115. if (table) {
  1116. RtlCopyMemory(table, header, header->Length);
  1117. }
  1118. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  1119. break;
  1120. }
  1121. MmUnmapIoSpace(header, sizeof(DESCRIPTION_HEADER));
  1122. }
  1123. GetAcpiTableEnd:
  1124. MmUnmapIoSpace(rsdt, rsdtSize);
  1125. return table;
  1126. }