1 /* 2 * PROJECT: ReactOS PCI Bus Driver 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: drivers/bus/pci/init.c 5 * PURPOSE: Driver Initialization 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <pci.h> 12 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS ********************************************************************/ 17 18 BOOLEAN PciRunningDatacenter; 19 PDRIVER_OBJECT PciDriverObject; 20 KEVENT PciGlobalLock; 21 KEVENT PciBusLock; 22 KEVENT PciLegacyDescriptionLock; 23 BOOLEAN PciLockDeviceResources; 24 BOOLEAN PciEnableNativeModeATA; 25 ULONG PciSystemWideHackFlags; 26 PPCI_IRQ_ROUTING_TABLE PciIrqRoutingTable; 27 PWATCHDOG_TABLE WdTable; 28 PPCI_HACK_ENTRY PciHackTable; 29 30 /* FUNCTIONS ******************************************************************/ 31 32 NTSTATUS 33 NTAPI 34 PciAcpiFindRsdt(OUT PACPI_BIOS_MULTI_NODE *AcpiMultiNode) 35 { 36 BOOLEAN Result; 37 NTSTATUS Status; 38 HANDLE KeyHandle, SubKey; 39 ULONG NumberOfBytes, i, Length; 40 PKEY_FULL_INFORMATION FullInfo; 41 PKEY_BASIC_INFORMATION KeyInfo; 42 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; 43 PACPI_BIOS_MULTI_NODE NodeData; 44 UNICODE_STRING ValueName; 45 struct 46 { 47 CM_FULL_RESOURCE_DESCRIPTOR Descriptor; 48 ACPI_BIOS_MULTI_NODE Node; 49 } *Package; 50 51 /* So we know what to free at the end of the body */ 52 ValueInfo = NULL; 53 KeyInfo = NULL; 54 KeyHandle = NULL; 55 FullInfo = NULL; 56 Package = NULL; 57 do 58 { 59 /* Open the ACPI BIOS key */ 60 Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\" 61 L"System\\MultiFunctionAdapter", 62 NULL, 63 KEY_QUERY_VALUE, 64 &KeyHandle, 65 &Status); 66 if (!Result) break; 67 68 /* Query how much space should be allocated for the key information */ 69 Status = ZwQueryKey(KeyHandle, 70 KeyFullInformation, 71 NULL, 72 sizeof(ULONG), 73 &NumberOfBytes); 74 if (Status != STATUS_BUFFER_TOO_SMALL) break; 75 76 /* Allocate the space required */ 77 Status = STATUS_INSUFFICIENT_RESOURCES; 78 FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG); 79 if ( !FullInfo ) break; 80 81 /* Now query the key information that's needed */ 82 Status = ZwQueryKey(KeyHandle, 83 KeyFullInformation, 84 FullInfo, 85 NumberOfBytes, 86 &NumberOfBytes); 87 if (!NT_SUCCESS(Status)) break; 88 89 /* Allocate enough space to hold the value information plus the name */ 90 Status = STATUS_INSUFFICIENT_RESOURCES; 91 Length = FullInfo->MaxNameLen + 26; 92 KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG); 93 if ( !KeyInfo ) break; 94 95 /* Allocate the value information and name we expect to find */ 96 ValueInfo = ExAllocatePoolWithTag(PagedPool, 97 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 98 sizeof(L"ACPI BIOS"), 99 PCI_POOL_TAG); 100 if (!ValueInfo) break; 101 102 /* Loop each sub-key */ 103 i = 0; 104 while (TRUE) 105 { 106 /* Query each sub-key */ 107 Status = ZwEnumerateKey(KeyHandle, 108 i++, 109 KeyBasicInformation, 110 KeyInfo, 111 Length, 112 &NumberOfBytes); 113 if (Status == STATUS_NO_MORE_ENTRIES) break; 114 115 /* Null-terminate the keyname, because the kernel does not */ 116 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 117 118 /* Open this subkey */ 119 Result = PciOpenKey(KeyInfo->Name, 120 KeyHandle, 121 KEY_QUERY_VALUE, 122 &SubKey, 123 &Status); 124 if (Result) 125 { 126 /* Query the identifier value for this subkey */ 127 RtlInitUnicodeString(&ValueName, L"Identifier"); 128 Status = ZwQueryValueKey(SubKey, 129 &ValueName, 130 KeyValuePartialInformation, 131 ValueInfo, 132 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 133 sizeof(L"ACPI BIOS"), 134 &NumberOfBytes); 135 if (NT_SUCCESS(Status)) 136 { 137 /* Check if this is the PCI BIOS subkey */ 138 if (!wcsncmp((PWCHAR)ValueInfo->Data, 139 L"ACPI BIOS", 140 ValueInfo->DataLength)) 141 { 142 /* It is, proceed to query the PCI IRQ routing table */ 143 Status = PciGetRegistryValue(L"Configuration Data", 144 KeyInfo->Name, 145 KeyHandle, 146 REG_FULL_RESOURCE_DESCRIPTOR, 147 (PVOID*)&Package, 148 &NumberOfBytes); 149 ZwClose(SubKey); 150 break; 151 } 152 } 153 154 /* Close the subkey and try the next one */ 155 ZwClose(SubKey); 156 } 157 } 158 159 /* Check if we got here because the routing table was found */ 160 if (!NT_SUCCESS(Status)) 161 { 162 /* This should only fail if we're out of entries */ 163 ASSERT(Status == STATUS_NO_MORE_ENTRIES); 164 break; 165 } 166 167 /* Check if a descriptor was found */ 168 if (!Package) break; 169 170 /* The configuration data is a resource list, and the BIOS node follows */ 171 NodeData = &Package->Node; 172 173 /* How many E820 memory entries are there? */ 174 Length = sizeof(ACPI_BIOS_MULTI_NODE) + 175 (NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY); 176 177 /* Allocate the buffer needed to copy the information */ 178 Status = STATUS_INSUFFICIENT_RESOURCES; 179 *AcpiMultiNode = ExAllocatePoolWithTag(NonPagedPool, Length, PCI_POOL_TAG); 180 if (!*AcpiMultiNode) break; 181 182 /* Copy the data */ 183 RtlCopyMemory(*AcpiMultiNode, NodeData, Length); 184 Status = STATUS_SUCCESS; 185 } while (FALSE); 186 187 /* Close any opened keys, free temporary allocations, and return status */ 188 if (Package) ExFreePoolWithTag(Package, 0); 189 if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0); 190 if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0); 191 if (FullInfo) ExFreePoolWithTag(FullInfo, 0); 192 if (KeyHandle) ZwClose(KeyHandle); 193 return Status; 194 } 195 196 PVOID 197 NTAPI 198 PciGetAcpiTable(IN ULONG TableCode) 199 { 200 PDESCRIPTION_HEADER Header; 201 PACPI_BIOS_MULTI_NODE AcpiMultiNode; 202 PRSDT Rsdt; 203 PXSDT Xsdt; 204 ULONG EntryCount, TableLength, Offset, CurrentEntry; 205 PVOID TableBuffer, MappedAddress; 206 PHYSICAL_ADDRESS PhysicalAddress; 207 NTSTATUS Status; 208 209 /* Try to find the RSDT or XSDT */ 210 Status = PciAcpiFindRsdt(&AcpiMultiNode); 211 if (!NT_SUCCESS(Status)) 212 { 213 /* No ACPI on the machine */ 214 DPRINT1("AcpiFindRsdt() Failed!\n"); 215 return NULL; 216 } 217 218 /* Map the RSDT with the minimum size allowed */ 219 MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress, 220 sizeof(DESCRIPTION_HEADER), 221 MmNonCached); 222 Header = MappedAddress; 223 if (!Header) return NULL; 224 225 /* Check how big the table really is and get rid of the temporary header */ 226 TableLength = Header->Length; 227 MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); 228 Header = NULL; 229 230 /* Map its true size */ 231 MappedAddress = MmMapIoSpace(AcpiMultiNode->RsdtAddress, 232 TableLength, 233 MmNonCached); 234 Rsdt = MappedAddress; 235 Xsdt = MappedAddress; 236 ExFreePoolWithTag(AcpiMultiNode, 0); 237 if (!Rsdt) return NULL; 238 239 /* Validate the table's signature */ 240 if ((Rsdt->Header.Signature != RSDT_SIGNATURE) && 241 (Rsdt->Header.Signature != XSDT_SIGNATURE)) 242 { 243 /* Very bad: crash */ 244 HalDisplayString("RSDT table contains invalid signature\r\n"); 245 MmUnmapIoSpace(Rsdt, TableLength); 246 return NULL; 247 } 248 249 /* Smallest RSDT/XSDT is one without table entries */ 250 Offset = FIELD_OFFSET(RSDT, Tables); 251 if (Rsdt->Header.Signature == XSDT_SIGNATURE) 252 { 253 /* Figure out total size of table and the offset */ 254 TableLength = Xsdt->Header.Length; 255 if (TableLength < Offset) Offset = Xsdt->Header.Length; 256 257 /* The entries are each 64-bits, so count them */ 258 EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS); 259 } 260 else 261 { 262 /* Figure out total size of table and the offset */ 263 TableLength = Rsdt->Header.Length; 264 if (TableLength < Offset) Offset = Rsdt->Header.Length; 265 266 /* The entries are each 32-bits, so count them */ 267 EntryCount = (TableLength - Offset) / sizeof(ULONG); 268 } 269 270 /* Start at the beginning of the array and loop it */ 271 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++) 272 { 273 /* Are we using the XSDT? */ 274 if (Rsdt->Header.Signature != XSDT_SIGNATURE) 275 { 276 /* Read the 32-bit physical address */ 277 PhysicalAddress.QuadPart = Rsdt->Tables[CurrentEntry]; 278 } 279 else 280 { 281 /* Read the 64-bit physical address */ 282 PhysicalAddress = Xsdt->Tables[CurrentEntry]; 283 } 284 285 /* Map this table */ 286 Header = MmMapIoSpace(PhysicalAddress, 287 sizeof(DESCRIPTION_HEADER), 288 MmNonCached); 289 if (!Header) break; 290 291 /* Check if this is the table that's being asked for */ 292 if (Header->Signature == TableCode) 293 { 294 /* Allocate a buffer for it */ 295 TableBuffer = ExAllocatePoolWithTag(PagedPool, 296 Header->Length, 297 PCI_POOL_TAG); 298 if (!TableBuffer) break; 299 300 /* Copy the table into the buffer */ 301 RtlCopyMemory(TableBuffer, Header, Header->Length); 302 } 303 304 /* Done with this table, keep going */ 305 MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); 306 } 307 308 if (Header) MmUnmapIoSpace(Header, sizeof(DESCRIPTION_HEADER)); 309 return NULL; 310 } 311 312 NTSTATUS 313 NTAPI 314 PciGetIrqRoutingTableFromRegistry(OUT PPCI_IRQ_ROUTING_TABLE *PciRoutingTable) 315 { 316 BOOLEAN Result; 317 NTSTATUS Status; 318 HANDLE KeyHandle, SubKey; 319 ULONG NumberOfBytes, i, Length; 320 PKEY_FULL_INFORMATION FullInfo; 321 PKEY_BASIC_INFORMATION KeyInfo; 322 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo; 323 UNICODE_STRING ValueName; 324 struct 325 { 326 CM_FULL_RESOURCE_DESCRIPTOR Descriptor; 327 PCI_IRQ_ROUTING_TABLE Table; 328 } *Package; 329 330 /* So we know what to free at the end of the body */ 331 Package = NULL; 332 ValueInfo = NULL; 333 KeyInfo = NULL; 334 KeyHandle = NULL; 335 FullInfo = NULL; 336 do 337 { 338 /* Open the BIOS key */ 339 Result = PciOpenKey(L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\" 340 L"System\\MultiFunctionAdapter", 341 NULL, 342 KEY_QUERY_VALUE, 343 &KeyHandle, 344 &Status); 345 if (!Result) break; 346 347 /* Query how much space should be allocated for the key information */ 348 Status = ZwQueryKey(KeyHandle, 349 KeyFullInformation, 350 NULL, 351 sizeof(ULONG), 352 &NumberOfBytes); 353 if (Status != STATUS_BUFFER_TOO_SMALL) break; 354 355 /* Allocate the space required */ 356 Status = STATUS_INSUFFICIENT_RESOURCES; 357 FullInfo = ExAllocatePoolWithTag(PagedPool, NumberOfBytes, PCI_POOL_TAG); 358 if ( !FullInfo ) break; 359 360 /* Now query the key information that's needed */ 361 Status = ZwQueryKey(KeyHandle, 362 KeyFullInformation, 363 FullInfo, 364 NumberOfBytes, 365 &NumberOfBytes); 366 if (!NT_SUCCESS(Status)) break; 367 368 /* Allocate enough space to hold the value information plus the name */ 369 Status = STATUS_INSUFFICIENT_RESOURCES; 370 Length = FullInfo->MaxNameLen + 26; 371 KeyInfo = ExAllocatePoolWithTag(PagedPool, Length, PCI_POOL_TAG); 372 if (!KeyInfo) break; 373 374 /* Allocate the value information and name we expect to find */ 375 ValueInfo = ExAllocatePoolWithTag(PagedPool, 376 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 377 sizeof(L"PCI BIOS"), 378 PCI_POOL_TAG); 379 if (!ValueInfo) break; 380 381 /* Loop each sub-key */ 382 i = 0; 383 while (TRUE) 384 { 385 /* Query each sub-key */ 386 Status = ZwEnumerateKey(KeyHandle, 387 i++, 388 KeyBasicInformation, 389 KeyInfo, 390 Length, 391 &NumberOfBytes); 392 if (Status == STATUS_NO_MORE_ENTRIES) break; 393 394 /* Null-terminate the keyname, because the kernel does not */ 395 KeyInfo->Name[KeyInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL; 396 397 /* Open this subkey */ 398 Result = PciOpenKey(KeyInfo->Name, 399 KeyHandle, 400 KEY_QUERY_VALUE, 401 &SubKey, 402 &Status); 403 if (Result) 404 { 405 /* Query the identifier value for this subkey */ 406 RtlInitUnicodeString(&ValueName, L"Identifier"); 407 Status = ZwQueryValueKey(SubKey, 408 &ValueName, 409 KeyValuePartialInformation, 410 ValueInfo, 411 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 412 sizeof(L"PCI BIOS"), 413 &NumberOfBytes); 414 if (NT_SUCCESS(Status)) 415 { 416 /* Check if this is the PCI BIOS subkey */ 417 if (!wcsncmp((PWCHAR)ValueInfo->Data, 418 L"PCI BIOS", 419 ValueInfo->DataLength)) 420 { 421 /* It is, proceed to query the PCI IRQ routing table */ 422 Status = PciGetRegistryValue(L"Configuration Data", 423 L"RealModeIrqRoutingTable" 424 L"\\0", 425 SubKey, 426 REG_FULL_RESOURCE_DESCRIPTOR, 427 (PVOID*)&Package, 428 &NumberOfBytes); 429 ZwClose(SubKey); 430 break; 431 } 432 } 433 434 /* Close the subkey and try the next one */ 435 ZwClose(SubKey); 436 } 437 } 438 439 /* Check if we got here because the routing table was found */ 440 if (!NT_SUCCESS(Status)) break; 441 442 /* Check if a descriptor was found */ 443 if (!Package) break; 444 445 /* Make sure the buffer is large enough to hold the table */ 446 if ((NumberOfBytes < sizeof(*Package)) || 447 (Package->Table.TableSize > 448 (NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)))) 449 { 450 /* Invalid package size */ 451 Status = STATUS_UNSUCCESSFUL; 452 break; 453 } 454 455 /* Allocate space for the table */ 456 Status = STATUS_INSUFFICIENT_RESOURCES; 457 *PciRoutingTable = ExAllocatePoolWithTag(PagedPool, 458 NumberOfBytes, 459 PCI_POOL_TAG); 460 if (!*PciRoutingTable) break; 461 462 /* Copy the registry data */ 463 RtlCopyMemory(*PciRoutingTable, 464 &Package->Table, 465 NumberOfBytes - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)); 466 Status = STATUS_SUCCESS; 467 } while (FALSE); 468 469 /* Close any opened keys, free temporary allocations, and return status */ 470 if (Package) ExFreePoolWithTag(Package, 0); 471 if (ValueInfo) ExFreePoolWithTag(ValueInfo, 0); 472 if (KeyInfo) ExFreePoolWithTag(KeyInfo, 0); 473 if (FullInfo) ExFreePoolWithTag(FullInfo, 0); 474 if (KeyHandle) ZwClose(KeyHandle); 475 return Status; 476 } 477 478 NTSTATUS 479 NTAPI 480 PciBuildHackTable(IN HANDLE KeyHandle) 481 { 482 PKEY_FULL_INFORMATION FullInfo; 483 ULONG i, HackCount; 484 PKEY_VALUE_FULL_INFORMATION ValueInfo; 485 PPCI_HACK_ENTRY Entry; 486 NTSTATUS Status; 487 ULONG NameLength, ResultLength; 488 ULONGLONG HackFlags; 489 490 /* So we know what to free at the end of the body */ 491 FullInfo = NULL; 492 ValueInfo = NULL; 493 do 494 { 495 /* Query the size required for full key information */ 496 Status = ZwQueryKey(KeyHandle, 497 KeyFullInformation, 498 NULL, 499 0, 500 &ResultLength); 501 if (Status != STATUS_BUFFER_TOO_SMALL) break; 502 503 /* Allocate the space required to hold the full key information */ 504 Status = STATUS_INSUFFICIENT_RESOURCES; 505 ASSERT(ResultLength > 0); 506 FullInfo = ExAllocatePoolWithTag(PagedPool, ResultLength, PCI_POOL_TAG); 507 if (!FullInfo) break; 508 509 /* Go ahead and query the key information */ 510 Status = ZwQueryKey(KeyHandle, 511 KeyFullInformation, 512 FullInfo, 513 ResultLength, 514 &ResultLength); 515 if (!NT_SUCCESS(Status)) break; 516 517 /* The only piece of information that's needed is the count of values */ 518 HackCount = FullInfo->Values; 519 520 /* Free the structure now */ 521 ExFreePoolWithTag(FullInfo, 0); 522 FullInfo = NULL; 523 524 /* Allocate the hack table, now that the number of entries is known */ 525 Status = STATUS_INSUFFICIENT_RESOURCES; 526 ResultLength = sizeof(PCI_HACK_ENTRY) * HackCount; 527 PciHackTable = ExAllocatePoolWithTag(NonPagedPool, 528 ResultLength + 529 sizeof(PCI_HACK_ENTRY), 530 PCI_POOL_TAG); 531 if (!PciHackTable) break; 532 533 /* Allocate the space needed to hold the full value information */ 534 ValueInfo = ExAllocatePoolWithTag(NonPagedPool, 535 sizeof(KEY_VALUE_FULL_INFORMATION) + 536 PCI_HACK_ENTRY_FULL_SIZE, 537 PCI_POOL_TAG); 538 if (!PciHackTable) break; 539 540 /* Loop each value in the registry */ 541 Entry = &PciHackTable[0]; 542 for (i = 0; i < HackCount; i++) 543 { 544 /* Get the entry for this value */ 545 Entry = &PciHackTable[i]; 546 547 /* Query the value in the key */ 548 Status = ZwEnumerateValueKey(KeyHandle, 549 i, 550 KeyValueFullInformation, 551 ValueInfo, 552 sizeof(KEY_VALUE_FULL_INFORMATION) + 553 PCI_HACK_ENTRY_FULL_SIZE, 554 &ResultLength); 555 if (!NT_SUCCESS(Status)) 556 { 557 /* Check why the call failed */ 558 if ((Status != STATUS_BUFFER_OVERFLOW) && 559 (Status != STATUS_BUFFER_TOO_SMALL)) 560 { 561 /* The call failed due to an unknown error, bail out */ 562 break; 563 } 564 565 /* The data seems to mismatch, try the next key in the list */ 566 continue; 567 } 568 569 /* Check if the value data matches what's expected */ 570 if ((ValueInfo->Type != REG_BINARY) || 571 (ValueInfo->DataLength != sizeof(ULONGLONG))) 572 { 573 /* It doesn't, try the next key in the list */ 574 continue; 575 } 576 577 /* Read the actual hack flags */ 578 HackFlags = *(PULONGLONG)((ULONG_PTR)ValueInfo + 579 ValueInfo->DataOffset); 580 581 /* Check what kind of errata entry this is, based on the name */ 582 NameLength = ValueInfo->NameLength; 583 if ((NameLength != PCI_HACK_ENTRY_SIZE) && 584 (NameLength != PCI_HACK_ENTRY_REV_SIZE) && 585 (NameLength != PCI_HACK_ENTRY_SUBSYS_SIZE) && 586 (NameLength != PCI_HACK_ENTRY_FULL_SIZE)) 587 { 588 /* It's an invalid entry, skip it */ 589 DPRINT1("Skipping hack entry with invalid length name\n"); 590 continue; 591 } 592 593 /* Initialize the entry */ 594 RtlZeroMemory(Entry, sizeof(PCI_HACK_ENTRY)); 595 596 /* Get the vendor and device data */ 597 if (!(PciStringToUSHORT(ValueInfo->Name, &Entry->VendorID)) || 598 !(PciStringToUSHORT(&ValueInfo->Name[4], &Entry->DeviceID))) 599 { 600 /* This failed, try the next entry */ 601 continue; 602 } 603 604 /* Check if the entry contains subsystem information */ 605 if ((NameLength == PCI_HACK_ENTRY_SUBSYS_SIZE) || 606 (NameLength == PCI_HACK_ENTRY_FULL_SIZE)) 607 { 608 /* Get the data */ 609 if (!(PciStringToUSHORT(&ValueInfo->Name[8], 610 &Entry->SubVendorID)) || 611 !(PciStringToUSHORT(&ValueInfo->Name[12], 612 &Entry->SubSystemID))) 613 { 614 /* This failed, try the next entry */ 615 continue; 616 } 617 618 /* Save the fact this entry has finer controls */ 619 Entry->Flags |= PCI_HACK_HAS_SUBSYSTEM_INFO; 620 } 621 622 /* Check if the entry contains revision information */ 623 if ((NameLength == PCI_HACK_ENTRY_REV_SIZE) || 624 (NameLength == PCI_HACK_ENTRY_FULL_SIZE)) 625 { 626 /* Get the data */ 627 if (!PciStringToUSHORT(&ValueInfo->Name[16], 628 &Entry->RevisionID)) 629 { 630 /* This failed, try the next entry */ 631 continue; 632 } 633 634 /* Save the fact this entry has finer controls */ 635 Entry->Flags |= PCI_HACK_HAS_REVISION_INFO; 636 } 637 638 /* Only the last entry should have this set */ 639 ASSERT(Entry->VendorID != PCI_INVALID_VENDORID); 640 641 /* Save the actual hack flags */ 642 Entry->HackFlags = HackFlags; 643 644 /* Print out for the debugger's sake */ 645 #ifdef HACK_DEBUG 646 DPRINT1("Adding Hack entry for Vendor:0x%04x Device:0x%04x ", 647 Entry->VendorID, Entry->DeviceID); 648 if (Entry->Flags & PCI_HACK_HAS_SUBSYSTEM_INFO) 649 DbgPrint("SybSys:0x%04x SubVendor:0x%04x ", 650 Entry->SubSystemID, Entry->SubVendorID); 651 if (Entry->Flags & PCI_HACK_HAS_REVISION_INFO) 652 DbgPrint("Revision:0x%02x", Entry->RevisionID); 653 DbgPrint(" = 0x%I64x\n", Entry->HackFlags); 654 #endif 655 } 656 657 /* Bail out in case of failure */ 658 if (!NT_SUCCESS(Status)) break; 659 660 /* Terminate the table with an invalid entry */ 661 ASSERT(Entry < (PciHackTable + HackCount + 1)); 662 Entry->VendorID = PCI_INVALID_VENDORID; 663 664 /* Success path, free the temporary registry data */ 665 ExFreePoolWithTag(ValueInfo, 0); 666 return STATUS_SUCCESS; 667 } while (TRUE); 668 669 /* Failure path, free temporary allocations and return failure code */ 670 ASSERT(!NT_SUCCESS(Status)); 671 if (FullInfo) ExFreePool(FullInfo); 672 if (ValueInfo) ExFreePool(ValueInfo); 673 if (PciHackTable) ExFreePool(PciHackTable); 674 return Status; 675 } 676 677 NTSTATUS 678 NTAPI 679 PciGetDebugPorts(IN HANDLE DebugKey) 680 { 681 UNREFERENCED_PARAMETER(DebugKey); 682 /* This function is not yet implemented */ 683 UNIMPLEMENTED_DBGBREAK(); 684 return STATUS_SUCCESS; 685 } 686 687 DRIVER_UNLOAD PciDriverUnload; 688 689 VOID 690 NTAPI 691 PciDriverUnload(IN PDRIVER_OBJECT DriverObject) 692 { 693 UNREFERENCED_PARAMETER(DriverObject); 694 /* This function is not yet implemented */ 695 UNIMPLEMENTED_DBGBREAK("PCI: Unload\n"); 696 } 697 698 NTSTATUS 699 NTAPI 700 DriverEntry(IN PDRIVER_OBJECT DriverObject, 701 IN PUNICODE_STRING RegistryPath) 702 { 703 HANDLE KeyHandle, ParametersKey, DebugKey, ControlSetKey; 704 BOOLEAN Result; 705 OBJECT_ATTRIBUTES ObjectAttributes; 706 ULONG ResultLength; 707 PULONG Value; 708 PWCHAR StartOptions; 709 UNICODE_STRING OptionString, PciLockString; 710 NTSTATUS Status; 711 DPRINT1("PCI: DriverEntry!\n"); 712 713 /* Setup initial loop variables */ 714 KeyHandle = NULL; 715 ParametersKey = NULL; 716 DebugKey = NULL; 717 ControlSetKey = NULL; 718 do 719 { 720 /* Remember our object so we can get it to it later */ 721 PciDriverObject = DriverObject; 722 723 /* Setup the IRP dispatcher */ 724 DriverObject->MajorFunction[IRP_MJ_POWER] = PciDispatchIrp; 725 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PciDispatchIrp; 726 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PciDispatchIrp; 727 DriverObject->MajorFunction[IRP_MJ_PNP] = PciDispatchIrp; 728 DriverObject->DriverUnload = PciDriverUnload; 729 730 /* This is how we'll detect a new PCI bus */ 731 DriverObject->DriverExtension->AddDevice = PciAddDevice; 732 733 /* Open the PCI key */ 734 InitializeObjectAttributes(&ObjectAttributes, 735 RegistryPath, 736 OBJ_CASE_INSENSITIVE, 737 NULL, 738 NULL); 739 Status = ZwOpenKey(&KeyHandle, KEY_QUERY_VALUE, &ObjectAttributes); 740 if (!NT_SUCCESS(Status)) break; 741 742 /* Open the Parameters subkey */ 743 Result = PciOpenKey(L"Parameters", 744 KeyHandle, 745 KEY_QUERY_VALUE, 746 &ParametersKey, 747 &Status); 748 //if (!Result) break; 749 750 /* Build the list of all known PCI erratas */ 751 Status = PciBuildHackTable(ParametersKey); 752 //if (!NT_SUCCESS(Status)) break; 753 754 /* Open the debug key, if it exists */ 755 Result = PciOpenKey(L"Debug", 756 KeyHandle, 757 KEY_QUERY_VALUE, 758 &DebugKey, 759 &Status); 760 if (Result) 761 { 762 /* There are PCI debug devices, go discover them */ 763 Status = PciGetDebugPorts(DebugKey); 764 if (!NT_SUCCESS(Status)) break; 765 } 766 767 /* Initialize the synchronization locks */ 768 KeInitializeEvent(&PciGlobalLock, SynchronizationEvent, TRUE); 769 KeInitializeEvent(&PciBusLock, SynchronizationEvent, TRUE); 770 KeInitializeEvent(&PciLegacyDescriptionLock, SynchronizationEvent, TRUE); 771 772 /* Open the control set key */ 773 Result = PciOpenKey(L"\\Registry\\Machine\\System\\CurrentControlSet", 774 NULL, 775 KEY_QUERY_VALUE, 776 &ControlSetKey, 777 &Status); 778 if (!Result) break; 779 780 /* Read the command line */ 781 Status = PciGetRegistryValue(L"SystemStartOptions", 782 L"Control", 783 ControlSetKey, 784 REG_SZ, 785 (PVOID*)&StartOptions, 786 &ResultLength); 787 if (NT_SUCCESS(Status)) 788 { 789 /* Initialize the command-line as a string */ 790 OptionString.Buffer = StartOptions; 791 OptionString.MaximumLength = OptionString.Length = ResultLength; 792 793 /* Check if the command-line has the PCILOCK argument */ 794 RtlInitUnicodeString(&PciLockString, L"PCILOCK"); 795 if (PciUnicodeStringStrStr(&OptionString, &PciLockString, TRUE)) 796 { 797 /* The PCI Bus driver will keep the BIOS-assigned resources */ 798 PciLockDeviceResources = TRUE; 799 } 800 801 /* This data isn't needed anymore */ 802 ExFreePoolWithTag(StartOptions, 0); 803 } 804 805 /* The PCILOCK feature can also be enabled per-system in the registry */ 806 Status = PciGetRegistryValue(L"PCILock", 807 L"Control\\BiosInfo\\PCI", 808 ControlSetKey, 809 REG_DWORD, 810 (PVOID*)&Value, 811 &ResultLength); 812 if (NT_SUCCESS(Status)) 813 { 814 /* Read the value it's been set to. This overrides /PCILOCK */ 815 if (ResultLength == sizeof(ULONG)) PciLockDeviceResources = *Value; 816 ExFreePoolWithTag(Value, 0); 817 } 818 819 /* The system can have global PCI erratas in the registry */ 820 Status = PciGetRegistryValue(L"HackFlags", 821 L"Control\\PnP\\PCI", 822 ControlSetKey, 823 REG_DWORD, 824 (PVOID*)&Value, 825 &ResultLength); 826 if (NT_SUCCESS(Status)) 827 { 828 /* Read them in */ 829 if (ResultLength == sizeof(ULONG)) PciSystemWideHackFlags = *Value; 830 ExFreePoolWithTag(Value, 0); 831 } 832 833 /* Check if the system should allow native ATA support */ 834 Status = PciGetRegistryValue(L"EnableNativeModeATA", 835 L"Control\\PnP\\PCI", 836 ControlSetKey, 837 REG_DWORD, 838 (PVOID*)&Value, 839 &ResultLength); 840 if (NT_SUCCESS(Status)) 841 { 842 /* This key is typically set by drivers, but users can force it */ 843 if (ResultLength == sizeof(ULONG)) PciEnableNativeModeATA = *Value; 844 ExFreePoolWithTag(Value, 0); 845 } 846 847 /* Build the range lists for all the excluded resource areas */ 848 Status = PciBuildDefaultExclusionLists(); 849 if (!NT_SUCCESS(Status)) break; 850 851 /* Read the PCI IRQ Routing Table that the loader put in the registry */ 852 PciGetIrqRoutingTableFromRegistry(&PciIrqRoutingTable); 853 854 /* Take over the HAL's default PCI Bus Handler routines */ 855 PciHookHal(); 856 857 /* Initialize verification of PCI BIOS and devices, if requested */ 858 PciVerifierInit(DriverObject); 859 860 /* Check if this is a Datacenter SKU, which impacts IRQ alignment */ 861 PciRunningDatacenter = PciIsDatacenter(); 862 if (PciRunningDatacenter) DPRINT1("PCI running on datacenter build\n"); 863 864 /* Check if the system has an ACPI Hardware Watchdog Timer */ 865 //WdTable = PciGetAcpiTable(WDRT_SIGNATURE); 866 Status = STATUS_SUCCESS; 867 } while (FALSE); 868 869 /* Close all opened keys, return driver status to PnP Manager */ 870 if (KeyHandle) ZwClose(KeyHandle); 871 if (ControlSetKey) ZwClose(ControlSetKey); 872 if (ParametersKey) ZwClose(ParametersKey); 873 if (DebugKey) ZwClose(DebugKey); 874 return Status; 875 } 876 877 /* EOF */ 878