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