1 /* 2 * PROJECT: ReactOS HAL 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: hal/halx86/legacy/bus/pcibus.c 5 * PURPOSE: PCI Bus Support (Configuration Space, Resource Allocation) 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <hal.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_) 16 #pragma alloc_text(INIT, HalpInitializePciStubs) 17 #pragma alloc_text(INIT, HalpQueryPciRegistryInfo) 18 #pragma alloc_text(INIT, HalpRegisterPciDebuggingDeviceInfo) 19 #pragma alloc_text(INIT, HalpReleasePciDeviceForDebugging) 20 #pragma alloc_text(INIT, HalpSetupPciDeviceForDebugging) 21 #endif 22 23 /* GLOBALS *******************************************************************/ 24 25 extern BOOLEAN HalpPciLockSettings; 26 ULONG HalpBusType; 27 28 PCI_TYPE1_CFG_CYCLE_BITS HalpPciDebuggingDevice[2] = {{{{0}}}}; 29 30 BOOLEAN HalpPCIConfigInitialized; 31 ULONG HalpMinPciBus, HalpMaxPciBus; 32 KSPIN_LOCK HalpPCIConfigLock; 33 PCI_CONFIG_HANDLER PCIConfigHandler; 34 35 /* PCI Operation Matrix */ 36 UCHAR PCIDeref[4][4] = 37 { 38 {0, 1, 2, 2}, // ULONG-aligned offset 39 {1, 1, 1, 1}, // UCHAR-aligned offset 40 {2, 1, 2, 2}, // USHORT-aligned offset 41 {1, 1, 1, 1} // UCHAR-aligned offset 42 }; 43 44 /* Type 1 PCI Bus */ 45 PCI_CONFIG_HANDLER PCIConfigHandlerType1 = 46 { 47 /* Synchronization */ 48 (FncSync)HalpPCISynchronizeType1, 49 (FncReleaseSync)HalpPCIReleaseSynchronzationType1, 50 51 /* Read */ 52 { 53 (FncConfigIO)HalpPCIReadUlongType1, 54 (FncConfigIO)HalpPCIReadUcharType1, 55 (FncConfigIO)HalpPCIReadUshortType1 56 }, 57 58 /* Write */ 59 { 60 (FncConfigIO)HalpPCIWriteUlongType1, 61 (FncConfigIO)HalpPCIWriteUcharType1, 62 (FncConfigIO)HalpPCIWriteUshortType1 63 } 64 }; 65 66 /* Type 2 PCI Bus */ 67 PCI_CONFIG_HANDLER PCIConfigHandlerType2 = 68 { 69 /* Synchronization */ 70 (FncSync)HalpPCISynchronizeType2, 71 (FncReleaseSync)HalpPCIReleaseSynchronizationType2, 72 73 /* Read */ 74 { 75 (FncConfigIO)HalpPCIReadUlongType2, 76 (FncConfigIO)HalpPCIReadUcharType2, 77 (FncConfigIO)HalpPCIReadUshortType2 78 }, 79 80 /* Write */ 81 { 82 (FncConfigIO)HalpPCIWriteUlongType2, 83 (FncConfigIO)HalpPCIWriteUcharType2, 84 (FncConfigIO)HalpPCIWriteUshortType2 85 } 86 }; 87 88 PCIPBUSDATA HalpFakePciBusData = 89 { 90 { 91 PCI_DATA_TAG, 92 PCI_DATA_VERSION, 93 HalpReadPCIConfig, 94 HalpWritePCIConfig, 95 NULL, 96 NULL, 97 {{{0, 0, 0}}}, 98 {0, 0, 0, 0} 99 }, 100 {{0, 0}}, 101 32, 102 }; 103 104 BUS_HANDLER HalpFakePciBusHandler = 105 { 106 1, 107 PCIBus, 108 PCIConfiguration, 109 0, 110 NULL, 111 NULL, 112 &HalpFakePciBusData, 113 0, 114 NULL, 115 {0, 0, 0, 0}, 116 (PGETSETBUSDATA)HalpGetPCIData, 117 (PGETSETBUSDATA)HalpSetPCIData, 118 NULL, 119 HalpAssignPCISlotResources, 120 NULL, 121 NULL 122 }; 123 124 /* TYPE 1 FUNCTIONS **********************************************************/ 125 126 VOID 127 NTAPI 128 HalpPCISynchronizeType1(IN PBUS_HANDLER BusHandler, 129 IN PCI_SLOT_NUMBER Slot, 130 IN PKIRQL Irql, 131 IN PPCI_TYPE1_CFG_BITS PciCfg1) 132 { 133 /* Setup the PCI Configuration Register */ 134 PciCfg1->u.AsULONG = 0; 135 PciCfg1->u.bits.BusNumber = BusHandler->BusNumber; 136 PciCfg1->u.bits.DeviceNumber = Slot.u.bits.DeviceNumber; 137 PciCfg1->u.bits.FunctionNumber = Slot.u.bits.FunctionNumber; 138 PciCfg1->u.bits.Enable = TRUE; 139 140 /* Acquire the lock */ 141 KeRaiseIrql(HIGH_LEVEL, Irql); 142 KiAcquireSpinLock(&HalpPCIConfigLock); 143 } 144 145 VOID 146 NTAPI 147 HalpPCIReleaseSynchronzationType1(IN PBUS_HANDLER BusHandler, 148 IN KIRQL Irql) 149 { 150 PCI_TYPE1_CFG_BITS PciCfg1; 151 152 /* Clear the PCI Configuration Register */ 153 PciCfg1.u.AsULONG = 0; 154 WRITE_PORT_ULONG(((PPCIPBUSDATA)BusHandler->BusData)->Config.Type1.Address, 155 PciCfg1.u.AsULONG); 156 157 /* Release the lock */ 158 KiReleaseSpinLock(&HalpPCIConfigLock); 159 KeLowerIrql(Irql); 160 } 161 162 TYPE1_READ(HalpPCIReadUcharType1, UCHAR) 163 TYPE1_READ(HalpPCIReadUshortType1, USHORT) 164 TYPE1_READ(HalpPCIReadUlongType1, ULONG) 165 TYPE1_WRITE(HalpPCIWriteUcharType1, UCHAR) 166 TYPE1_WRITE(HalpPCIWriteUshortType1, USHORT) 167 TYPE1_WRITE(HalpPCIWriteUlongType1, ULONG) 168 169 /* TYPE 2 FUNCTIONS **********************************************************/ 170 171 VOID 172 NTAPI 173 HalpPCISynchronizeType2(IN PBUS_HANDLER BusHandler, 174 IN PCI_SLOT_NUMBER Slot, 175 IN PKIRQL Irql, 176 IN PPCI_TYPE2_ADDRESS_BITS PciCfg) 177 { 178 PCI_TYPE2_CSE_BITS PciCfg2Cse; 179 PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; 180 181 /* Setup the configuration register */ 182 PciCfg->u.AsUSHORT = 0; 183 PciCfg->u.bits.Agent = (USHORT)Slot.u.bits.DeviceNumber; 184 PciCfg->u.bits.AddressBase = (USHORT)BusData->Config.Type2.Base; 185 186 /* Acquire the lock */ 187 KeRaiseIrql(HIGH_LEVEL, Irql); 188 KiAcquireSpinLock(&HalpPCIConfigLock); 189 190 /* Setup the CSE Register */ 191 PciCfg2Cse.u.AsUCHAR = 0; 192 PciCfg2Cse.u.bits.Enable = TRUE; 193 PciCfg2Cse.u.bits.FunctionNumber = (UCHAR)Slot.u.bits.FunctionNumber; 194 PciCfg2Cse.u.bits.Key = -1; 195 196 /* Write the bus number and CSE */ 197 WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 198 (UCHAR)BusHandler->BusNumber); 199 WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); 200 } 201 202 VOID 203 NTAPI 204 HalpPCIReleaseSynchronizationType2(IN PBUS_HANDLER BusHandler, 205 IN KIRQL Irql) 206 { 207 PCI_TYPE2_CSE_BITS PciCfg2Cse; 208 PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; 209 210 /* Clear CSE and bus number */ 211 PciCfg2Cse.u.AsUCHAR = 0; 212 WRITE_PORT_UCHAR(BusData->Config.Type2.CSE, PciCfg2Cse.u.AsUCHAR); 213 WRITE_PORT_UCHAR(BusData->Config.Type2.Forward, 0); 214 215 /* Release the lock */ 216 KiReleaseSpinLock(&HalpPCIConfigLock); 217 KeLowerIrql(Irql); 218 } 219 220 TYPE2_READ(HalpPCIReadUcharType2, UCHAR) 221 TYPE2_READ(HalpPCIReadUshortType2, USHORT) 222 TYPE2_READ(HalpPCIReadUlongType2, ULONG) 223 TYPE2_WRITE(HalpPCIWriteUcharType2, UCHAR) 224 TYPE2_WRITE(HalpPCIWriteUshortType2, USHORT) 225 TYPE2_WRITE(HalpPCIWriteUlongType2, ULONG) 226 227 /* PCI CONFIGURATION SPACE ***************************************************/ 228 229 VOID 230 NTAPI 231 HalpPCIConfig(IN PBUS_HANDLER BusHandler, 232 IN PCI_SLOT_NUMBER Slot, 233 IN PUCHAR Buffer, 234 IN ULONG Offset, 235 IN ULONG Length, 236 IN FncConfigIO *ConfigIO) 237 { 238 KIRQL OldIrql; 239 ULONG i; 240 UCHAR State[20]; 241 242 /* Synchronize the operation */ 243 PCIConfigHandler.Synchronize(BusHandler, Slot, &OldIrql, State); 244 245 /* Loop every increment */ 246 while (Length) 247 { 248 /* Find out the type of read/write we need to do */ 249 i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)]; 250 251 /* Do the read/write and return the number of bytes */ 252 i = ConfigIO[i]((PPCIPBUSDATA)BusHandler->BusData, 253 State, 254 Buffer, 255 Offset); 256 257 /* Increment the buffer position and offset, and decrease the length */ 258 Offset += i; 259 Buffer += i; 260 Length -= i; 261 } 262 263 /* Release the lock and PCI bus */ 264 PCIConfigHandler.ReleaseSynchronzation(BusHandler, OldIrql); 265 } 266 267 VOID 268 NTAPI 269 HalpReadPCIConfig(IN PBUS_HANDLER BusHandler, 270 IN PCI_SLOT_NUMBER Slot, 271 IN PVOID Buffer, 272 IN ULONG Offset, 273 IN ULONG Length) 274 { 275 /* Validate the PCI Slot */ 276 if (!HalpValidPCISlot(BusHandler, Slot)) 277 { 278 /* Fill the buffer with invalid data */ 279 RtlFillMemory(Buffer, Length, -1); 280 } 281 else 282 { 283 /* Send the request */ 284 HalpPCIConfig(BusHandler, 285 Slot, 286 Buffer, 287 Offset, 288 Length, 289 PCIConfigHandler.ConfigRead); 290 } 291 } 292 293 VOID 294 NTAPI 295 HalpWritePCIConfig(IN PBUS_HANDLER BusHandler, 296 IN PCI_SLOT_NUMBER Slot, 297 IN PVOID Buffer, 298 IN ULONG Offset, 299 IN ULONG Length) 300 { 301 /* Validate the PCI Slot */ 302 if (HalpValidPCISlot(BusHandler, Slot)) 303 { 304 /* Send the request */ 305 HalpPCIConfig(BusHandler, 306 Slot, 307 Buffer, 308 Offset, 309 Length, 310 PCIConfigHandler.ConfigWrite); 311 } 312 } 313 314 #ifdef SARCH_XBOX 315 BOOLEAN 316 NTAPI 317 HalpXboxBlacklistedPCISlot(IN PBUS_HANDLER BusHandler, 318 IN PCI_SLOT_NUMBER Slot) 319 { 320 /* Trying to get PCI config data from devices 0:0:1 and 0:0:2 will completely 321 * hang the Xbox. Also, the device number doesn't seem to be decoded for the 322 * video card, so it appears to be present on 1:0:0 - 1:31:0. 323 * We hack around these problems by indicating "device not present" for devices 324 * 0:0:1, 0:0:2, 1:1:0, 1:2:0, 1:3:0, ...., 1:31:0 */ 325 if ((BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 0 && 326 (Slot.u.bits.FunctionNumber == 1 || Slot.u.bits.FunctionNumber == 2)) || 327 (BusHandler->BusNumber == 1 && Slot.u.bits.DeviceNumber != 0)) 328 { 329 DPRINT("Blacklisted PCI slot (%d:%d:%d)\n", BusHandler->BusNumber, Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber); 330 return TRUE; 331 } 332 333 /* Temporary hack to avoid stack overflow in kernel, see CORE-16319 */ 334 if (BusHandler->BusNumber == 0 && Slot.u.bits.DeviceNumber == 8 && Slot.u.bits.FunctionNumber == 0) 335 { 336 DPRINT("Blacklisted PCI-to-PCI bridge (00:08.0 - PCI\\VEN_10DE&DEV_01B8, see CORE-16319)\n"); 337 return TRUE; 338 } 339 340 return FALSE; 341 } 342 #endif 343 344 BOOLEAN 345 NTAPI 346 HalpValidPCISlot(IN PBUS_HANDLER BusHandler, 347 IN PCI_SLOT_NUMBER Slot) 348 { 349 PCI_SLOT_NUMBER MultiSlot; 350 PPCIPBUSDATA BusData = (PPCIPBUSDATA)BusHandler->BusData; 351 UCHAR HeaderType; 352 //ULONG Device; 353 354 /* Simple validation */ 355 if (Slot.u.bits.Reserved) return FALSE; 356 if (Slot.u.bits.DeviceNumber >= BusData->MaxDevice) return FALSE; 357 358 #ifdef SARCH_XBOX 359 if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return FALSE; 360 #endif 361 362 /* Function 0 doesn't need checking */ 363 if (!Slot.u.bits.FunctionNumber) return TRUE; 364 365 /* Functions 0+ need Multi-Function support, so check the slot */ 366 //Device = Slot.u.bits.DeviceNumber; 367 MultiSlot = Slot; 368 MultiSlot.u.bits.FunctionNumber = 0; 369 370 /* Send function 0 request to get the header back */ 371 HalpReadPCIConfig(BusHandler, 372 MultiSlot, 373 &HeaderType, 374 FIELD_OFFSET(PCI_COMMON_CONFIG, HeaderType), 375 sizeof(UCHAR)); 376 377 /* Now make sure the header is multi-function */ 378 if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) return FALSE; 379 return TRUE; 380 } 381 382 /* HAL PCI CALLBACKS *********************************************************/ 383 384 ULONG 385 NTAPI 386 HalpGetPCIData(IN PBUS_HANDLER BusHandler, 387 IN PBUS_HANDLER RootHandler, 388 IN ULONG SlotNumber, 389 IN PVOID Buffer, 390 IN ULONG Offset, 391 IN ULONG Length) 392 { 393 PCI_SLOT_NUMBER Slot; 394 UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; 395 PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; 396 ULONG Len = 0; 397 398 Slot.u.AsULONG = SlotNumber; 399 #ifdef SARCH_XBOX 400 if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) 401 { 402 if (Offset == 0 && Length >= sizeof(USHORT)) 403 { 404 *(PUSHORT)Buffer = PCI_INVALID_VENDORID; 405 return sizeof(USHORT); 406 } 407 return 0; 408 } 409 #endif 410 411 /* Normalize the length */ 412 if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG); 413 414 /* Check if this is a vendor-specific read */ 415 if (Offset >= PCI_COMMON_HDR_LENGTH) 416 { 417 /* Read the header */ 418 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); 419 420 /* Make sure the vendor is valid */ 421 if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; 422 } 423 else 424 { 425 /* Read the entire header */ 426 Len = PCI_COMMON_HDR_LENGTH; 427 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); 428 429 /* Validate the vendor ID */ 430 if (PciConfig->VendorID == PCI_INVALID_VENDORID) 431 { 432 /* It's invalid, but we want to return this much */ 433 Len = sizeof(USHORT); 434 } 435 436 /* Now check if there's space left */ 437 if (Len < Offset) return 0; 438 439 /* There is, so return what's after the offset and normalize */ 440 Len -= Offset; 441 if (Len > Length) Len = Length; 442 443 /* Copy the data into the caller's buffer */ 444 RtlMoveMemory(Buffer, PciBuffer + Offset, Len); 445 446 /* Update buffer and offset, decrement total length */ 447 Offset += Len; 448 Buffer = (PVOID)((ULONG_PTR)Buffer + Len); 449 Length -= Len; 450 } 451 452 /* Now we still have something to copy */ 453 if (Length) 454 { 455 /* Check if it's vendor-specific data */ 456 if (Offset >= PCI_COMMON_HDR_LENGTH) 457 { 458 /* Read it now */ 459 HalpReadPCIConfig(BusHandler, Slot, Buffer, Offset, Length); 460 Len += Length; 461 } 462 } 463 464 /* Update the total length read */ 465 return Len; 466 } 467 468 ULONG 469 NTAPI 470 HalpSetPCIData(IN PBUS_HANDLER BusHandler, 471 IN PBUS_HANDLER RootHandler, 472 IN ULONG SlotNumber, 473 IN PVOID Buffer, 474 IN ULONG Offset, 475 IN ULONG Length) 476 { 477 PCI_SLOT_NUMBER Slot; 478 UCHAR PciBuffer[PCI_COMMON_HDR_LENGTH]; 479 PPCI_COMMON_CONFIG PciConfig = (PPCI_COMMON_CONFIG)PciBuffer; 480 ULONG Len = 0; 481 482 Slot.u.AsULONG = SlotNumber; 483 #ifdef SARCH_XBOX 484 if (HalpXboxBlacklistedPCISlot(BusHandler, Slot)) return 0; 485 #endif 486 487 /* Normalize the length */ 488 if (Length > sizeof(PCI_COMMON_CONFIG)) Length = sizeof(PCI_COMMON_CONFIG); 489 490 /* Check if this is a vendor-specific read */ 491 if (Offset >= PCI_COMMON_HDR_LENGTH) 492 { 493 /* Read the header */ 494 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, sizeof(ULONG)); 495 496 /* Make sure the vendor is valid */ 497 if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; 498 } 499 else 500 { 501 /* Read the entire header and validate the vendor ID */ 502 Len = PCI_COMMON_HDR_LENGTH; 503 HalpReadPCIConfig(BusHandler, Slot, PciConfig, 0, Len); 504 if (PciConfig->VendorID == PCI_INVALID_VENDORID) return 0; 505 506 /* Return what's after the offset and normalize */ 507 Len -= Offset; 508 if (Len > Length) Len = Length; 509 510 /* Copy the specific caller data */ 511 RtlMoveMemory(PciBuffer + Offset, Buffer, Len); 512 513 /* Write the actual configuration data */ 514 HalpWritePCIConfig(BusHandler, Slot, PciBuffer + Offset, Offset, Len); 515 516 /* Update buffer and offset, decrement total length */ 517 Offset += Len; 518 Buffer = (PVOID)((ULONG_PTR)Buffer + Len); 519 Length -= Len; 520 } 521 522 /* Now we still have something to copy */ 523 if (Length) 524 { 525 /* Check if it's vendor-specific data */ 526 if (Offset >= PCI_COMMON_HDR_LENGTH) 527 { 528 /* Read it now */ 529 HalpWritePCIConfig(BusHandler, Slot, Buffer, Offset, Length); 530 Len += Length; 531 } 532 } 533 534 /* Update the total length read */ 535 return Len; 536 } 537 538 ULONG 539 NTAPI 540 HalpGetPCIIntOnISABus(IN PBUS_HANDLER BusHandler, 541 IN PBUS_HANDLER RootHandler, 542 IN ULONG BusInterruptLevel, 543 IN ULONG BusInterruptVector, 544 OUT PKIRQL Irql, 545 OUT PKAFFINITY Affinity) 546 { 547 /* Validate the level first */ 548 if (BusInterruptLevel < 1) return 0; 549 550 /* PCI has its IRQs on top of ISA IRQs, so pass it on to the ISA handler */ 551 return HalGetInterruptVector(Isa, 552 0, 553 BusInterruptLevel, 554 0, 555 Irql, 556 Affinity); 557 } 558 559 VOID 560 NTAPI 561 HalpPCIPin2ISALine(IN PBUS_HANDLER BusHandler, 562 IN PBUS_HANDLER RootHandler, 563 IN PCI_SLOT_NUMBER SlotNumber, 564 IN PPCI_COMMON_CONFIG PciData) 565 { 566 UNIMPLEMENTED_DBGBREAK(); 567 } 568 569 VOID 570 NTAPI 571 HalpPCIISALine2Pin(IN PBUS_HANDLER BusHandler, 572 IN PBUS_HANDLER RootHandler, 573 IN PCI_SLOT_NUMBER SlotNumber, 574 IN PPCI_COMMON_CONFIG PciNewData, 575 IN PPCI_COMMON_CONFIG PciOldData) 576 { 577 UNIMPLEMENTED_DBGBREAK(); 578 } 579 580 NTSTATUS 581 NTAPI 582 HalpGetISAFixedPCIIrq(IN PBUS_HANDLER BusHandler, 583 IN PBUS_HANDLER RootHandler, 584 IN PCI_SLOT_NUMBER PciSlot, 585 OUT PSUPPORTED_RANGE *Range) 586 { 587 PCI_COMMON_HEADER PciData; 588 589 /* Read PCI configuration data */ 590 HalGetBusData(PCIConfiguration, 591 BusHandler->BusNumber, 592 PciSlot.u.AsULONG, 593 &PciData, 594 PCI_COMMON_HDR_LENGTH); 595 596 /* Make sure it's a real device */ 597 if (PciData.VendorID == PCI_INVALID_VENDORID) return STATUS_UNSUCCESSFUL; 598 599 /* Allocate the supported range structure */ 600 *Range = ExAllocatePoolWithTag(PagedPool, sizeof(SUPPORTED_RANGE), TAG_HAL); 601 if (!*Range) return STATUS_INSUFFICIENT_RESOURCES; 602 603 /* Set it up */ 604 RtlZeroMemory(*Range, sizeof(SUPPORTED_RANGE)); 605 (*Range)->Base = 1; 606 607 /* If the PCI device has no IRQ, nothing to do */ 608 if (!PciData.u.type0.InterruptPin) return STATUS_SUCCESS; 609 610 /* FIXME: The PCI IRQ Routing Miniport should be called */ 611 612 /* Also if the INT# seems bogus, nothing to do either */ 613 if ((PciData.u.type0.InterruptLine == 0) || 614 (PciData.u.type0.InterruptLine == 255)) 615 { 616 /* Fake success */ 617 return STATUS_SUCCESS; 618 } 619 620 /* Otherwise, the INT# should be valid, return it to the caller */ 621 (*Range)->Base = PciData.u.type0.InterruptLine; 622 (*Range)->Limit = PciData.u.type0.InterruptLine; 623 return STATUS_SUCCESS; 624 } 625 626 INIT_FUNCTION 627 NTSTATUS 628 NTAPI 629 HalpSetupPciDeviceForDebugging(IN PVOID LoaderBlock, 630 IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice) 631 { 632 DPRINT1("Unimplemented!\n"); 633 return STATUS_NOT_IMPLEMENTED; 634 } 635 636 INIT_FUNCTION 637 NTSTATUS 638 NTAPI 639 HalpReleasePciDeviceForDebugging(IN OUT PDEBUG_DEVICE_DESCRIPTOR PciDevice) 640 { 641 DPRINT1("Unimplemented!\n"); 642 return STATUS_NOT_IMPLEMENTED; 643 } 644 645 INIT_FUNCTION 646 VOID 647 NTAPI 648 HalpRegisterPciDebuggingDeviceInfo(VOID) 649 { 650 BOOLEAN Found = FALSE; 651 ULONG i; 652 PAGED_CODE(); 653 654 /* Loop PCI debugging devices */ 655 for (i = 0; i < 2; i++) 656 { 657 /* Reserved bit is set if we found one */ 658 if (HalpPciDebuggingDevice[i].u.bits.Reserved1) 659 { 660 Found = TRUE; 661 break; 662 } 663 } 664 665 /* Bail out if there aren't any */ 666 if (!Found) return; 667 668 /* FIXME: TODO */ 669 UNIMPLEMENTED_DBGBREAK("You have implemented the KD routines for searching PCI debugger" 670 "devices, but you have forgotten to implement this routine\n"); 671 } 672 673 static ULONG NTAPI 674 PciSize(ULONG Base, ULONG Mask) 675 { 676 ULONG Size = Mask & Base; /* Find the significant bits */ 677 Size = Size & ~(Size - 1); /* Get the lowest of them to find the decode size */ 678 return Size; 679 } 680 681 NTSTATUS 682 NTAPI 683 HalpAdjustPCIResourceList(IN PBUS_HANDLER BusHandler, 684 IN PBUS_HANDLER RootHandler, 685 IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList) 686 { 687 PPCIPBUSDATA BusData; 688 PCI_SLOT_NUMBER SlotNumber; 689 PSUPPORTED_RANGE Interrupt; 690 NTSTATUS Status; 691 692 /* Get PCI bus data */ 693 BusData = BusHandler->BusData; 694 SlotNumber.u.AsULONG = (*pResourceList)->SlotNumber; 695 696 /* Get the IRQ supported range */ 697 Status = BusData->GetIrqRange(BusHandler, RootHandler, SlotNumber, &Interrupt); 698 if (!NT_SUCCESS(Status)) return Status; 699 #ifndef _MINIHAL_ 700 /* Handle the /PCILOCK feature */ 701 if (HalpPciLockSettings) 702 { 703 /* /PCILOCK is not yet supported */ 704 UNIMPLEMENTED_DBGBREAK("/PCILOCK boot switch is not yet supported."); 705 } 706 #endif 707 /* Now create the correct resource list based on the supported bus ranges */ 708 #if 0 709 Status = HaliAdjustResourceListRange(BusHandler->BusAddresses, 710 Interrupt, 711 pResourceList); 712 #else 713 DPRINT1("HAL: No PCI Resource Adjustment done! Hardware may malfunction\n"); 714 Status = STATUS_SUCCESS; 715 #endif 716 717 /* Return to caller */ 718 ExFreePool(Interrupt); 719 return Status; 720 } 721 722 NTSTATUS 723 NTAPI 724 HalpAssignPCISlotResources(IN PBUS_HANDLER BusHandler, 725 IN PBUS_HANDLER RootHandler, 726 IN PUNICODE_STRING RegistryPath, 727 IN PUNICODE_STRING DriverClassName OPTIONAL, 728 IN PDRIVER_OBJECT DriverObject, 729 IN PDEVICE_OBJECT DeviceObject OPTIONAL, 730 IN ULONG Slot, 731 IN OUT PCM_RESOURCE_LIST *AllocatedResources) 732 { 733 PCI_COMMON_CONFIG PciConfig; 734 SIZE_T Address; 735 ULONG ResourceCount; 736 ULONG Size[PCI_TYPE0_ADDRESSES]; 737 NTSTATUS Status = STATUS_SUCCESS; 738 UCHAR Offset; 739 PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor; 740 PCI_SLOT_NUMBER SlotNumber; 741 ULONG WriteBuffer; 742 DPRINT1("WARNING: PCI Slot Resource Assignment is FOOBAR\n"); 743 744 /* FIXME: Should handle 64-bit addresses */ 745 746 /* Read configuration data */ 747 SlotNumber.u.AsULONG = Slot; 748 HalpReadPCIConfig(BusHandler, SlotNumber, &PciConfig, 0, PCI_COMMON_HDR_LENGTH); 749 750 /* Check if we read it correctly */ 751 if (PciConfig.VendorID == PCI_INVALID_VENDORID) 752 return STATUS_NO_SUCH_DEVICE; 753 754 /* Read the PCI configuration space for the device and store base address and 755 size information in temporary storage. Count the number of valid base addresses */ 756 ResourceCount = 0; 757 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) 758 { 759 if (0xffffffff == PciConfig.u.type0.BaseAddresses[Address]) 760 PciConfig.u.type0.BaseAddresses[Address] = 0; 761 762 /* Memory resource */ 763 if (0 != PciConfig.u.type0.BaseAddresses[Address]) 764 { 765 ResourceCount++; 766 767 Offset = (UCHAR)FIELD_OFFSET(PCI_COMMON_CONFIG, u.type0.BaseAddresses[Address]); 768 769 /* Write 0xFFFFFFFF there */ 770 WriteBuffer = 0xffffffff; 771 HalpWritePCIConfig(BusHandler, SlotNumber, &WriteBuffer, Offset, sizeof(ULONG)); 772 773 /* Read that figure back from the config space */ 774 HalpReadPCIConfig(BusHandler, SlotNumber, &Size[Address], Offset, sizeof(ULONG)); 775 776 /* Write back initial value */ 777 HalpWritePCIConfig(BusHandler, SlotNumber, &PciConfig.u.type0.BaseAddresses[Address], Offset, sizeof(ULONG)); 778 } 779 } 780 781 /* Interrupt resource */ 782 if (0 != PciConfig.u.type0.InterruptPin && 783 0 != PciConfig.u.type0.InterruptLine && 784 0xFF != PciConfig.u.type0.InterruptLine) 785 ResourceCount++; 786 787 /* Allocate output buffer and initialize */ 788 *AllocatedResources = ExAllocatePoolWithTag( 789 PagedPool, 790 sizeof(CM_RESOURCE_LIST) + 791 (ResourceCount - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR), 792 TAG_HAL); 793 794 if (NULL == *AllocatedResources) 795 return STATUS_NO_MEMORY; 796 797 (*AllocatedResources)->Count = 1; 798 (*AllocatedResources)->List[0].InterfaceType = PCIBus; 799 (*AllocatedResources)->List[0].BusNumber = BusHandler->BusNumber; 800 (*AllocatedResources)->List[0].PartialResourceList.Version = 1; 801 (*AllocatedResources)->List[0].PartialResourceList.Revision = 1; 802 (*AllocatedResources)->List[0].PartialResourceList.Count = ResourceCount; 803 Descriptor = (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors; 804 805 /* Store configuration information */ 806 for (Address = 0; Address < PCI_TYPE0_ADDRESSES; Address++) 807 { 808 if (0 != PciConfig.u.type0.BaseAddresses[Address]) 809 { 810 if (PCI_ADDRESS_MEMORY_SPACE == 811 (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) 812 { 813 Descriptor->Type = CmResourceTypeMemory; 814 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ 815 Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE; /* FIXME Just a guess */ 816 Descriptor->u.Memory.Start.QuadPart = (PciConfig.u.type0.BaseAddresses[Address] & PCI_ADDRESS_MEMORY_ADDRESS_MASK); 817 Descriptor->u.Memory.Length = PciSize(Size[Address], PCI_ADDRESS_MEMORY_ADDRESS_MASK); 818 } 819 else if (PCI_ADDRESS_IO_SPACE == 820 (PciConfig.u.type0.BaseAddresses[Address] & 0x1)) 821 { 822 Descriptor->Type = CmResourceTypePort; 823 Descriptor->ShareDisposition = CmResourceShareDeviceExclusive; /* FIXME I have no idea... */ 824 Descriptor->Flags = CM_RESOURCE_PORT_IO; /* FIXME Just a guess */ 825 Descriptor->u.Port.Start.QuadPart = PciConfig.u.type0.BaseAddresses[Address] &= PCI_ADDRESS_IO_ADDRESS_MASK; 826 Descriptor->u.Port.Length = PciSize(Size[Address], PCI_ADDRESS_IO_ADDRESS_MASK & 0xffff); 827 } 828 else 829 { 830 ASSERT(FALSE); 831 return STATUS_UNSUCCESSFUL; 832 } 833 Descriptor++; 834 } 835 } 836 837 if (0 != PciConfig.u.type0.InterruptPin && 838 0 != PciConfig.u.type0.InterruptLine && 839 0xFF != PciConfig.u.type0.InterruptLine) 840 { 841 Descriptor->Type = CmResourceTypeInterrupt; 842 Descriptor->ShareDisposition = CmResourceShareShared; /* FIXME Just a guess */ 843 Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE; /* FIXME Just a guess */ 844 Descriptor->u.Interrupt.Level = PciConfig.u.type0.InterruptLine; 845 Descriptor->u.Interrupt.Vector = PciConfig.u.type0.InterruptLine; 846 Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF; 847 848 Descriptor++; 849 } 850 851 ASSERT(Descriptor == (*AllocatedResources)->List[0].PartialResourceList.PartialDescriptors + ResourceCount); 852 853 /* FIXME: Should store the resources in the registry resource map */ 854 855 return Status; 856 } 857 858 ULONG 859 NTAPI 860 HaliPciInterfaceReadConfig(IN PBUS_HANDLER RootBusHandler, 861 IN ULONG BusNumber, 862 IN PCI_SLOT_NUMBER SlotNumber, 863 IN PVOID Buffer, 864 IN ULONG Offset, 865 IN ULONG Length) 866 { 867 BUS_HANDLER BusHandler; 868 869 /* Setup fake PCI Bus handler */ 870 RtlCopyMemory(&BusHandler, &HalpFakePciBusHandler, sizeof(BUS_HANDLER)); 871 BusHandler.BusNumber = BusNumber; 872 873 /* Read configuration data */ 874 HalpReadPCIConfig(&BusHandler, SlotNumber, Buffer, Offset, Length); 875 876 /* Return length */ 877 return Length; 878 } 879 880 INIT_FUNCTION 881 PPCI_REGISTRY_INFO_INTERNAL 882 NTAPI 883 HalpQueryPciRegistryInfo(VOID) 884 { 885 #ifndef _MINIHAL_ 886 WCHAR NameBuffer[8]; 887 OBJECT_ATTRIBUTES ObjectAttributes; 888 UNICODE_STRING KeyName, ConfigName, IdentName; 889 HANDLE KeyHandle, BusKeyHandle, CardListHandle; 890 NTSTATUS Status; 891 UCHAR KeyBuffer[sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + 100]; 892 PKEY_VALUE_FULL_INFORMATION ValueInfo = (PVOID)KeyBuffer; 893 UCHAR PartialKeyBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 894 sizeof(PCI_CARD_DESCRIPTOR)]; 895 PKEY_VALUE_PARTIAL_INFORMATION PartialValueInfo = (PVOID)PartialKeyBuffer; 896 KEY_FULL_INFORMATION KeyInformation; 897 ULONG ResultLength; 898 PWSTR Tag; 899 ULONG i, ElementCount; 900 PCM_FULL_RESOURCE_DESCRIPTOR FullDescriptor; 901 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 902 PPCI_REGISTRY_INFO PciRegInfo; 903 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; 904 PPCI_CARD_DESCRIPTOR CardDescriptor; 905 906 /* Setup the object attributes for the key */ 907 RtlInitUnicodeString(&KeyName, 908 L"\\Registry\\Machine\\Hardware\\Description\\" 909 L"System\\MultiFunctionAdapter"); 910 InitializeObjectAttributes(&ObjectAttributes, 911 &KeyName, 912 OBJ_CASE_INSENSITIVE, 913 NULL, 914 NULL); 915 916 /* Open the key */ 917 Status = ZwOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes); 918 if (!NT_SUCCESS(Status)) return NULL; 919 920 /* Setup the receiving string */ 921 KeyName.Buffer = NameBuffer; 922 KeyName.MaximumLength = sizeof(NameBuffer); 923 924 /* Setup the configuration and identifier key names */ 925 RtlInitUnicodeString(&ConfigName, L"Configuration Data"); 926 RtlInitUnicodeString(&IdentName, L"Identifier"); 927 928 /* Keep looping for each ID */ 929 for (i = 0; TRUE; i++) 930 { 931 /* Setup the key name */ 932 RtlIntegerToUnicodeString(i, 10, &KeyName); 933 InitializeObjectAttributes(&ObjectAttributes, 934 &KeyName, 935 OBJ_CASE_INSENSITIVE, 936 KeyHandle, 937 NULL); 938 939 /* Open it */ 940 Status = ZwOpenKey(&BusKeyHandle, KEY_READ, &ObjectAttributes); 941 if (!NT_SUCCESS(Status)) 942 { 943 /* None left, fail */ 944 ZwClose(KeyHandle); 945 return NULL; 946 } 947 948 /* Read the registry data */ 949 Status = ZwQueryValueKey(BusKeyHandle, 950 &IdentName, 951 KeyValueFullInformation, 952 ValueInfo, 953 sizeof(KeyBuffer), 954 &ResultLength); 955 if (!NT_SUCCESS(Status)) 956 { 957 /* Failed, try the next one */ 958 ZwClose(BusKeyHandle); 959 continue; 960 } 961 962 /* Get the PCI Tag and validate it */ 963 Tag = (PWSTR)((ULONG_PTR)ValueInfo + ValueInfo->DataOffset); 964 if ((Tag[0] != L'P') || 965 (Tag[1] != L'C') || 966 (Tag[2] != L'I') || 967 (Tag[3])) 968 { 969 /* Not a valid PCI entry, skip it */ 970 ZwClose(BusKeyHandle); 971 continue; 972 } 973 974 /* Now read our PCI structure */ 975 Status = ZwQueryValueKey(BusKeyHandle, 976 &ConfigName, 977 KeyValueFullInformation, 978 ValueInfo, 979 sizeof(KeyBuffer), 980 &ResultLength); 981 ZwClose(BusKeyHandle); 982 if (!NT_SUCCESS(Status)) continue; 983 984 /* We read it OK! Get the actual resource descriptors */ 985 FullDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR) 986 ((ULONG_PTR)ValueInfo + ValueInfo->DataOffset); 987 PartialDescriptor = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) 988 ((ULONG_PTR)FullDescriptor-> 989 PartialResourceList.PartialDescriptors); 990 991 /* Check if this is our PCI Registry Information */ 992 if (PartialDescriptor->Type == CmResourceTypeDeviceSpecific) 993 { 994 /* It is, stop searching */ 995 break; 996 } 997 } 998 999 /* Close the key */ 1000 ZwClose(KeyHandle); 1001 1002 /* Save the PCI information for later */ 1003 PciRegInfo = (PPCI_REGISTRY_INFO)(PartialDescriptor + 1); 1004 1005 /* Assume no Card List entries */ 1006 ElementCount = 0; 1007 1008 /* Set up for checking the PCI Card List key */ 1009 RtlInitUnicodeString(&KeyName, 1010 L"\\Registry\\Machine\\System\\CurrentControlSet\\" 1011 L"Control\\PnP\\PCI\\CardList"); 1012 InitializeObjectAttributes(&ObjectAttributes, 1013 &KeyName, 1014 OBJ_CASE_INSENSITIVE, 1015 NULL, 1016 NULL); 1017 1018 /* Attempt to open it */ 1019 Status = ZwOpenKey(&CardListHandle, KEY_READ, &ObjectAttributes); 1020 if (NT_SUCCESS(Status)) 1021 { 1022 /* It exists, so let's query it */ 1023 Status = ZwQueryKey(CardListHandle, 1024 KeyFullInformation, 1025 &KeyInformation, 1026 sizeof(KEY_FULL_INFORMATION), 1027 &ResultLength); 1028 if (!NT_SUCCESS(Status)) 1029 { 1030 /* Failed to query, so no info */ 1031 PciRegistryInfo = NULL; 1032 } 1033 else 1034 { 1035 /* Allocate the full structure */ 1036 PciRegistryInfo = 1037 ExAllocatePoolWithTag(NonPagedPool, 1038 sizeof(PCI_REGISTRY_INFO_INTERNAL) + 1039 (KeyInformation.Values * 1040 sizeof(PCI_CARD_DESCRIPTOR)), 1041 TAG_HAL); 1042 if (PciRegistryInfo) 1043 { 1044 /* Get the first card descriptor entry */ 1045 CardDescriptor = (PPCI_CARD_DESCRIPTOR)(PciRegistryInfo + 1); 1046 1047 /* Loop all the values */ 1048 for (i = 0; i < KeyInformation.Values; i++) 1049 { 1050 /* Attempt to get the value */ 1051 Status = ZwEnumerateValueKey(CardListHandle, 1052 i, 1053 KeyValuePartialInformation, 1054 PartialValueInfo, 1055 sizeof(PartialKeyBuffer), 1056 &ResultLength); 1057 if (!NT_SUCCESS(Status)) 1058 { 1059 /* Something went wrong, stop the search */ 1060 break; 1061 } 1062 1063 /* Make sure it is correctly sized */ 1064 if (PartialValueInfo->DataLength == sizeof(PCI_CARD_DESCRIPTOR)) 1065 { 1066 /* Sure is, copy it over */ 1067 *CardDescriptor = *(PPCI_CARD_DESCRIPTOR) 1068 PartialValueInfo->Data; 1069 1070 /* One more Card List entry */ 1071 ElementCount++; 1072 1073 /* Move to the next descriptor */ 1074 CardDescriptor = (CardDescriptor + 1); 1075 } 1076 } 1077 } 1078 } 1079 1080 /* Close the Card List key */ 1081 ZwClose(CardListHandle); 1082 } 1083 else 1084 { 1085 /* No key, no Card List */ 1086 PciRegistryInfo = NULL; 1087 } 1088 1089 /* Check if we failed to get the full structure */ 1090 if (!PciRegistryInfo) 1091 { 1092 /* Just allocate the basic structure then */ 1093 PciRegistryInfo = ExAllocatePoolWithTag(NonPagedPool, 1094 sizeof(PCI_REGISTRY_INFO_INTERNAL), 1095 TAG_HAL); 1096 if (!PciRegistryInfo) return NULL; 1097 } 1098 1099 /* Save the info we got */ 1100 PciRegistryInfo->MajorRevision = PciRegInfo->MajorRevision; 1101 PciRegistryInfo->MinorRevision = PciRegInfo->MinorRevision; 1102 PciRegistryInfo->NoBuses = PciRegInfo->NoBuses; 1103 PciRegistryInfo->HardwareMechanism = PciRegInfo->HardwareMechanism; 1104 PciRegistryInfo->ElementCount = ElementCount; 1105 1106 /* Return it */ 1107 return PciRegistryInfo; 1108 #else 1109 return NULL; 1110 #endif 1111 } 1112 1113 INIT_FUNCTION 1114 VOID 1115 NTAPI 1116 HalpInitializePciStubs(VOID) 1117 { 1118 PPCI_REGISTRY_INFO_INTERNAL PciRegistryInfo; 1119 UCHAR PciType; 1120 PPCIPBUSDATA BusData = (PPCIPBUSDATA)HalpFakePciBusHandler.BusData; 1121 ULONG i; 1122 PCI_SLOT_NUMBER j; 1123 ULONG VendorId = 0; 1124 ULONG MaxPciBusNumber; 1125 1126 /* Query registry information */ 1127 PciRegistryInfo = HalpQueryPciRegistryInfo(); 1128 if (!PciRegistryInfo) 1129 { 1130 /* Assume type 1 */ 1131 PciType = 1; 1132 1133 /* Force a manual bus scan later */ 1134 MaxPciBusNumber = MAXULONG; 1135 } 1136 else 1137 { 1138 /* Get the PCI type */ 1139 PciType = PciRegistryInfo->HardwareMechanism & 0xF; 1140 1141 /* Get MaxPciBusNumber and make it 0-based */ 1142 MaxPciBusNumber = PciRegistryInfo->NoBuses - 1; 1143 1144 /* Free the info structure */ 1145 ExFreePoolWithTag(PciRegistryInfo, TAG_HAL); 1146 } 1147 1148 /* Initialize the PCI lock */ 1149 KeInitializeSpinLock(&HalpPCIConfigLock); 1150 1151 /* Check the type of PCI bus */ 1152 switch (PciType) 1153 { 1154 /* Type 1 PCI Bus */ 1155 case 1: 1156 1157 /* Copy the Type 1 handler data */ 1158 RtlCopyMemory(&PCIConfigHandler, 1159 &PCIConfigHandlerType1, 1160 sizeof(PCIConfigHandler)); 1161 1162 /* Set correct I/O Ports */ 1163 BusData->Config.Type1.Address = PCI_TYPE1_ADDRESS_PORT; 1164 BusData->Config.Type1.Data = PCI_TYPE1_DATA_PORT; 1165 break; 1166 1167 /* Type 2 PCI Bus */ 1168 case 2: 1169 1170 /* Copy the Type 2 handler data */ 1171 RtlCopyMemory(&PCIConfigHandler, 1172 &PCIConfigHandlerType2, 1173 sizeof (PCIConfigHandler)); 1174 1175 /* Set correct I/O Ports */ 1176 BusData->Config.Type2.CSE = PCI_TYPE2_CSE_PORT; 1177 BusData->Config.Type2.Forward = PCI_TYPE2_FORWARD_PORT; 1178 BusData->Config.Type2.Base = PCI_TYPE2_ADDRESS_BASE; 1179 1180 /* Only 16 devices supported, not 32 */ 1181 BusData->MaxDevice = 16; 1182 break; 1183 1184 default: 1185 1186 /* Invalid type */ 1187 DbgPrint("HAL: Unknown PCI type\n"); 1188 } 1189 1190 /* Run a forced bus scan if needed */ 1191 if (MaxPciBusNumber == MAXULONG) 1192 { 1193 /* Initialize the max bus number to 0xFF */ 1194 HalpMaxPciBus = 0xFF; 1195 1196 /* Initialize the counter */ 1197 MaxPciBusNumber = 0; 1198 1199 /* Loop all possible buses */ 1200 for (i = 0; i < HalpMaxPciBus; i++) 1201 { 1202 /* Loop all devices */ 1203 for (j.u.AsULONG = 0; j.u.AsULONG < BusData->MaxDevice; j.u.AsULONG++) 1204 { 1205 /* Query the interface */ 1206 if (HaliPciInterfaceReadConfig(NULL, 1207 i, 1208 j, 1209 &VendorId, 1210 0, 1211 sizeof(ULONG))) 1212 { 1213 /* Validate the vendor ID */ 1214 if ((VendorId & 0xFFFF) != PCI_INVALID_VENDORID) 1215 { 1216 /* Set this as the maximum ID */ 1217 MaxPciBusNumber = i; 1218 break; 1219 } 1220 } 1221 } 1222 } 1223 } 1224 1225 /* Set the real max bus number */ 1226 HalpMaxPciBus = MaxPciBusNumber; 1227 1228 /* We're done */ 1229 HalpPCIConfigInitialized = TRUE; 1230 } 1231 1232 /* EOF */ 1233 1234