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