1 /*++ 2 3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 PcatPciRootBridgeIo.c 14 15 Abstract: 16 17 EFI PC AT PCI Root Bridge Io Protocol 18 19 Revision History 20 21 --*/ 22 23 #include "PcatPciRootBridge.h" 24 25 BOOLEAN mPciOptionRomTableInstalled = FALSE; 26 EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; 27 28 EFI_STATUS 29 EFIAPI 30 PcatRootBridgeIoIoRead ( 31 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, 32 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, 33 IN UINT64 UserAddress, 34 IN UINTN Count, 35 IN OUT VOID *UserBuffer 36 ) 37 { 38 return gCpuIo->Io.Read ( 39 gCpuIo, 40 (EFI_CPU_IO_PROTOCOL_WIDTH) Width, 41 UserAddress, 42 Count, 43 UserBuffer 44 ); 45 } 46 47 EFI_STATUS 48 EFIAPI 49 PcatRootBridgeIoIoWrite ( 50 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, 51 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, 52 IN UINT64 UserAddress, 53 IN UINTN Count, 54 IN OUT VOID *UserBuffer 55 ) 56 { 57 return gCpuIo->Io.Write ( 58 gCpuIo, 59 (EFI_CPU_IO_PROTOCOL_WIDTH) Width, 60 UserAddress, 61 Count, 62 UserBuffer 63 ); 64 65 } 66 67 EFI_STATUS 68 PcatRootBridgeIoGetIoPortMapping ( 69 OUT EFI_PHYSICAL_ADDRESS *IoPortMapping, 70 OUT EFI_PHYSICAL_ADDRESS *MemoryPortMapping 71 ) 72 /*++ 73 74 Get the IO Port Mapping. For IA-32 it is always 0. 75 76 --*/ 77 { 78 *IoPortMapping = 0; 79 *MemoryPortMapping = 0; 80 81 return EFI_SUCCESS; 82 } 83 84 EFI_STATUS 85 PcatRootBridgeIoPciRW ( 86 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, 87 IN BOOLEAN Write, 88 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width, 89 IN UINT64 UserAddress, 90 IN UINTN Count, 91 IN OUT VOID *UserBuffer 92 ) 93 { 94 PCI_CONFIG_ACCESS_CF8 Pci; 95 PCI_CONFIG_ACCESS_CF8 PciAligned; 96 UINT32 InStride; 97 UINT32 OutStride; 98 UINTN PciData; 99 UINTN PciDataStride; 100 PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData; 101 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress; 102 UINT64 PciExpressRegAddr; 103 BOOLEAN UsePciExpressAccess; 104 105 if ((UINT32)Width >= EfiPciWidthMaximum) { 106 return EFI_INVALID_PARAMETER; 107 } 108 109 if ((Width & 0x03) >= EfiPciWidthUint64) { 110 return EFI_INVALID_PARAMETER; 111 } 112 113 PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This); 114 115 InStride = 1 << (Width & 0x03); 116 OutStride = InStride; 117 if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) { 118 InStride = 0; 119 } 120 121 if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) { 122 OutStride = 0; 123 } 124 125 UsePciExpressAccess = FALSE; 126 127 CopyMem (&PciAddress, &UserAddress, sizeof(UINT64)); 128 129 if (PciAddress.ExtendedRegister > 0xFF) { 130 // 131 // Check PciExpressBaseAddress 132 // 133 if ((PrivateData->PciExpressBaseAddress == 0) || 134 (PrivateData->PciExpressBaseAddress >= MAX_ADDRESS)) { 135 return EFI_UNSUPPORTED; 136 } else { 137 UsePciExpressAccess = TRUE; 138 } 139 } else { 140 if (PciAddress.ExtendedRegister != 0) { 141 Pci.Bits.Reg = PciAddress.ExtendedRegister & 0xFF; 142 } else { 143 Pci.Bits.Reg = PciAddress.Register; 144 } 145 // 146 // Note: We can also use PciExpress access here, if wanted. 147 // 148 } 149 150 if (!UsePciExpressAccess) { 151 Pci.Bits.Func = PciAddress.Function; 152 Pci.Bits.Dev = PciAddress.Device; 153 Pci.Bits.Bus = PciAddress.Bus; 154 Pci.Bits.Reserved = 0; 155 Pci.Bits.Enable = 1; 156 157 // 158 // PCI Config access are all 32-bit alligned, but by accessing the 159 // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types 160 // are possible on PCI. 161 // 162 // To read a byte of PCI config space you load 0xcf8 and 163 // read 0xcfc, 0xcfd, 0xcfe, 0xcff 164 // 165 PciDataStride = Pci.Bits.Reg & 0x03; 166 167 while (Count) { 168 PciAligned = Pci; 169 PciAligned.Bits.Reg &= 0xfc; 170 PciData = (UINTN)PrivateData->PciData + PciDataStride; 171 EfiAcquireLock(&PrivateData->PciLock); 172 This->Io.Write (This, EfiPciWidthUint32, PrivateData->PciAddress, 1, &PciAligned); 173 if (Write) { 174 This->Io.Write (This, Width, PciData, 1, UserBuffer); 175 } else { 176 This->Io.Read (This, Width, PciData, 1, UserBuffer); 177 } 178 EfiReleaseLock(&PrivateData->PciLock); 179 UserBuffer = ((UINT8 *)UserBuffer) + OutStride; 180 PciDataStride = (PciDataStride + InStride) % 4; 181 Pci.Bits.Reg += InStride; 182 Count -= 1; 183 } 184 } else { 185 // 186 // Access PCI-Express space by using memory mapped method. 187 // 188 PciExpressRegAddr = (PrivateData->PciExpressBaseAddress) | 189 (PciAddress.Bus << 20) | 190 (PciAddress.Device << 15) | 191 (PciAddress.Function << 12); 192 if (PciAddress.ExtendedRegister != 0) { 193 PciExpressRegAddr += PciAddress.ExtendedRegister; 194 } else { 195 PciExpressRegAddr += PciAddress.Register; 196 } 197 while (Count) { 198 if (Write) { 199 This->Mem.Write (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); 200 } else { 201 This->Mem.Read (This, Width, (UINTN) PciExpressRegAddr, 1, UserBuffer); 202 } 203 204 UserBuffer = ((UINT8 *) UserBuffer) + OutStride; 205 PciExpressRegAddr += InStride; 206 Count -= 1; 207 } 208 } 209 210 return EFI_SUCCESS; 211 } 212 213 VOID 214 ScanPciBus( 215 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, 216 UINT16 MinBus, 217 UINT16 MaxBus, 218 UINT16 MinDevice, 219 UINT16 MaxDevice, 220 UINT16 MinFunc, 221 UINT16 MaxFunc, 222 EFI_PCI_BUS_SCAN_CALLBACK Callback, 223 VOID *Context 224 ) 225 226 { 227 UINT16 Bus; 228 UINT16 Device; 229 UINT16 Func; 230 UINT64 Address; 231 PCI_TYPE00 PciHeader; 232 233 // 234 // Loop through all busses 235 // 236 for (Bus = MinBus; Bus <= MaxBus; Bus++) { 237 // 238 // Loop 32 devices per bus 239 // 240 for (Device = MinDevice; Device <= MaxDevice; Device++) { 241 // 242 // Loop through 8 functions per device 243 // 244 for (Func = MinFunc; Func <= MaxFunc; Func++) { 245 246 // 247 // Compute the EFI Address required to access the PCI Configuration Header of this PCI Device 248 // 249 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); 250 251 // 252 // Read the VendorID from this PCI Device's Confioguration Header 253 // 254 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &PciHeader.Hdr.VendorId); 255 256 // 257 // If VendorId = 0xffff, there does not exist a device at this 258 // location. For each device, if there is any function on it, 259 // there must be 1 function at Function 0. So if Func = 0, there 260 // will be no more functions in the same device, so we can break 261 // loop to deal with the next device. 262 // 263 if (PciHeader.Hdr.VendorId == 0xffff && Func == 0) { 264 break; 265 } 266 267 if (PciHeader.Hdr.VendorId != 0xffff) { 268 269 // 270 // Read the HeaderType to determine if this is a multi-function device 271 // 272 IoDev->Pci.Read (IoDev, EfiPciWidthUint8, Address + 0x0e, 1, &PciHeader.Hdr.HeaderType); 273 274 // 275 // Call the callback function for the device that was found 276 // 277 Callback( 278 IoDev, 279 MinBus, MaxBus, 280 MinDevice, MaxDevice, 281 MinFunc, MaxFunc, 282 Bus, 283 Device, 284 Func, 285 Context 286 ); 287 288 // 289 // If this is not a multi-function device, we can leave the loop 290 // to deal with the next device. 291 // 292 if ((PciHeader.Hdr.HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00 && Func == 0) { 293 break; 294 } 295 } 296 } 297 } 298 } 299 } 300 301 VOID 302 CheckForRom ( 303 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, 304 UINT16 MinBus, 305 UINT16 MaxBus, 306 UINT16 MinDevice, 307 UINT16 MaxDevice, 308 UINT16 MinFunc, 309 UINT16 MaxFunc, 310 UINT16 Bus, 311 UINT16 Device, 312 UINT16 Func, 313 IN VOID *VoidContext 314 ) 315 { 316 EFI_STATUS Status; 317 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; 318 UINT64 Address; 319 PCI_TYPE00 PciHeader; 320 PCI_TYPE01 *PciBridgeHeader; 321 UINT32 Register; 322 UINT32 RomBar; 323 UINT32 RomBarSize; 324 EFI_PHYSICAL_ADDRESS RomBuffer; 325 UINT32 MaxRomSize; 326 EFI_PCI_EXPANSION_ROM_HEADER EfiRomHeader; 327 PCI_DATA_STRUCTURE Pcir; 328 EFI_PCI_OPTION_ROM_DESCRIPTOR *TempPciOptionRomDescriptors; 329 BOOLEAN LastImage; 330 331 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; 332 333 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); 334 335 // 336 // Save the contents of the PCI Configuration Header 337 // 338 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); 339 340 if (IS_PCI_BRIDGE(&PciHeader)) { 341 342 PciBridgeHeader = (PCI_TYPE01 *)(&PciHeader); 343 344 // 345 // See if the PCI-PCI Bridge has its secondary interface enabled. 346 // 347 if (PciBridgeHeader->Bridge.SubordinateBus >= PciBridgeHeader->Bridge.SecondaryBus) { 348 349 // 350 // Disable the Prefetchable Memory Window 351 // 352 Register = 0x00000000; 353 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x26, 1, &Register); 354 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x2c, 1, &Register); 355 Register = 0xffffffff; 356 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x24, 1, &Register); 357 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x28, 1, &Register); 358 359 // 360 // Program Memory Window to the PCI Root Bridge Memory Window 361 // 362 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 0x20, 4, &Context->PpbMemoryWindow); 363 364 // 365 // Enable the Memory decode for the PCI-PCI Bridge 366 // 367 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); 368 Register |= 0x02; 369 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); 370 371 // 372 // Recurse on the Secondary Bus Number 373 // 374 ScanPciBus( 375 IoDev, 376 PciBridgeHeader->Bridge.SecondaryBus, PciBridgeHeader->Bridge.SecondaryBus, 377 0, PCI_MAX_DEVICE, 378 0, PCI_MAX_FUNC, 379 CheckForRom, Context 380 ); 381 } 382 } else { 383 384 // 385 // Check if an Option ROM Register is present and save the Option ROM Window Register 386 // 387 RomBar = 0xffffffff; 388 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); 389 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); 390 391 RomBarSize = (~(RomBar & 0xfffff800)) + 1; 392 393 // 394 // Make sure the size of the ROM is between 0 and 16 MB 395 // 396 if (RomBarSize > 0 && RomBarSize <= 0x01000000) { 397 398 // 399 // Program Option ROM Window Register to the PCI Root Bridge Window and Enable the Option ROM Window 400 // 401 RomBar = (Context->PpbMemoryWindow & 0xffff) << 16; 402 RomBar = ((RomBar - 1) & (~(RomBarSize - 1))) + RomBarSize; 403 if (RomBar < (Context->PpbMemoryWindow & 0xffff0000)) { 404 MaxRomSize = (Context->PpbMemoryWindow & 0xffff0000) - RomBar; 405 RomBar = RomBar + 1; 406 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); 407 IoDev->Pci.Read (IoDev, EfiPciWidthUint32, Address + 0x30, 1, &RomBar); 408 RomBar = RomBar - 1; 409 410 // 411 // Enable the Memory decode for the PCI Device 412 // 413 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); 414 Register |= 0x02; 415 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); 416 417 // 418 // Follow the chain of images to determine the size of the Option ROM present 419 // Keep going until the last image is found by looking at the Indicator field 420 // or the size of an image is 0, or the size of all the images is bigger than the 421 // size of the window programmed into the PPB. 422 // 423 RomBarSize = 0; 424 do { 425 426 LastImage = TRUE; 427 428 ZeroMem (&EfiRomHeader, sizeof(EfiRomHeader)); 429 IoDev->Mem.Read ( 430 IoDev, 431 EfiPciWidthUint8, 432 RomBar + RomBarSize, 433 sizeof(EfiRomHeader), 434 &EfiRomHeader 435 ); 436 437 Pcir.ImageLength = 0; 438 439 if (EfiRomHeader.Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE && 440 EfiRomHeader.PcirOffset != 0 && 441 (EfiRomHeader.PcirOffset & 3) == 0 && 442 RomBarSize + EfiRomHeader.PcirOffset + sizeof (PCI_DATA_STRUCTURE) <= MaxRomSize) { 443 ZeroMem (&Pcir, sizeof(Pcir)); 444 IoDev->Mem.Read ( 445 IoDev, 446 EfiPciWidthUint8, 447 RomBar + RomBarSize + EfiRomHeader.PcirOffset, 448 sizeof(Pcir), 449 &Pcir 450 ); 451 452 if (Pcir.Signature != PCI_DATA_STRUCTURE_SIGNATURE) { 453 break; 454 } 455 if (RomBarSize + Pcir.ImageLength * 512 > MaxRomSize) { 456 break; 457 } 458 if ((Pcir.Indicator & 0x80) == 0x00) { 459 LastImage = FALSE; 460 } 461 462 RomBarSize += Pcir.ImageLength * 512; 463 } 464 } while (!LastImage && RomBarSize < MaxRomSize && Pcir.ImageLength !=0); 465 466 if (RomBarSize > 0) { 467 468 // 469 // Allocate a memory buffer for the Option ROM contents. 470 // 471 Status = gBS->AllocatePages( 472 AllocateAnyPages, 473 EfiBootServicesData, 474 EFI_SIZE_TO_PAGES(RomBarSize), 475 &RomBuffer 476 ); 477 478 if (!EFI_ERROR (Status)) { 479 480 // 481 // Copy the contents of the Option ROM to the memory buffer 482 // 483 IoDev->Mem.Read (IoDev, EfiPciWidthUint32, RomBar, RomBarSize / sizeof(UINT32), (VOID *)(UINTN)RomBuffer); 484 485 Status = gBS->AllocatePool( 486 EfiBootServicesData, 487 ((UINT32)mPciOptionRomTable.PciOptionRomCount + 1) * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR), 488 (VOID*)&TempPciOptionRomDescriptors 489 ); 490 if (mPciOptionRomTable.PciOptionRomCount > 0) { 491 CopyMem( 492 TempPciOptionRomDescriptors, 493 mPciOptionRomTable.PciOptionRomDescriptors, 494 (UINT32)mPciOptionRomTable.PciOptionRomCount * sizeof(EFI_PCI_OPTION_ROM_DESCRIPTOR) 495 ); 496 497 gBS->FreePool(mPciOptionRomTable.PciOptionRomDescriptors); 498 } 499 500 mPciOptionRomTable.PciOptionRomDescriptors = TempPciOptionRomDescriptors; 501 502 TempPciOptionRomDescriptors = &(mPciOptionRomTable.PciOptionRomDescriptors[(UINT32)mPciOptionRomTable.PciOptionRomCount]); 503 504 TempPciOptionRomDescriptors->RomAddress = RomBuffer; 505 TempPciOptionRomDescriptors->MemoryType = EfiBootServicesData; 506 TempPciOptionRomDescriptors->RomLength = RomBarSize; 507 TempPciOptionRomDescriptors->Seg = (UINT32)IoDev->SegmentNumber; 508 TempPciOptionRomDescriptors->Bus = (UINT8)Bus; 509 TempPciOptionRomDescriptors->Dev = (UINT8)Device; 510 TempPciOptionRomDescriptors->Func = (UINT8)Func; 511 TempPciOptionRomDescriptors->ExecutedLegacyBiosImage = TRUE; 512 TempPciOptionRomDescriptors->DontLoadEfiRom = FALSE; 513 514 mPciOptionRomTable.PciOptionRomCount++; 515 } 516 } 517 518 // 519 // Disable the Memory decode for the PCI-PCI Bridge 520 // 521 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); 522 Register &= (~0x02); 523 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address + 4, 1, &Register); 524 } 525 } 526 } 527 528 // 529 // Restore the PCI Configuration Header 530 // 531 IoDev->Pci.Write (IoDev, EfiPciWidthUint32, Address, sizeof(PciHeader)/sizeof(UINT32), &PciHeader); 532 } 533 534 VOID 535 SaveCommandRegister ( 536 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, 537 UINT16 MinBus, 538 UINT16 MaxBus, 539 UINT16 MinDevice, 540 UINT16 MaxDevice, 541 UINT16 MinFunc, 542 UINT16 MaxFunc, 543 UINT16 Bus, 544 UINT16 Device, 545 UINT16 Func, 546 IN VOID *VoidContext 547 ) 548 549 { 550 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; 551 UINT64 Address; 552 UINTN Index; 553 UINT16 Command; 554 555 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; 556 557 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); 558 559 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; 560 561 IoDev->Pci.Read (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); 562 563 // 564 // Clear the memory enable bit 565 // 566 Command = (UINT16) (Context->CommandRegisterBuffer[Index] & (~0x02)); 567 568 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Command); 569 } 570 571 VOID 572 RestoreCommandRegister ( 573 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev, 574 UINT16 MinBus, 575 UINT16 MaxBus, 576 UINT16 MinDevice, 577 UINT16 MaxDevice, 578 UINT16 MinFunc, 579 UINT16 MaxFunc, 580 UINT16 Bus, 581 UINT16 Device, 582 UINT16 Func, 583 IN VOID *VoidContext 584 ) 585 586 { 587 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *Context; 588 UINT64 Address; 589 UINTN Index; 590 591 Context = (PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT *)VoidContext; 592 593 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 4); 594 595 Index = (Bus - MinBus) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1) + Device * (PCI_MAX_FUNC+1) + Func; 596 597 IoDev->Pci.Write (IoDev, EfiPciWidthUint16, Address, 1, &Context->CommandRegisterBuffer[Index]); 598 } 599 600 EFI_STATUS 601 ScanPciRootBridgeForRoms( 602 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *IoDev 603 ) 604 605 { 606 EFI_STATUS Status; 607 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; 608 UINT16 MinBus; 609 UINT16 MaxBus; 610 UINT64 RootWindowBase; 611 UINT64 RootWindowLimit; 612 PCAT_PCI_ROOT_BRIDGE_SCAN_FOR_ROM_CONTEXT Context; 613 614 if (mPciOptionRomTableInstalled == FALSE) { 615 gBS->InstallConfigurationTable(&gEfiPciOptionRomTableGuid, &mPciOptionRomTable); 616 mPciOptionRomTableInstalled = TRUE; 617 } 618 619 Status = IoDev->Configuration(IoDev, (VOID **)&Descriptors); 620 if (EFI_ERROR (Status) || Descriptors == NULL) { 621 return EFI_NOT_FOUND; 622 } 623 624 MinBus = 0xffff; 625 MaxBus = 0xffff; 626 RootWindowBase = 0; 627 RootWindowLimit = 0; 628 while (Descriptors->Desc != ACPI_END_TAG_DESCRIPTOR) { 629 // 630 // Find bus range 631 // 632 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { 633 MinBus = (UINT16)Descriptors->AddrRangeMin; 634 MaxBus = (UINT16)Descriptors->AddrRangeMax; 635 } 636 // 637 // Find memory descriptors that are not prefetchable 638 // 639 if (Descriptors->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM && Descriptors->SpecificFlag == 0) { 640 // 641 // Find Memory Descriptors that are less than 4GB, so the PPB Memory Window can be used for downstream devices 642 // 643 if (Descriptors->AddrRangeMax < 0x100000000ULL) { 644 // 645 // Find the largest Non-Prefetchable Memory Descriptor that is less than 4GB 646 // 647 if ((Descriptors->AddrRangeMax - Descriptors->AddrRangeMin) > (RootWindowLimit - RootWindowBase)) { 648 RootWindowBase = Descriptors->AddrRangeMin; 649 RootWindowLimit = Descriptors->AddrRangeMax; 650 } 651 } 652 } 653 Descriptors ++; 654 } 655 656 // 657 // Make sure a bus range was found 658 // 659 if (MinBus == 0xffff || MaxBus == 0xffff) { 660 return EFI_NOT_FOUND; 661 } 662 663 // 664 // Make sure a non-prefetchable memory region was found 665 // 666 if (RootWindowBase == 0 && RootWindowLimit == 0) { 667 return EFI_NOT_FOUND; 668 } 669 670 // 671 // Round the Base and Limit values to 1 MB boudaries 672 // 673 RootWindowBase = ((RootWindowBase - 1) & 0xfff00000) + 0x00100000; 674 RootWindowLimit = ((RootWindowLimit + 1) & 0xfff00000) - 1; 675 676 // 677 // Make sure that the size of the rounded window is greater than zero 678 // 679 if (RootWindowLimit <= RootWindowBase) { 680 return EFI_NOT_FOUND; 681 } 682 683 // 684 // Allocate buffer to save the Command register from all the PCI devices 685 // 686 Context.CommandRegisterBuffer = NULL; 687 Status = gBS->AllocatePool( 688 EfiBootServicesData, 689 sizeof(UINT16) * (MaxBus - MinBus + 1) * (PCI_MAX_DEVICE+1) * (PCI_MAX_FUNC+1), 690 (VOID **)&Context.CommandRegisterBuffer 691 ); 692 693 if (EFI_ERROR (Status)) { 694 return Status; 695 } 696 697 Context.PpbMemoryWindow = (((UINT32)RootWindowBase) >> 16) | ((UINT32)RootWindowLimit & 0xffff0000); 698 699 // 700 // Save the Command register from all the PCI devices, and disable the I/O, Mem, and BusMaster bits 701 // 702 ScanPciBus( 703 IoDev, 704 MinBus, MaxBus, 705 0, PCI_MAX_DEVICE, 706 0, PCI_MAX_FUNC, 707 SaveCommandRegister, &Context 708 ); 709 710 // 711 // Recursively scan all the busses for PCI Option ROMs 712 // 713 ScanPciBus( 714 IoDev, 715 MinBus, MinBus, 716 0, PCI_MAX_DEVICE, 717 0, PCI_MAX_FUNC, 718 CheckForRom, &Context 719 ); 720 721 // 722 // Restore the Command register in all the PCI devices 723 // 724 ScanPciBus( 725 IoDev, 726 MinBus, MaxBus, 727 0, PCI_MAX_DEVICE, 728 0, PCI_MAX_FUNC, 729 RestoreCommandRegister, &Context 730 ); 731 732 // 733 // Free the buffer used to save all the Command register values 734 // 735 gBS->FreePool(Context.CommandRegisterBuffer); 736 737 return EFI_SUCCESS; 738 } 739