Home | History | Annotate | Download | only in DxeCapsuleLib
      1 /** @file
      2   Capsule Library instance to process capsule images.
      3 
      4   Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials
      7   are licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 #include <PiDxe.h>
     16 
     17 #include <Guid/Capsule.h>
     18 #include <Guid/FmpCapsule.h>
     19 
     20 #include <Library/DebugLib.h>
     21 #include <Library/BaseMemoryLib.h>
     22 #include <Library/DxeServicesTableLib.h>
     23 #include <Library/MemoryAllocationLib.h>
     24 #include <Library/CapsuleLib.h>
     25 #include <Library/GenericBdsLib.h>
     26 #include <Library/UefiBootServicesTableLib.h>
     27 #include <Library/BaseLib.h>
     28 #include <Library/DevicePathLib.h>
     29 
     30 #include <Protocol/FirmwareManagement.h>
     31 #include <Protocol/DevicePath.h>
     32 
     33 
     34 /**
     35   Function indicate the current completion progress of the firmware
     36   update. Platform may override with own specific progress function.
     37 
     38   @param  Completion    A value between 1 and 100 indicating the current completion progress of the firmware update
     39 
     40   @retval EFI_SUCESS    Input capsule is a correct FMP capsule.
     41 **/
     42 EFI_STATUS
     43 EFIAPI
     44 Update_Image_Progress (
     45    IN UINTN Completion
     46 )
     47 {
     48   return EFI_SUCCESS;
     49 }
     50 
     51 
     52 /**
     53   Validate Fmp capsules layout.
     54 
     55   @param  CapsuleHeader    Points to a capsule header.
     56 
     57   @retval EFI_SUCESS                     Input capsule is a correct FMP capsule.
     58   @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.
     59 **/
     60 EFI_STATUS
     61 ValidateFmpCapsule (
     62   IN EFI_CAPSULE_HEADER *CapsuleHeader
     63   )
     64 {
     65   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
     66   UINT8                                        *EndOfCapsule;
     67   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
     68   UINT8                                        *EndOfPayload;
     69   UINT64                                       *ItemOffsetList;
     70   UINT32                                       ItemNum;
     71   UINTN                                        Index;
     72 
     73   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
     74   EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
     75 
     76   if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
     77     return EFI_INVALID_PARAMETER;
     78   }
     79   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
     80 
     81   ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
     82 
     83   if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) {
     84     //
     85     // No payload element
     86     //
     87     if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) {
     88       return EFI_SUCCESS;
     89     } else {
     90       return EFI_INVALID_PARAMETER;
     91     }
     92   }
     93 
     94   if (FmpCapsuleHeader->PayloadItemCount != 0) {
     95     //
     96     // Check if the last payload is within capsule image range
     97     //
     98     ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]);
     99     EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize;
    100   } else {
    101     //
    102     // No driver & payload element in FMP
    103     //
    104     EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
    105   }
    106 
    107   if (EndOfPayload != EndOfCapsule) {
    108     return EFI_INVALID_PARAMETER;
    109   }
    110 
    111   //
    112   // All the address in ItemOffsetList must be stored in ascending order
    113   //
    114   if (ItemNum >= 2) {
    115     for (Index = 0; Index < ItemNum - 1; Index++) {
    116       if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) {
    117         return EFI_INVALID_PARAMETER;
    118       }
    119     }
    120   }
    121 
    122   return EFI_SUCCESS;
    123 }
    124 
    125 /**
    126   Process Firmware management protocol data capsule.
    127 
    128   @param  CapsuleHeader         Points to a capsule header.
    129 
    130   @retval EFI_SUCESS            Process Capsule Image successfully.
    131   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
    132   @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
    133   @retval EFI_OUT_OF_RESOURCES  Not enough memory.
    134 **/
    135 EFI_STATUS
    136 ProcessFmpCapsuleImage (
    137   IN EFI_CAPSULE_HEADER *CapsuleHeader
    138   )
    139 {
    140   EFI_STATUS                                    Status;
    141   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
    142   UINT8                                         *EndOfCapsule;
    143   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
    144   EFI_HANDLE                                    ImageHandle;
    145   UINT64                                        *ItemOffsetList;
    146   UINT32                                        ItemNum;
    147   UINTN                                         Index;
    148   UINTN                                         ExitDataSize;
    149   EFI_HANDLE                                    *HandleBuffer;
    150   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
    151   UINTN                                         NumberOfHandles;
    152   UINTN                                         DescriptorSize;
    153   UINT8                                         FmpImageInfoCount;
    154   UINT32                                        FmpImageInfoDescriptorVer;
    155   UINTN                                         ImageInfoSize;
    156   UINT32                                        PackageVersion;
    157   CHAR16                                        *PackageVersionName;
    158   CHAR16                                        *AbortReason;
    159   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
    160   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;
    161   UINTN                                         DriverLen;
    162   UINTN                                         Index1;
    163   UINTN                                         Index2;
    164   MEMMAP_DEVICE_PATH                            MemMapNode;
    165   EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;
    166 
    167   Status           = EFI_SUCCESS;
    168   HandleBuffer     = NULL;
    169   ExitDataSize     = 0;
    170   DriverDevicePath = NULL;
    171 
    172   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
    173   EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
    174 
    175   if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
    176     return EFI_INVALID_PARAMETER;
    177   }
    178   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
    179 
    180   ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
    181 
    182   //
    183   // capsule in which driver count and payload count are both zero is not processed.
    184   //
    185   if (ItemNum == 0) {
    186     return EFI_SUCCESS;
    187   }
    188 
    189   //
    190   // 1. ConnectAll to ensure
    191   //    All the communication protocol required by driver in capsule installed
    192   //    All FMP protocols are installed
    193   //
    194   BdsLibConnectAll();
    195 
    196 
    197   //
    198   // 2. Try to load & start all the drivers within capsule
    199   //
    200   SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
    201   MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;
    202   MemMapNode.Header.SubType  = HW_MEMMAP_DP;
    203   MemMapNode.MemoryType      = EfiBootServicesCode;
    204   MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;
    205   MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);
    206 
    207   DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
    208   if (DriverDevicePath == NULL) {
    209     return EFI_OUT_OF_RESOURCES;
    210   }
    211 
    212   for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
    213     if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {
    214       //
    215       // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
    216       //
    217       DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
    218     } else {
    219       DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
    220     }
    221 
    222     Status = gBS->LoadImage(
    223                     FALSE,
    224                     gImageHandle,
    225                     DriverDevicePath,
    226                     (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
    227                     DriverLen,
    228                     &ImageHandle
    229                     );
    230     if (EFI_ERROR(Status)) {
    231       goto EXIT;
    232     }
    233 
    234     Status = gBS->StartImage(
    235                     ImageHandle,
    236                     &ExitDataSize,
    237                     NULL
    238                     );
    239     if (EFI_ERROR(Status)) {
    240       DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
    241       goto EXIT;
    242     }
    243   }
    244 
    245   //
    246   // Connnect all again to connect drivers within capsule
    247   //
    248   if (FmpCapsuleHeader->EmbeddedDriverCount > 0) {
    249     BdsLibConnectAll();
    250   }
    251 
    252   //
    253   // 3. Route payload to right FMP instance
    254   //
    255   Status = gBS->LocateHandleBuffer (
    256                   ByProtocol,
    257                   &gEfiFirmwareManagementProtocolGuid,
    258                   NULL,
    259                   &NumberOfHandles,
    260                   &HandleBuffer
    261                   );
    262 
    263   if (!EFI_ERROR(Status)) {
    264     for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {
    265       Status = gBS->HandleProtocol(
    266                       HandleBuffer[Index1],
    267                       &gEfiFirmwareManagementProtocolGuid,
    268                       (VOID **)&Fmp
    269                       );
    270       if (EFI_ERROR(Status)) {
    271         continue;
    272       }
    273 
    274       ImageInfoSize = 0;
    275       Status = Fmp->GetImageInfo (
    276                       Fmp,
    277                       &ImageInfoSize,
    278                       NULL,
    279                       NULL,
    280                       NULL,
    281                       NULL,
    282                       NULL,
    283                       NULL
    284                       );
    285       if (Status != EFI_BUFFER_TOO_SMALL) {
    286         continue;
    287       }
    288 
    289       FmpImageInfoBuf = NULL;
    290       FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
    291       if (FmpImageInfoBuf == NULL) {
    292         Status = EFI_OUT_OF_RESOURCES;
    293         goto EXIT;
    294       }
    295 
    296       PackageVersionName = NULL;
    297       Status = Fmp->GetImageInfo (
    298                       Fmp,
    299                       &ImageInfoSize,               // ImageInfoSize
    300                       FmpImageInfoBuf,              // ImageInfo
    301                       &FmpImageInfoDescriptorVer,   // DescriptorVersion
    302                       &FmpImageInfoCount,           // DescriptorCount
    303                       &DescriptorSize,              // DescriptorSize
    304                       &PackageVersion,              // PackageVersion
    305                       &PackageVersionName           // PackageVersionName
    306                       );
    307 
    308       //
    309       // If FMP GetInformation interface failed, skip this resource
    310       //
    311       if (EFI_ERROR(Status)) {
    312         FreePool(FmpImageInfoBuf);
    313         continue;
    314       }
    315 
    316       if (PackageVersionName != NULL) {
    317         FreePool(PackageVersionName);
    318       }
    319 
    320       TempFmpImageInfo = FmpImageInfoBuf;
    321       for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
    322         //
    323         // Check all the payload entry in capsule payload list
    324         //
    325         for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
    326           ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
    327           if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&
    328               ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {
    329             AbortReason = NULL;
    330             if (ImageHeader->UpdateVendorCodeSize == 0) {
    331               Status = Fmp->SetImage(
    332                               Fmp,
    333                               TempFmpImageInfo->ImageIndex,           // ImageIndex
    334                               (UINT8 *)(ImageHeader + 1),             // Image
    335                               ImageHeader->UpdateImageSize,           // ImageSize
    336                               NULL,                                   // VendorCode
    337                               Update_Image_Progress,                  // Progress
    338                               &AbortReason                            // AbortReason
    339                               );
    340             } else {
    341               Status = Fmp->SetImage(
    342                               Fmp,
    343                               TempFmpImageInfo->ImageIndex,                                          // ImageIndex
    344                               (UINT8 *)(ImageHeader + 1),                                            // Image
    345                               ImageHeader->UpdateImageSize,                                          // ImageSize
    346                               (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode
    347                               Update_Image_Progress,                                                 // Progress
    348                               &AbortReason                                                           // AbortReason
    349                               );
    350             }
    351             if (AbortReason != NULL) {
    352               DEBUG ((EFI_D_ERROR, "%s\n", AbortReason));
    353               FreePool(AbortReason);
    354             }
    355           }
    356         }
    357         //
    358         // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
    359         //
    360         TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
    361       }
    362       FreePool(FmpImageInfoBuf);
    363     }
    364   }
    365 
    366 EXIT:
    367 
    368   if (HandleBuffer != NULL) {
    369     FreePool(HandleBuffer);
    370   }
    371 
    372   if (DriverDevicePath != NULL) {
    373     FreePool(DriverDevicePath);
    374   }
    375 
    376   return Status;
    377 }
    378 
    379 /**
    380   Those capsules supported by the firmwares.
    381 
    382   @param  CapsuleHeader    Points to a capsule header.
    383 
    384   @retval EFI_SUCESS       Input capsule is supported by firmware.
    385   @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
    386   @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
    387 **/
    388 EFI_STATUS
    389 EFIAPI
    390 SupportCapsuleImage (
    391   IN EFI_CAPSULE_HEADER *CapsuleHeader
    392   )
    393 {
    394   if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
    395     return EFI_SUCCESS;
    396   }
    397 
    398   if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
    399     //
    400     // Check layout of FMP capsule
    401     //
    402     return ValidateFmpCapsule(CapsuleHeader);
    403   }
    404 
    405   return EFI_UNSUPPORTED;
    406 }
    407 
    408 /**
    409   The firmware implements to process the capsule image.
    410 
    411   @param  CapsuleHeader         Points to a capsule header.
    412 
    413   @retval EFI_SUCESS            Process Capsule Image successfully.
    414   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
    415   @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
    416   @retval EFI_OUT_OF_RESOURCES  Not enough memory.
    417 **/
    418 EFI_STATUS
    419 EFIAPI
    420 ProcessCapsuleImage (
    421   IN EFI_CAPSULE_HEADER *CapsuleHeader
    422   )
    423 {
    424   UINT32                       Length;
    425   EFI_FIRMWARE_VOLUME_HEADER   *FvImage;
    426   EFI_FIRMWARE_VOLUME_HEADER   *ProcessedFvImage;
    427   EFI_STATUS                   Status;
    428   EFI_HANDLE                   FvProtocolHandle;
    429   UINT32                       FvAlignment;
    430 
    431   FvImage = NULL;
    432   ProcessedFvImage = NULL;
    433   Status  = EFI_SUCCESS;
    434 
    435   if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
    436     return EFI_UNSUPPORTED;
    437   }
    438 
    439   //
    440   // Check FMP capsule layout
    441   //
    442   if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
    443     Status = ValidateFmpCapsule(CapsuleHeader);
    444     if (EFI_ERROR(Status)) {
    445       return Status;
    446     }
    447 
    448     //
    449     // Press EFI FMP Capsule
    450     //
    451     return ProcessFmpCapsuleImage(CapsuleHeader);
    452   }
    453 
    454   //
    455   // Skip the capsule header, move to the Firware Volume
    456   //
    457   FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
    458   Length  = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
    459 
    460   while (Length != 0) {
    461     //
    462     // Point to the next firmware volume header, and then
    463     // call the DXE service to process it.
    464     //
    465     if (FvImage->FvLength > (UINTN) Length) {
    466       //
    467       // Notes: need to stuff this status somewhere so that the
    468       // error can be detected at OS runtime
    469       //
    470       Status = EFI_VOLUME_CORRUPTED;
    471       break;
    472     }
    473 
    474     FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
    475     //
    476     // FvAlignment must be more than 8 bytes required by FvHeader structure.
    477     //
    478     if (FvAlignment < 8) {
    479       FvAlignment = 8;
    480     }
    481     //
    482     // Check FvImage Align is required.
    483     //
    484     if (((UINTN) FvImage % FvAlignment) == 0) {
    485       ProcessedFvImage = FvImage;
    486     } else {
    487       //
    488       // Allocate new aligned buffer to store FvImage.
    489       //
    490       ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment);
    491       if (ProcessedFvImage == NULL) {
    492         Status = EFI_OUT_OF_RESOURCES;
    493         break;
    494       }
    495       CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength);
    496     }
    497 
    498     Status = gDS->ProcessFirmwareVolume (
    499                   (VOID *) ProcessedFvImage,
    500                   (UINTN) ProcessedFvImage->FvLength,
    501                   &FvProtocolHandle
    502                   );
    503     if (EFI_ERROR (Status)) {
    504       break;
    505     }
    506     //
    507     // Call the dispatcher to dispatch any drivers from the produced firmware volume
    508     //
    509     gDS->Dispatch ();
    510     //
    511     // On to the next FV in the capsule
    512     //
    513     Length -= (UINT32) FvImage->FvLength;
    514     FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength);
    515   }
    516 
    517   return Status;
    518 }
    519 
    520 
    521