1/*++ 2 3Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR> 4This program and the accompanying materials 5are licensed and made available under the terms and conditions of the BSD License 6which accompanies this distribution. The full text of the license may be found at 7http://opensource.org/licenses/bsd-license.php 8 9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12Module Name: 13 PcatPciRootBridgeIo.c 14 15Abstract: 16 17 EFI PC AT PCI Root Bridge Io Protocol 18 19Revision History 20 21--*/ 22 23#include "PcatPciRootBridge.h" 24 25BOOLEAN mPciOptionRomTableInstalled = FALSE; 26EFI_PCI_OPTION_ROM_TABLE mPciOptionRomTable = {0, NULL}; 27 28EFI_STATUS 29EFIAPI 30PcatRootBridgeIoIoRead ( 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 47EFI_STATUS 48EFIAPI 49PcatRootBridgeIoIoWrite ( 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 67EFI_STATUS 68PcatRootBridgeIoGetIoPortMapping ( 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 84EFI_STATUS 85PcatRootBridgeIoPciRW ( 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 213VOID 214ScanPciBus( 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 301VOID 302CheckForRom ( 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 534VOID 535SaveCommandRegister ( 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 571VOID 572RestoreCommandRegister ( 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 600EFI_STATUS 601ScanPciRootBridgeForRoms( 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