Home | History | Annotate | Download | only in PciBusNoEnumerationDxe
      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 
     14   PciRomTable.c
     15 
     16 Abstract:
     17 
     18   Option Rom Support for PCI Bus Driver
     19 
     20 Revision History
     21 
     22 --*/
     23 
     24 #include "PciBus.h"
     25 
     26 typedef struct {
     27   EFI_HANDLE  ImageHandle;
     28   UINTN       Seg;
     29   UINT8       Bus;
     30   UINT8       Dev;
     31   UINT8       Func;
     32 } EFI_PCI_ROM_IMAGE_MAPPING;
     33 
     34 UINTN                      mNumberOfPciRomImages     = 0;
     35 UINTN                      mMaxNumberOfPciRomImages  = 0;
     36 EFI_PCI_ROM_IMAGE_MAPPING  *mRomImageTable           = NULL;
     37 
     38 CHAR16 mHexDigit[17] = L"0123456789ABCDEF";
     39 
     40 VOID
     41 PciRomAddImageMapping (
     42   IN EFI_HANDLE  ImageHandle,
     43   IN UINTN       Seg,
     44   IN UINT8       Bus,
     45   IN UINT8       Dev,
     46   IN UINT8       Func
     47   )
     48 
     49 {
     50   EFI_PCI_ROM_IMAGE_MAPPING *TempMapping;
     51 
     52   if (mNumberOfPciRomImages >= mMaxNumberOfPciRomImages) {
     53 
     54     mMaxNumberOfPciRomImages += 0x20;
     55 
     56     TempMapping = NULL;
     57     TempMapping = AllocatePool (mMaxNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING));
     58     if (TempMapping == NULL) {
     59       return ;
     60     }
     61 
     62     CopyMem (TempMapping, mRomImageTable, mNumberOfPciRomImages * sizeof (EFI_PCI_ROM_IMAGE_MAPPING));
     63 
     64     if (mRomImageTable != NULL) {
     65       gBS->FreePool (mRomImageTable);
     66     }
     67 
     68     mRomImageTable = TempMapping;
     69   }
     70 
     71   mRomImageTable[mNumberOfPciRomImages].ImageHandle = ImageHandle;
     72   mRomImageTable[mNumberOfPciRomImages].Seg         = Seg;
     73   mRomImageTable[mNumberOfPciRomImages].Bus         = Bus;
     74   mRomImageTable[mNumberOfPciRomImages].Dev         = Dev;
     75   mRomImageTable[mNumberOfPciRomImages].Func        = Func;
     76   mNumberOfPciRomImages++;
     77 }
     78 
     79 VOID
     80 HexToString (
     81   CHAR16  *String,
     82   UINTN   Value,
     83   UINTN   Digits
     84   )
     85 
     86 {
     87   for (; Digits > 0; Digits--, String++) {
     88     *String = mHexDigit[((Value >> (4*(Digits-1))) & 0x0f)];
     89   }
     90 }
     91 
     92 EFI_STATUS
     93 PciRomLoadEfiDriversFromRomImage (
     94   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
     95   IN EFI_PCI_OPTION_ROM_DESCRIPTOR  *PciOptionRomDescriptor
     96   )
     97 /*++
     98 
     99 Routine Description:
    100   Command entry point.
    101 
    102 Arguments:
    103   ImageHandle     The image handle.
    104   SystemTable     The system table.
    105 
    106 Returns:
    107   EFI_SUCCESS             - The command completed successfully
    108   EFI_INVALID_PARAMETER   - Command usage error
    109   EFI_UNSUPPORTED         - Protocols unsupported
    110   EFI_OUT_OF_RESOURCES    - Out of memory
    111   Other value             - Unknown error
    112 
    113 --*/
    114 {
    115   VOID                          *RomBar;
    116   UINTN                         RomSize;
    117   CHAR16                        *FileName;
    118   EFI_PCI_EXPANSION_ROM_HEADER  *EfiRomHeader;
    119   PCI_DATA_STRUCTURE            *Pcir;
    120   UINTN                         ImageIndex;
    121   UINTN                         RomBarOffset;
    122   UINT32                        ImageSize;
    123   UINT16                        ImageOffset;
    124   EFI_HANDLE                    ImageHandle;
    125   EFI_STATUS                    Status;
    126   EFI_STATUS                    retStatus;
    127   EFI_DEVICE_PATH_PROTOCOL      *FilePath;
    128   BOOLEAN                       SkipImage;
    129   UINT32                        DestinationSize;
    130   UINT32                        ScratchSize;
    131   UINT8                         *Scratch;
    132   VOID                          *ImageBuffer;
    133   VOID                          *DecompressedImageBuffer;
    134   UINT32                        ImageLength;
    135   EFI_DECOMPRESS_PROTOCOL       *Decompress;
    136   UINT32                        InitializationSize;
    137 
    138   RomBar = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress;
    139   RomSize = (UINTN) PciOptionRomDescriptor->RomLength;
    140   FileName = L"PciRom Seg=00000000 Bus=00 Dev=00 Func=00 Image=0000";
    141 
    142   HexToString (&FileName[11], PciOptionRomDescriptor->Seg, 8);
    143   HexToString (&FileName[24], PciOptionRomDescriptor->Bus, 2);
    144   HexToString (&FileName[31], PciOptionRomDescriptor->Dev, 2);
    145   HexToString (&FileName[39], PciOptionRomDescriptor->Func, 2);
    146 
    147   ImageIndex    = 0;
    148   retStatus     = EFI_NOT_FOUND;
    149   RomBarOffset  = (UINTN) RomBar;
    150 
    151   do {
    152 
    153     EfiRomHeader = (EFI_PCI_EXPANSION_ROM_HEADER *) (UINTN) RomBarOffset;
    154 
    155 
    156     if (EfiRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
    157       return retStatus;
    158     }
    159 
    160     //
    161     // If the pointer to the PCI Data Structure is invalid, no further images can be located.
    162     // The PCI Data Structure must be DWORD aligned.
    163     //
    164     if (EfiRomHeader->PcirOffset == 0 ||
    165         (EfiRomHeader->PcirOffset & 3) != 0 ||
    166         RomBarOffset - (UINTN)RomBar + EfiRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > RomSize) {
    167       break;
    168     }
    169     Pcir      = (PCI_DATA_STRUCTURE *) (UINTN) (RomBarOffset + EfiRomHeader->PcirOffset);
    170     //
    171     // If a valid signature is not present in the PCI Data Structure, no further images can be located.
    172     //
    173     if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
    174       break;
    175     }
    176     ImageSize = Pcir->ImageLength * 512;
    177     if (RomBarOffset - (UINTN)RomBar + ImageSize > RomSize) {
    178       break;
    179     }
    180 
    181     if ((Pcir->CodeType == PCI_CODE_TYPE_EFI_IMAGE) &&
    182         (EfiRomHeader->EfiSignature == EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE) &&
    183         ((EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER) ||
    184          (EfiRomHeader->EfiSubsystem == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER))) {
    185 
    186       ImageOffset             = EfiRomHeader->EfiImageHeaderOffset;
    187       InitializationSize      = EfiRomHeader->InitializationSize * 512;
    188 
    189       if (InitializationSize <= ImageSize && ImageOffset < InitializationSize) {
    190 
    191         ImageBuffer             = (VOID *) (UINTN) (RomBarOffset + ImageOffset);
    192         ImageLength             = InitializationSize - ImageOffset;
    193         DecompressedImageBuffer = NULL;
    194 
    195         //
    196         // decompress here if needed
    197         //
    198         SkipImage = FALSE;
    199         if (EfiRomHeader->CompressionType > EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
    200           SkipImage = TRUE;
    201         }
    202 
    203         if (EfiRomHeader->CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) {
    204           Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **) &Decompress);
    205           if (EFI_ERROR (Status)) {
    206             SkipImage = TRUE;
    207           } else {
    208             SkipImage = TRUE;
    209             Status = Decompress->GetInfo (
    210                                   Decompress,
    211                                   ImageBuffer,
    212                                   ImageLength,
    213                                   &DestinationSize,
    214                                   &ScratchSize
    215                                   );
    216             if (!EFI_ERROR (Status)) {
    217               DecompressedImageBuffer = NULL;
    218               DecompressedImageBuffer = AllocatePool (DestinationSize);
    219               if (DecompressedImageBuffer != NULL) {
    220                 Scratch = AllocatePool (ScratchSize);
    221                 if (Scratch != NULL) {
    222                   Status = Decompress->Decompress (
    223                                         Decompress,
    224                                         ImageBuffer,
    225                                         ImageLength,
    226                                         DecompressedImageBuffer,
    227                                         DestinationSize,
    228                                         Scratch,
    229                                         ScratchSize
    230                                         );
    231                   if (!EFI_ERROR (Status)) {
    232                     ImageBuffer = DecompressedImageBuffer;
    233                     ImageLength = DestinationSize;
    234                     SkipImage   = FALSE;
    235                   }
    236 
    237                   gBS->FreePool (Scratch);
    238                 }
    239               }
    240             }
    241           }
    242         }
    243 
    244         if (!SkipImage) {
    245 
    246           //
    247           // load image and start image
    248           //
    249 
    250           HexToString (&FileName[48], ImageIndex, 4);
    251           FilePath = FileDevicePath (NULL, FileName);
    252 
    253           Status = gBS->LoadImage (
    254                           FALSE,
    255                           This->ImageHandle,
    256                           FilePath,
    257                           ImageBuffer,
    258                           ImageLength,
    259                           &ImageHandle
    260                           );
    261           if (!EFI_ERROR (Status)) {
    262             Status = gBS->StartImage (ImageHandle, NULL, NULL);
    263             if (!EFI_ERROR (Status)) {
    264               PciRomAddImageMapping (
    265                 ImageHandle,
    266                 PciOptionRomDescriptor->Seg,
    267                 PciOptionRomDescriptor->Bus,
    268                 PciOptionRomDescriptor->Dev,
    269                 PciOptionRomDescriptor->Func
    270                 );
    271               retStatus = Status;
    272             }
    273           }
    274           if (FilePath != NULL) {
    275             gBS->FreePool (FilePath);
    276           }
    277         }
    278 
    279         if (DecompressedImageBuffer != NULL) {
    280           gBS->FreePool (DecompressedImageBuffer);
    281         }
    282 
    283       }
    284     }
    285 
    286     RomBarOffset = RomBarOffset + ImageSize;
    287     ImageIndex++;
    288   } while (((Pcir->Indicator & 0x80) == 0x00) && ((RomBarOffset - (UINTN) RomBar) < RomSize));
    289 
    290   return retStatus;
    291 }
    292 
    293 EFI_STATUS
    294 PciRomLoadEfiDriversFromOptionRomTable (
    295   IN EFI_DRIVER_BINDING_PROTOCOL      *This,
    296   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo
    297   )
    298 /*++
    299 
    300 Routine Description:
    301 
    302 Arguments:
    303 
    304 Returns:
    305 
    306 --*/
    307 {
    308   EFI_STATUS                        Status;
    309   EFI_PCI_OPTION_ROM_TABLE          *PciOptionRomTable;
    310   EFI_PCI_OPTION_ROM_DESCRIPTOR     *PciOptionRomDescriptor;
    311   UINTN                             Index;
    312   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
    313   UINT16                            MinBus;
    314   UINT16                            MaxBus;
    315 
    316   Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable);
    317   if (EFI_ERROR (Status)) {
    318     return EFI_NOT_FOUND;
    319   }
    320 
    321   Status = EFI_NOT_FOUND;
    322 
    323   for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) {
    324     PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index];
    325     if (!PciOptionRomDescriptor->DontLoadEfiRom) {
    326       if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber) {
    327         Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
    328         if (EFI_ERROR (Status)) {
    329           return Status;
    330         }
    331 
    332         PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL);
    333         if ((MinBus <= PciOptionRomDescriptor->Bus) && (PciOptionRomDescriptor->Bus <= MaxBus)) {
    334           Status = PciRomLoadEfiDriversFromRomImage (This, PciOptionRomDescriptor);
    335           PciOptionRomDescriptor->DontLoadEfiRom |= 2;
    336         }
    337       }
    338     }
    339   }
    340 
    341   return Status;
    342 }
    343 
    344 EFI_STATUS
    345 PciRomGetRomResourceFromPciOptionRomTable (
    346   IN EFI_DRIVER_BINDING_PROTOCOL      *This,
    347   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,
    348   PCI_IO_DEVICE                       *PciIoDevice
    349   )
    350 /*++
    351 
    352 Routine Description:
    353 
    354 Arguments:
    355 
    356 Returns:
    357 
    358 --*/
    359 {
    360   EFI_STATUS                    Status;
    361   EFI_PCI_OPTION_ROM_TABLE      *PciOptionRomTable;
    362   EFI_PCI_OPTION_ROM_DESCRIPTOR *PciOptionRomDescriptor;
    363   UINTN                         Index;
    364 
    365   Status = EfiGetSystemConfigurationTable (&gEfiPciOptionRomTableGuid, (VOID **) &PciOptionRomTable);
    366   if (EFI_ERROR (Status)) {
    367     return EFI_NOT_FOUND;
    368   }
    369 
    370   for (Index = 0; Index < PciOptionRomTable->PciOptionRomCount; Index++) {
    371     PciOptionRomDescriptor = &PciOptionRomTable->PciOptionRomDescriptors[Index];
    372     if (PciOptionRomDescriptor->Seg == PciRootBridgeIo->SegmentNumber &&
    373         PciOptionRomDescriptor->Bus == PciIoDevice->BusNumber         &&
    374         PciOptionRomDescriptor->Dev == PciIoDevice->DeviceNumber      &&
    375         PciOptionRomDescriptor->Func == PciIoDevice->FunctionNumber ) {
    376 
    377       PciIoDevice->PciIo.RomImage = (VOID *) (UINTN) PciOptionRomDescriptor->RomAddress;
    378       PciIoDevice->PciIo.RomSize  = (UINTN) PciOptionRomDescriptor->RomLength;
    379     }
    380   }
    381 
    382   for (Index = 0; Index < mNumberOfPciRomImages; Index++) {
    383     if (mRomImageTable[Index].Seg  == PciRootBridgeIo->SegmentNumber &&
    384         mRomImageTable[Index].Bus  == PciIoDevice->BusNumber         &&
    385         mRomImageTable[Index].Dev  == PciIoDevice->DeviceNumber      &&
    386         mRomImageTable[Index].Func == PciIoDevice->FunctionNumber    ) {
    387 
    388       AddDriver (PciIoDevice, mRomImageTable[Index].ImageHandle);
    389     }
    390   }
    391 
    392   return EFI_SUCCESS;
    393 }
    394