1 /** @file 2 PCI Rom supporting funtions implementation for PCI Bus module. 3 4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include "PciBus.h" 16 17 /** 18 Load the EFI Image from Option ROM 19 20 @param PciIoDevice PCI IO device instance. 21 @param FilePath The file path of the EFI Image 22 @param BufferSize On input the size of Buffer in bytes. On output with a return 23 code of EFI_SUCCESS, the amount of data transferred to Buffer. 24 On output with a return code of EFI_BUFFER_TOO_SMALL, 25 the size of Buffer required to retrieve the requested file. 26 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL, 27 then no the size of the requested file is returned in BufferSize. 28 29 @retval EFI_SUCCESS The file was loaded. 30 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or 31 BufferSize is NULL. 32 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device. 33 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image. 34 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. 35 BufferSize has been updated with the size needed to complete the request. 36 **/ 37 EFI_STATUS 38 LocalLoadFile2 ( 39 IN PCI_IO_DEVICE *PciIoDevice, 40 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 41 IN OUT UINTN *BufferSize, 42 IN VOID *Buffer OPTIONAL 43 ) 44 { 45 EFI_STATUS Status; 46 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *EfiOpRomImageNode; 47 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; 48 PCI_DATA_STRUCTURE *Pcir; 49 UINT32 ImageSize; 50 UINT8 *ImageBuffer; 51 UINT32 ImageLength; 52 UINT32 DestinationSize; 53 UINT32 ScratchSize; 54 VOID *Scratch; 55 EFI_DECOMPRESS_PROTOCOL *Decompress; 56 UINT32 InitializationSize; 57 58 EfiOpRomImageNode = (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH *) FilePath; 59 if ((EfiOpRomImageNode == NULL) || 60 (DevicePathType (FilePath) != MEDIA_DEVICE_PATH) || 61 (DevicePathSubType (FilePath) != MEDIA_RELATIVE_OFFSET_RANGE_DP) || 62 (DevicePathNodeLength (FilePath) != sizeof (MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH)) || 63 (!IsDevicePathEnd (NextDevicePathNode (FilePath))) || 64 (EfiOpRomImageNode->StartingOffset > EfiOpRomImageNode->EndingOffset) || 65 (EfiOpRomImageNode->EndingOffset >= PciIoDevice->RomSize) || 66 (BufferSize == NULL) 67 ) { 68 return EFI_INVALID_PARAMETER; 69 } 70 71 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) ( 72 (UINT8 *) PciIoDevice->PciIo.RomImage + EfiOpRomImageNode->StartingOffset 73 ); 74 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { 75 return EFI_NOT_FOUND; 76 } 77 78 79 Pcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) EfiRomHeader + EfiRomHeader->PcirOffset); 80 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE); 81 82 if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) && 83 (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) && 84 ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) || 85 (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) && 86 (EfiRomHeader->CompressionType <= EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) 87 ) { 88 89 ImageSize = Pcir->ImageLength * 512; 90 InitializationSize = (UINT32) EfiRomHeader->InitializationSize * 512; 91 if (InitializationSize > ImageSize || EfiRomHeader->EfiImageHeaderOffset >= InitializationSize) { 92 return EFI_NOT_FOUND; 93 } 94 95 ImageBuffer = (UINT8 *) EfiRomHeader + EfiRomHeader->EfiImageHeaderOffset; 96 ImageLength = InitializationSize - EfiRomHeader->EfiImageHeaderOffset; 97 98 if (EfiRomHeader->CompressionType != EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { 99 // 100 // Uncompressed: Copy the EFI Image directly to user's buffer 101 // 102 if (Buffer == NULL || *BufferSize < ImageLength) { 103 *BufferSize = ImageLength; 104 return EFI_BUFFER_TOO_SMALL; 105 } 106 107 *BufferSize = ImageLength; 108 CopyMem (Buffer, ImageBuffer, ImageLength); 109 return EFI_SUCCESS; 110 111 } else { 112 // 113 // Compressed: Uncompress before copying 114 // 115 Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress); 116 if (EFI_ERROR (Status)) { 117 return EFI_DEVICE_ERROR; 118 } 119 Status = Decompress->GetInfo ( 120 Decompress, 121 ImageBuffer, 122 ImageLength, 123 &DestinationSize, 124 &ScratchSize 125 ); 126 if (EFI_ERROR (Status)) { 127 return EFI_DEVICE_ERROR; 128 } 129 130 if (Buffer == NULL || *BufferSize < DestinationSize) { 131 *BufferSize = DestinationSize; 132 return EFI_BUFFER_TOO_SMALL; 133 } 134 135 *BufferSize = DestinationSize; 136 Scratch = AllocatePool (ScratchSize); 137 if (Scratch == NULL) { 138 return EFI_DEVICE_ERROR; 139 } 140 141 Status = Decompress->Decompress ( 142 Decompress, 143 ImageBuffer, 144 ImageLength, 145 Buffer, 146 DestinationSize, 147 Scratch, 148 ScratchSize 149 ); 150 FreePool (Scratch); 151 152 if (EFI_ERROR (Status)) { 153 return EFI_DEVICE_ERROR; 154 } 155 return EFI_SUCCESS; 156 } 157 } 158 159 return EFI_NOT_FOUND; 160 } 161 162 /** 163 Initialize a PCI LoadFile2 instance. 164 165 @param PciIoDevice PCI IO Device. 166 167 **/ 168 VOID 169 InitializePciLoadFile2 ( 170 IN PCI_IO_DEVICE *PciIoDevice 171 ) 172 { 173 PciIoDevice->LoadFile2.LoadFile = LoadFile2; 174 } 175 176 /** 177 Causes the driver to load a specified file. 178 179 @param This Indicates a pointer to the calling context. 180 @param FilePath The device specific path of the file to load. 181 @param BootPolicy Should always be FALSE. 182 @param BufferSize On input the size of Buffer in bytes. On output with a return 183 code of EFI_SUCCESS, the amount of data transferred to Buffer. 184 On output with a return code of EFI_BUFFER_TOO_SMALL, 185 the size of Buffer required to retrieve the requested file. 186 @param Buffer The memory buffer to transfer the file to. If Buffer is NULL, 187 then no the size of the requested file is returned in BufferSize. 188 189 @retval EFI_SUCCESS The file was loaded. 190 @retval EFI_UNSUPPORTED BootPolicy is TRUE. 191 @retval EFI_INVALID_PARAMETER FilePath is not a valid device path, or 192 BufferSize is NULL. 193 @retval EFI_NOT_FOUND Not found PCI Option Rom on PCI device. 194 @retval EFI_DEVICE_ERROR Failed to decompress PCI Option Rom image. 195 @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. 196 BufferSize has been updated with the size needed to complete the request. 197 198 **/ 199 EFI_STATUS 200 EFIAPI 201 LoadFile2 ( 202 IN EFI_LOAD_FILE2_PROTOCOL *This, 203 IN EFI_DEVICE_PATH_PROTOCOL *FilePath, 204 IN BOOLEAN BootPolicy, 205 IN OUT UINTN *BufferSize, 206 IN VOID *Buffer OPTIONAL 207 ) 208 { 209 PCI_IO_DEVICE *PciIoDevice; 210 211 if (BootPolicy) { 212 return EFI_UNSUPPORTED; 213 } 214 PciIoDevice = PCI_IO_DEVICE_FROM_LOAD_FILE2_THIS (This); 215 216 return LocalLoadFile2 ( 217 PciIoDevice, 218 FilePath, 219 BufferSize, 220 Buffer 221 ); 222 } 223 224 /** 225 Get Pci device's oprom information. 226 227 @param PciIoDevice Input Pci device instance. 228 Output Pci device instance with updated OptionRom size. 229 230 @retval EFI_NOT_FOUND Pci device has not Option Rom. 231 @retval EFI_SUCCESS Pci device has Option Rom. 232 233 **/ 234 EFI_STATUS 235 GetOpRomInfo ( 236 IN OUT PCI_IO_DEVICE *PciIoDevice 237 ) 238 { 239 UINT8 RomBarIndex; 240 UINT32 AllOnes; 241 UINT64 Address; 242 EFI_STATUS Status; 243 UINT8 Bus; 244 UINT8 Device; 245 UINT8 Function; 246 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 247 248 Bus = PciIoDevice->BusNumber; 249 Device = PciIoDevice->DeviceNumber; 250 Function = PciIoDevice->FunctionNumber; 251 252 PciRootBridgeIo = PciIoDevice->PciRootBridgeIo; 253 254 // 255 // Offset is 0x30 if is not ppb 256 // 257 258 // 259 // 0x30 260 // 261 RomBarIndex = PCI_EXPANSION_ROM_BASE; 262 263 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { 264 // 265 // If is ppb, 0x38 266 // 267 RomBarIndex = PCI_BRIDGE_ROMBAR; 268 } 269 // 270 // The bit0 is 0 to prevent the enabling of the Rom address decoder 271 // 272 AllOnes = 0xfffffffe; 273 Address = EFI_PCI_ADDRESS (Bus, Device, Function, RomBarIndex); 274 275 Status = PciRootBridgeIo->Pci.Write ( 276 PciRootBridgeIo, 277 EfiPciWidthUint32, 278 Address, 279 1, 280 &AllOnes 281 ); 282 if (EFI_ERROR (Status)) { 283 return EFI_NOT_FOUND; 284 } 285 286 // 287 // Read back 288 // 289 Status = PciRootBridgeIo->Pci.Read( 290 PciRootBridgeIo, 291 EfiPciWidthUint32, 292 Address, 293 1, 294 &AllOnes 295 ); 296 if (EFI_ERROR (Status)) { 297 return EFI_NOT_FOUND; 298 } 299 300 // 301 // Bits [1, 10] are reserved 302 // 303 AllOnes &= 0xFFFFF800; 304 if ((AllOnes == 0) || (AllOnes == 0xFFFFF800)) { 305 return EFI_NOT_FOUND; 306 } 307 308 PciIoDevice->RomSize = (UINT64) ((~AllOnes) + 1); 309 return EFI_SUCCESS; 310 } 311 312 /** 313 Check if the RomImage contains EFI Images. 314 315 @param RomImage The ROM address of Image for check. 316 @param RomSize Size of ROM for check. 317 318 @retval TRUE ROM contain EFI Image. 319 @retval FALSE ROM not contain EFI Image. 320 321 **/ 322 BOOLEAN 323 ContainEfiImage ( 324 IN VOID *RomImage, 325 IN UINT64 RomSize 326 ) 327 { 328 PCI_EXPANSION_ROM_HEADER *RomHeader; 329 PCI_DATA_STRUCTURE *RomPcir; 330 UINT8 Indicator; 331 332 Indicator = 0; 333 RomHeader = RomImage; 334 if (RomHeader == NULL) { 335 return FALSE; 336 } 337 338 do { 339 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { 340 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + 512); 341 continue; 342 } 343 344 // 345 // The PCI Data Structure must be DWORD aligned. 346 // 347 if (RomHeader->PcirOffset == 0 || 348 (RomHeader->PcirOffset & 3) != 0 || 349 (UINT8 *) RomHeader + RomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > (UINT8 *) RomImage + RomSize) { 350 break; 351 } 352 353 RomPcir = (PCI_DATA_STRUCTURE *) ((UINT8 *) RomHeader + RomHeader->PcirOffset); 354 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { 355 break; 356 } 357 358 if (RomPcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) { 359 return TRUE; 360 } 361 362 Indicator = RomPcir->Indicator; 363 RomHeader = (PCI_EXPANSION_ROM_HEADER *) ((UINT8 *) RomHeader + RomPcir->ImageLength * 512); 364 } while (((UINT8 *) RomHeader < (UINT8 *) RomImage + RomSize) && ((Indicator & 0x80) == 0x00)); 365 366 return FALSE; 367 } 368 369 /** 370 Load Option Rom image for specified PCI device. 371 372 @param PciDevice Pci device instance. 373 @param RomBase Base address of Option Rom. 374 375 @retval EFI_OUT_OF_RESOURCES No enough memory to hold image. 376 @retval EFI_SUCESS Successfully loaded Option Rom. 377 378 **/ 379 EFI_STATUS 380 LoadOpRomImage ( 381 IN PCI_IO_DEVICE *PciDevice, 382 IN UINT64 RomBase 383 ) 384 { 385 UINT8 RomBarIndex; 386 UINT8 Indicator; 387 UINT16 OffsetPcir; 388 UINT32 RomBarOffset; 389 UINT32 RomBar; 390 EFI_STATUS RetStatus; 391 BOOLEAN FirstCheck; 392 UINT8 *Image; 393 PCI_EXPANSION_ROM_HEADER *RomHeader; 394 PCI_DATA_STRUCTURE *RomPcir; 395 UINT64 RomSize; 396 UINT64 RomImageSize; 397 UINT32 LegacyImageLength; 398 UINT8 *RomInMemory; 399 UINT8 CodeType; 400 401 RomSize = PciDevice->RomSize; 402 403 Indicator = 0; 404 RomImageSize = 0; 405 RomInMemory = NULL; 406 CodeType = 0xFF; 407 408 // 409 // Get the RomBarIndex 410 // 411 412 // 413 // 0x30 414 // 415 RomBarIndex = PCI_EXPANSION_ROM_BASE; 416 if (IS_PCI_BRIDGE (&(PciDevice->Pci))) { 417 // 418 // if is ppb 419 // 420 421 // 422 // 0x38 423 // 424 RomBarIndex = PCI_BRIDGE_ROMBAR; 425 } 426 // 427 // Allocate memory for Rom header and PCIR 428 // 429 RomHeader = AllocatePool (sizeof (PCI_EXPANSION_ROM_HEADER)); 430 if (RomHeader == NULL) { 431 return EFI_OUT_OF_RESOURCES; 432 } 433 434 RomPcir = AllocatePool (sizeof (PCI_DATA_STRUCTURE)); 435 if (RomPcir == NULL) { 436 FreePool (RomHeader); 437 return EFI_OUT_OF_RESOURCES; 438 } 439 440 RomBar = (UINT32) RomBase; 441 442 // 443 // Enable RomBar 444 // 445 RomDecode (PciDevice, RomBarIndex, RomBar, TRUE); 446 447 RomBarOffset = RomBar; 448 RetStatus = EFI_NOT_FOUND; 449 FirstCheck = TRUE; 450 LegacyImageLength = 0; 451 452 do { 453 PciDevice->PciRootBridgeIo->Mem.Read ( 454 PciDevice->PciRootBridgeIo, 455 EfiPciWidthUint8, 456 RomBarOffset, 457 sizeof (PCI_EXPANSION_ROM_HEADER), 458 (UINT8 *) RomHeader 459 ); 460 461 if (RomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { 462 RomBarOffset = RomBarOffset + 512; 463 if (FirstCheck) { 464 break; 465 } else { 466 RomImageSize = RomImageSize + 512; 467 continue; 468 } 469 } 470 471 FirstCheck = FALSE; 472 OffsetPcir = RomHeader->PcirOffset; 473 // 474 // If the pointer to the PCI Data Structure is invalid, no further images can be located. 475 // The PCI Data Structure must be DWORD aligned. 476 // 477 if (OffsetPcir == 0 || 478 (OffsetPcir & 3) != 0 || 479 RomImageSize + OffsetPcir + sizeof (PCI_DATA_STRUCTURE) > RomSize) { 480 break; 481 } 482 PciDevice->PciRootBridgeIo->Mem.Read ( 483 PciDevice->PciRootBridgeIo, 484 EfiPciWidthUint8, 485 RomBarOffset + OffsetPcir, 486 sizeof (PCI_DATA_STRUCTURE), 487 (UINT8 *) RomPcir 488 ); 489 // 490 // If a valid signature is not present in the PCI Data Structure, no further images can be located. 491 // 492 if (RomPcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { 493 break; 494 } 495 if (RomImageSize + RomPcir->ImageLength * 512 > RomSize) { 496 break; 497 } 498 if (RomPcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { 499 CodeType = PCI_CODE_TYPE_PCAT_IMAGE; 500 LegacyImageLength = ((UINT32)((EFI_LEGACY_EXPANSION_ROM_HEADER *)RomHeader)->Size512) * 512; 501 } 502 Indicator = RomPcir->Indicator; 503 RomImageSize = RomImageSize + RomPcir->ImageLength * 512; 504 RomBarOffset = RomBarOffset + RomPcir->ImageLength * 512; 505 } while (((Indicator & 0x80) == 0x00) && ((RomBarOffset - RomBar) < RomSize)); 506 507 // 508 // Some Legacy Cards do not report the correct ImageLength so used the maximum 509 // of the legacy length and the PCIR Image Length 510 // 511 if (CodeType == PCI_CODE_TYPE_PCAT_IMAGE) { 512 RomImageSize = MAX (RomImageSize, LegacyImageLength); 513 } 514 515 if (RomImageSize > 0) { 516 RetStatus = EFI_SUCCESS; 517 Image = AllocatePool ((UINT32) RomImageSize); 518 if (Image == NULL) { 519 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); 520 FreePool (RomHeader); 521 FreePool (RomPcir); 522 return EFI_OUT_OF_RESOURCES; 523 } 524 525 // 526 // Copy Rom image into memory 527 // 528 PciDevice->PciRootBridgeIo->Mem.Read ( 529 PciDevice->PciRootBridgeIo, 530 EfiPciWidthUint8, 531 RomBar, 532 (UINT32) RomImageSize, 533 Image 534 ); 535 RomInMemory = Image; 536 } 537 538 RomDecode (PciDevice, RomBarIndex, RomBar, FALSE); 539 540 PciDevice->EmbeddedRom = TRUE; 541 PciDevice->PciIo.RomSize = RomImageSize; 542 PciDevice->PciIo.RomImage = RomInMemory; 543 544 // 545 // For OpROM read from PCI device: 546 // Add the Rom Image to internal database for later PCI light enumeration 547 // 548 PciRomAddImageMapping ( 549 NULL, 550 PciDevice->PciRootBridgeIo->SegmentNumber, 551 PciDevice->BusNumber, 552 PciDevice->DeviceNumber, 553 PciDevice->FunctionNumber, 554 (UINT64) (UINTN) PciDevice->PciIo.RomImage, 555 PciDevice->PciIo.RomSize 556 ); 557 558 // 559 // Free allocated memory 560 // 561 FreePool (RomHeader); 562 FreePool (RomPcir); 563 564 return RetStatus; 565 } 566 567 /** 568 Enable/Disable Option Rom decode. 569 570 @param PciDevice Pci device instance. 571 @param RomBarIndex The BAR index of the standard PCI Configuration header to use as the 572 base address for resource range. The legal range for this field is 0..5. 573 @param RomBar Base address of Option Rom. 574 @param Enable Flag for enable/disable decode. 575 576 **/ 577 VOID 578 RomDecode ( 579 IN PCI_IO_DEVICE *PciDevice, 580 IN UINT8 RomBarIndex, 581 IN UINT32 RomBar, 582 IN BOOLEAN Enable 583 ) 584 { 585 UINT32 Value32; 586 UINT32 Offset; 587 UINT32 OffsetMax; 588 EFI_PCI_IO_PROTOCOL *PciIo; 589 590 PciIo = &PciDevice->PciIo; 591 if (Enable) { 592 // 593 // Clear all bars 594 // 595 OffsetMax = 0x24; 596 if (IS_PCI_BRIDGE(&PciDevice->Pci)) { 597 OffsetMax = 0x14; 598 } 599 600 for (Offset = 0x10; Offset <= OffsetMax; Offset += sizeof (UINT32)) { 601 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllZero); 602 } 603 604 // 605 // set the Rom base address: now is hardcode 606 // enable its decoder 607 // 608 Value32 = RomBar | 0x1; 609 PciIo->Pci.Write ( 610 PciIo, 611 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32, 612 RomBarIndex, 613 1, 614 &Value32 615 ); 616 617 // 618 // Programe all upstream bridge 619 // 620 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, TRUE); 621 622 // 623 // Setting the memory space bit in the function's command register 624 // 625 PCI_ENABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE); 626 627 } else { 628 629 // 630 // disable command register decode to memory 631 // 632 PCI_DISABLE_COMMAND_REGISTER(PciDevice, EFI_PCI_COMMAND_MEMORY_SPACE); 633 634 // 635 // Destroy the programmed bar in all the upstream bridge. 636 // 637 ProgrameUpstreamBridgeForRom(PciDevice, RomBar, FALSE); 638 639 // 640 // disable rom decode 641 // 642 Value32 = 0xFFFFFFFE; 643 PciIo->Pci.Write ( 644 PciIo, 645 (EFI_PCI_IO_PROTOCOL_WIDTH) EfiPciWidthUint32, 646 RomBarIndex, 647 1, 648 &Value32 649 ); 650 651 } 652 } 653 654 /** 655 Load and start the Option Rom image. 656 657 @param PciDevice Pci device instance. 658 659 @retval EFI_SUCCESS Successfully loaded and started PCI Option Rom image. 660 @retval EFI_NOT_FOUND Failed to process PCI Option Rom image. 661 662 **/ 663 EFI_STATUS 664 ProcessOpRomImage ( 665 IN PCI_IO_DEVICE *PciDevice 666 ) 667 { 668 UINT8 Indicator; 669 UINT32 ImageSize; 670 VOID *RomBar; 671 UINT8 *RomBarOffset; 672 EFI_HANDLE ImageHandle; 673 EFI_STATUS Status; 674 EFI_STATUS RetStatus; 675 EFI_PCI_EXPANSION_ROM_HEADER *EfiRomHeader; 676 PCI_DATA_STRUCTURE *Pcir; 677 EFI_DEVICE_PATH_PROTOCOL *PciOptionRomImageDevicePath; 678 MEDIA_RELATIVE_OFFSET_RANGE_DEVICE_PATH EfiOpRomImageNode; 679 VOID *Buffer; 680 UINTN BufferSize; 681 682 Indicator = 0; 683 684 // 685 // Get the Address of the Option Rom image 686 // 687 RomBar = PciDevice->PciIo.RomImage; 688 RomBarOffset = (UINT8 *) RomBar; 689 RetStatus = EFI_NOT_FOUND; 690 691 if (RomBar == NULL) { 692 return RetStatus; 693 } 694 ASSERT (((EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset)->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE); 695 696 do { 697 EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) RomBarOffset; 698 if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { 699 RomBarOffset += 512; 700 continue; 701 } 702 703 Pcir = (PCI_DATA_STRUCTURE *) (RomBarOffset + EfiRomHeader->PcirOffset); 704 ASSERT (Pcir->Signature == PCI_DATA_STRUCTURE_SIGNATURE); 705 ImageSize = (UINT32) (Pcir->ImageLength * 512); 706 Indicator = Pcir->Indicator; 707 708 // 709 // Skip the image if it is not an EFI PCI Option ROM image 710 // 711 if (Pcir->CodeType != PCI_CODE_TYPE_EFI_IMAGE) { 712 goto NextImage; 713 } 714 715 // 716 // Skip the EFI PCI Option ROM image if its machine type is not supported 717 // 718 if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (EfiRomHeader->EfiMachineType)) { 719 goto NextImage; 720 } 721 722 // 723 // Ignore the EFI PCI Option ROM image if it is an EFI application 724 // 725 if (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { 726 goto NextImage; 727 } 728 729 // 730 // Create Pci Option Rom Image device path header 731 // 732 EfiOpRomImageNode.Header.Type = MEDIA_DEVICE_PATH; 733 EfiOpRomImageNode.Header.SubType = MEDIA_RELATIVE_OFFSET_RANGE_DP; 734 SetDevicePathNodeLength (&EfiOpRomImageNode.Header, sizeof (EfiOpRomImageNode)); 735 EfiOpRomImageNode.StartingOffset = (UINTN) RomBarOffset - (UINTN) RomBar; 736 EfiOpRomImageNode.EndingOffset = (UINTN) RomBarOffset + ImageSize - 1 - (UINTN) RomBar; 737 738 PciOptionRomImageDevicePath = AppendDevicePathNode (PciDevice->DevicePath, &EfiOpRomImageNode.Header); 739 ASSERT (PciOptionRomImageDevicePath != NULL); 740 741 // 742 // load image and start image 743 // 744 BufferSize = 0; 745 Buffer = NULL; 746 ImageHandle = NULL; 747 748 Status = gBS->LoadImage ( 749 FALSE, 750 gPciBusDriverBinding.DriverBindingHandle, 751 PciOptionRomImageDevicePath, 752 Buffer, 753 BufferSize, 754 &ImageHandle 755 ); 756 757 FreePool (PciOptionRomImageDevicePath); 758 759 if (!EFI_ERROR (Status)) { 760 Status = gBS->StartImage (ImageHandle, NULL, NULL); 761 if (!EFI_ERROR (Status)) { 762 AddDriver (PciDevice, ImageHandle); 763 PciRomAddImageMapping ( 764 ImageHandle, 765 PciDevice->PciRootBridgeIo->SegmentNumber, 766 PciDevice->BusNumber, 767 PciDevice->DeviceNumber, 768 PciDevice->FunctionNumber, 769 (UINT64) (UINTN) PciDevice->PciIo.RomImage, 770 PciDevice->PciIo.RomSize 771 ); 772 RetStatus = EFI_SUCCESS; 773 } 774 } 775 776 NextImage: 777 RomBarOffset += ImageSize; 778 779 } while (((Indicator & 0x80) == 0x00) && ((UINTN) (RomBarOffset - (UINT8 *) RomBar) < PciDevice->RomSize)); 780 781 return RetStatus; 782 } 783 784