Home | History | Annotate | Download | only in PciBusDxe
      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