Add bitmask to structure which gives a binary-inspectable mechanism to determine if a capsule contains an authentication section or depex section. (UEFI 2.8 errata a, mantis 2026) Signed-off-by: Oleksiy Yakovlev <oleksiyy@ami.com> Signed-off-by: Wei6 Xu <wei6.xu@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			1651 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1651 lines
		
	
	
		
			56 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   DXE capsule library.
 | |
| 
 | |
|   Caution: This module requires additional review when modified.
 | |
|   This module will have external input - capsule image.
 | |
|   This external input must be validated carefully to avoid security issue like
 | |
|   buffer overflow, integer overflow.
 | |
| 
 | |
|   SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
 | |
|   ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
 | |
|   performs basic validation.
 | |
| 
 | |
|   Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <PiDxe.h>
 | |
| 
 | |
| #include <IndustryStandard/WindowsUxCapsule.h>
 | |
| 
 | |
| #include <Guid/FmpCapsule.h>
 | |
| #include <Guid/SystemResourceTable.h>
 | |
| #include <Guid/EventGroup.h>
 | |
| 
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DxeServicesTableLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/UefiRuntimeServicesTableLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/CapsuleLib.h>
 | |
| #include <Library/DevicePathLib.h>
 | |
| #include <Library/UefiLib.h>
 | |
| #include <Library/BmpSupportLib.h>
 | |
| 
 | |
| #include <Protocol/GraphicsOutput.h>
 | |
| #include <Protocol/EsrtManagement.h>
 | |
| #include <Protocol/FirmwareManagement.h>
 | |
| #include <Protocol/FirmwareManagementProgress.h>
 | |
| #include <Protocol/DevicePath.h>
 | |
| 
 | |
| EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable                  = NULL;
 | |
| BOOLEAN                   mIsVirtualAddrConverted      = FALSE;
 | |
| 
 | |
| BOOLEAN                   mDxeCapsuleLibEndOfDxe       = FALSE;
 | |
| EFI_EVENT                 mDxeCapsuleLibEndOfDxeEvent  = NULL;
 | |
| 
 | |
| EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *mFmpProgress = NULL;
 | |
| 
 | |
| /**
 | |
|   Initialize capsule related variables.
 | |
| **/
 | |
| VOID
 | |
| InitCapsuleVariable (
 | |
|   VOID
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Record capsule status variable.
 | |
| 
 | |
|   @param[in] CapsuleHeader  The capsule image header
 | |
|   @param[in] CapsuleStatus  The capsule process stauts
 | |
| 
 | |
|   @retval EFI_SUCCESS          The capsule status variable is recorded.
 | |
|   @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
 | |
| **/
 | |
| EFI_STATUS
 | |
| RecordCapsuleStatusVariable (
 | |
|   IN EFI_CAPSULE_HEADER                           *CapsuleHeader,
 | |
|   IN EFI_STATUS                                   CapsuleStatus
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Record FMP capsule status variable.
 | |
| 
 | |
|   @param[in] CapsuleHeader  The capsule image header
 | |
|   @param[in] CapsuleStatus  The capsule process stauts
 | |
|   @param[in] PayloadIndex   FMP payload index
 | |
|   @param[in] ImageHeader    FMP image header
 | |
|   @param[in] FmpDevicePath  DevicePath associated with the FMP producer
 | |
|   @param[in] CapFileName    Capsule file name
 | |
| 
 | |
|   @retval EFI_SUCCESS          The capsule status variable is recorded.
 | |
|   @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
 | |
| **/
 | |
| EFI_STATUS
 | |
| RecordFmpCapsuleStatusVariable (
 | |
|   IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
 | |
|   IN EFI_STATUS                                    CapsuleStatus,
 | |
|   IN UINTN                                         PayloadIndex,
 | |
|   IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL                      *FmpDevicePath, OPTIONAL
 | |
|   IN CHAR16                                        *CapFileName    OPTIONAL
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Function indicate the current completion progress of the firmware
 | |
|   update. Platform may override with own specific progress function.
 | |
| 
 | |
|   @param[in]  Completion  A value between 1 and 100 indicating the current
 | |
|                           completion progress of the firmware update
 | |
| 
 | |
|   @retval EFI_SUCESS             The capsule update progress was updated.
 | |
|   @retval EFI_INVALID_PARAMETER  Completion is greater than 100%.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UpdateImageProgress (
 | |
|   IN UINTN  Completion
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
 | |
| 
 | |
|   @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
 | |
| 
 | |
|   @retval TRUE  It is a capsule name capsule.
 | |
|   @retval FALSE It is not a capsule name capsule.
 | |
| **/
 | |
| BOOLEAN
 | |
| IsCapsuleNameCapsule (
 | |
|   IN EFI_CAPSULE_HEADER         *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return if this CapsuleGuid is a FMP capsule GUID or not.
 | |
| 
 | |
|   @param[in] CapsuleGuid A pointer to EFI_GUID
 | |
| 
 | |
|   @retval TRUE  It is a FMP capsule GUID.
 | |
|   @retval FALSE It is not a FMP capsule GUID.
 | |
| **/
 | |
| BOOLEAN
 | |
| IsFmpCapsuleGuid (
 | |
|   IN EFI_GUID  *CapsuleGuid
 | |
|   )
 | |
| {
 | |
|   if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Validate if it is valid capsule header
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   This function assumes the caller provided correct CapsuleHeader pointer
 | |
|   and CapsuleSize.
 | |
| 
 | |
|   This function validates the fields in EFI_CAPSULE_HEADER.
 | |
| 
 | |
|   @param[in]  CapsuleHeader    Points to a capsule header.
 | |
|   @param[in]  CapsuleSize      Size of the whole capsule image.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| IsValidCapsuleHeader (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | |
|   IN UINT64              CapsuleSize
 | |
|   )
 | |
| {
 | |
|   if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Validate Fmp capsules layout.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   This function assumes the caller validated the capsule by using
 | |
|   IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
 | |
|   The capsule buffer size is CapsuleHeader->CapsuleImageSize.
 | |
| 
 | |
|   This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
 | |
|   and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
 | |
| 
 | |
|   This function need support nested FMP capsule.
 | |
| 
 | |
|   @param[in]   CapsuleHeader        Points to a capsule header.
 | |
|   @param[out]  EmbeddedDriverCount  The EmbeddedDriverCount in the FMP capsule.
 | |
| 
 | |
|   @retval EFI_SUCESS             Input capsule is a correct FMP capsule.
 | |
|   @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.
 | |
| **/
 | |
| EFI_STATUS
 | |
| ValidateFmpCapsule (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | |
|   OUT UINT16             *EmbeddedDriverCount OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
 | |
|   UINT8                                        *EndOfCapsule;
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
 | |
|   UINT8                                        *EndOfPayload;
 | |
|   UINT64                                       *ItemOffsetList;
 | |
|   UINT32                                       ItemNum;
 | |
|   UINTN                                        Index;
 | |
|   UINTN                                        FmpCapsuleSize;
 | |
|   UINTN                                        FmpCapsuleHeaderSize;
 | |
|   UINT64                                       FmpImageSize;
 | |
|   UINTN                                        FmpImageHeaderSize;
 | |
| 
 | |
|   if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
 | |
|     return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
 | |
|   }
 | |
| 
 | |
|   if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
 | |
|     DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | |
|   EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
 | |
|   FmpCapsuleSize   = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
 | |
| 
 | |
|   if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
 | |
|     DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
 | |
|   if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
 | |
|     DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | |
| 
 | |
|   // No overflow
 | |
|   ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
 | |
| 
 | |
|   if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {
 | |
|     DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;
 | |
| 
 | |
|   // Check ItemOffsetList
 | |
|   for (Index = 0; Index < ItemNum; Index++) {
 | |
|     if (ItemOffsetList[Index] >= FmpCapsuleSize) {
 | |
|       DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
 | |
|       DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     //
 | |
|     // All the address in ItemOffsetList must be stored in ascending order
 | |
|     //
 | |
|     if (Index > 0) {
 | |
|       if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
 | |
|         DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
 | |
|   for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
 | |
|     ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
 | |
|     if (Index == ItemNum - 1) {
 | |
|       EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
 | |
|     } else {
 | |
|       EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
 | |
|     }
 | |
|     FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
 | |
| 
 | |
|     FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
 | |
|     if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
 | |
|         (ImageHeader->Version < 1)) {
 | |
|       DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     if (ImageHeader->Version == 1) {
 | |
|       FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
 | |
|     } else if (ImageHeader->Version == 2) {
 | |
|       FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
 | |
|     }
 | |
|     if (FmpImageSize < FmpImageHeaderSize) {
 | |
|       DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     // No overflow
 | |
|     if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
 | |
|       DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (ItemNum == 0) {
 | |
|     //
 | |
|     // No driver & payload element in FMP
 | |
|     //
 | |
|     EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
 | |
|     if (EndOfPayload != EndOfCapsule) {
 | |
|       DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   if (EmbeddedDriverCount != NULL) {
 | |
|     *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Those capsules supported by the firmwares.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   @param[in]  CapsuleHeader    Points to a capsule header.
 | |
| 
 | |
|   @retval EFI_SUCESS       Input capsule is supported by firmware.
 | |
|   @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
 | |
| **/
 | |
| EFI_STATUS
 | |
| DisplayCapsuleImage (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   DISPLAY_DISPLAY_PAYLOAD       *ImagePayload;
 | |
|   UINTN                         PayloadSize;
 | |
|   EFI_STATUS                    Status;
 | |
|   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
 | |
|   UINTN                         BltSize;
 | |
|   UINTN                         Height;
 | |
|   UINTN                         Width;
 | |
|   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
 | |
| 
 | |
|   //
 | |
|   // UX capsule doesn't have extended header entries.
 | |
|   //
 | |
|   if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN) CapsuleHeader + CapsuleHeader->HeaderSize);
 | |
|   //
 | |
|   // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
 | |
|   //
 | |
|   PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
 | |
| 
 | |
|   //
 | |
|   // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
 | |
|   // Further size check is performed by the logic translating BMP to GOP BLT.
 | |
|   //
 | |
|   if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (ImagePayload->Version != 1) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   //
 | |
|   // Only Support Bitmap by now
 | |
|   //
 | |
|   if (ImagePayload->ImageType != 0) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Try to open GOP
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Blt = NULL;
 | |
|   Width = 0;
 | |
|   Height = 0;
 | |
|   Status = TranslateBmpToGopBlt (
 | |
|              ImagePayload + 1,
 | |
|              PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),
 | |
|              &Blt,
 | |
|              &BltSize,
 | |
|              &Height,
 | |
|              &Width
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = GraphicsOutput->Blt (
 | |
|                              GraphicsOutput,
 | |
|                              Blt,
 | |
|                              EfiBltBufferToVideo,
 | |
|                              0,
 | |
|                              0,
 | |
|                              (UINTN) ImagePayload->OffsetX,
 | |
|                              (UINTN) ImagePayload->OffsetY,
 | |
|                              Width,
 | |
|                              Height,
 | |
|                              Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
 | |
|                              );
 | |
| 
 | |
|   FreePool(Blt);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dump FMP information.
 | |
| 
 | |
|   @param[in] ImageInfoSize       The size of ImageInfo, in bytes.
 | |
|   @param[in] ImageInfo           A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
 | |
|   @param[in] DescriptorVersion   The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
 | |
|   @param[in] DescriptorCount     The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
 | |
|   @param[in] DescriptorSize      The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
 | |
|   @param[in] PackageVersion      The version of package.
 | |
|   @param[in] PackageVersionName  The version name of package.
 | |
| **/
 | |
| VOID
 | |
| DumpFmpImageInfo (
 | |
|   IN UINTN                           ImageInfoSize,
 | |
|   IN EFI_FIRMWARE_IMAGE_DESCRIPTOR   *ImageInfo,
 | |
|   IN UINT32                          DescriptorVersion,
 | |
|   IN UINT8                           DescriptorCount,
 | |
|   IN UINTN                           DescriptorSize,
 | |
|   IN UINT32                          PackageVersion,
 | |
|   IN CHAR16                          *PackageVersionName
 | |
|   )
 | |
| {
 | |
|   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *CurrentImageInfo;
 | |
|   UINTN                                         Index;
 | |
| 
 | |
|   DEBUG((DEBUG_VERBOSE, "  DescriptorVersion  - 0x%x\n", DescriptorVersion));
 | |
|   DEBUG((DEBUG_VERBOSE, "  DescriptorCount    - 0x%x\n", DescriptorCount));
 | |
|   DEBUG((DEBUG_VERBOSE, "  DescriptorSize     - 0x%x\n", DescriptorSize));
 | |
|   DEBUG((DEBUG_VERBOSE, "  PackageVersion     - 0x%x\n", PackageVersion));
 | |
|   DEBUG((DEBUG_VERBOSE, "  PackageVersionName - %s\n\n", PackageVersionName));
 | |
|   CurrentImageInfo = ImageInfo;
 | |
|   for (Index = 0; Index < DescriptorCount; Index++) {
 | |
|     DEBUG((DEBUG_VERBOSE, "  ImageDescriptor (%d)\n", Index));
 | |
|     DEBUG((DEBUG_VERBOSE, "    ImageIndex                  - 0x%x\n", CurrentImageInfo->ImageIndex));
 | |
|     DEBUG((DEBUG_VERBOSE, "    ImageTypeId                 - %g\n", &CurrentImageInfo->ImageTypeId));
 | |
|     DEBUG((DEBUG_VERBOSE, "    ImageId                     - 0x%lx\n", CurrentImageInfo->ImageId));
 | |
|     DEBUG((DEBUG_VERBOSE, "    ImageIdName                 - %s\n", CurrentImageInfo->ImageIdName));
 | |
|     DEBUG((DEBUG_VERBOSE, "    Version                     - 0x%x\n", CurrentImageInfo->Version));
 | |
|     DEBUG((DEBUG_VERBOSE, "    VersionName                 - %s\n", CurrentImageInfo->VersionName));
 | |
|     DEBUG((DEBUG_VERBOSE, "    Size                        - 0x%x\n", CurrentImageInfo->Size));
 | |
|     DEBUG((DEBUG_VERBOSE, "    AttributesSupported         - 0x%lx\n", CurrentImageInfo->AttributesSupported));
 | |
|     DEBUG((DEBUG_VERBOSE, "    AttributesSetting           - 0x%lx\n", CurrentImageInfo->AttributesSetting));
 | |
|     DEBUG((DEBUG_VERBOSE, "    Compatibilities             - 0x%lx\n", CurrentImageInfo->Compatibilities));
 | |
|     if (DescriptorVersion > 1) {
 | |
|       DEBUG((DEBUG_VERBOSE, "    LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
 | |
|       if (DescriptorVersion > 2) {
 | |
|         DEBUG((DEBUG_VERBOSE, "    LastAttemptVersion          - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
 | |
|         DEBUG((DEBUG_VERBOSE, "    LastAttemptStatus           - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
 | |
|         DEBUG((DEBUG_VERBOSE, "    HardwareInstance            - 0x%lx\n", CurrentImageInfo->HardwareInstance));
 | |
|       }
 | |
|     }
 | |
|     //
 | |
|     // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
 | |
|     //
 | |
|     CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dump a non-nested FMP capsule.
 | |
| 
 | |
|   @param[in]  CapsuleHeader  A pointer to CapsuleHeader
 | |
| **/
 | |
| VOID
 | |
| DumpFmpCapsule (
 | |
|   IN EFI_CAPSULE_HEADER                *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
 | |
|   UINTN                                         Index;
 | |
|   UINT64                                        *ItemOffsetList;
 | |
| 
 | |
|   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
 | |
| 
 | |
|   DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));
 | |
|   DEBUG((DEBUG_VERBOSE, "  Version                - 0x%x\n", FmpCapsuleHeader->Version));
 | |
|   DEBUG((DEBUG_VERBOSE, "  EmbeddedDriverCount    - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
 | |
|   DEBUG((DEBUG_VERBOSE, "  PayloadItemCount       - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
 | |
| 
 | |
|   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | |
|   for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
 | |
|     DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));
 | |
|   }
 | |
|   for (; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
 | |
|     DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));
 | |
|     ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
 | |
| 
 | |
|     DEBUG((DEBUG_VERBOSE, "  ImageHeader:\n"));
 | |
|     DEBUG((DEBUG_VERBOSE, "    Version                - 0x%x\n", ImageHeader->Version));
 | |
|     DEBUG((DEBUG_VERBOSE, "    UpdateImageTypeId      - %g\n", &ImageHeader->UpdateImageTypeId));
 | |
|     DEBUG((DEBUG_VERBOSE, "    UpdateImageIndex       - 0x%x\n", ImageHeader->UpdateImageIndex));
 | |
|     DEBUG((DEBUG_VERBOSE, "    UpdateImageSize        - 0x%x\n", ImageHeader->UpdateImageSize));
 | |
|     DEBUG((DEBUG_VERBOSE, "    UpdateVendorCodeSize   - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
 | |
|     if (ImageHeader->Version >= 2) {
 | |
|       DEBUG((DEBUG_VERBOSE, "    UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
 | |
|       if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|         DEBUG((DEBUG_VERBOSE, "    ImageCapsuleSupport    - 0x%lx\n",  ImageHeader->ImageCapsuleSupport));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Dump all FMP information.
 | |
| **/
 | |
| VOID
 | |
| DumpAllFmpInfo (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_HANDLE                                    *HandleBuffer;
 | |
|   UINTN                                         NumberOfHandles;
 | |
|   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
 | |
|   UINTN                                         Index;
 | |
|   UINTN                                         ImageInfoSize;
 | |
|   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
 | |
|   UINT32                                        FmpImageInfoDescriptorVer;
 | |
|   UINT8                                         FmpImageInfoCount;
 | |
|   UINTN                                         DescriptorSize;
 | |
|   UINT32                                        PackageVersion;
 | |
|   CHAR16                                        *PackageVersionName;
 | |
| 
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiFirmwareManagementProtocolGuid,
 | |
|                   NULL,
 | |
|                   &NumberOfHandles,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfHandles; Index++) {
 | |
|     Status = gBS->HandleProtocol(
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiFirmwareManagementProtocolGuid,
 | |
|                     (VOID **)&Fmp
 | |
|                     );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     ImageInfoSize = 0;
 | |
|     Status = Fmp->GetImageInfo (
 | |
|                     Fmp,
 | |
|                     &ImageInfoSize,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
 | |
|     if (FmpImageInfoBuf == NULL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     PackageVersionName = NULL;
 | |
|     Status = Fmp->GetImageInfo (
 | |
|                     Fmp,
 | |
|                     &ImageInfoSize,               // ImageInfoSize
 | |
|                     FmpImageInfoBuf,              // ImageInfo
 | |
|                     &FmpImageInfoDescriptorVer,   // DescriptorVersion
 | |
|                     &FmpImageInfoCount,           // DescriptorCount
 | |
|                     &DescriptorSize,              // DescriptorSize
 | |
|                     &PackageVersion,              // PackageVersion
 | |
|                     &PackageVersionName           // PackageVersionName
 | |
|                     );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       FreePool(FmpImageInfoBuf);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));
 | |
|     DumpFmpImageInfo(
 | |
|       ImageInfoSize,               // ImageInfoSize
 | |
|       FmpImageInfoBuf,             // ImageInfo
 | |
|       FmpImageInfoDescriptorVer,   // DescriptorVersion
 | |
|       FmpImageInfoCount,           // DescriptorCount
 | |
|       DescriptorSize,              // DescriptorSize
 | |
|       PackageVersion,              // PackageVersion
 | |
|       PackageVersionName           // PackageVersionName
 | |
|       );
 | |
| 
 | |
|     if (PackageVersionName != NULL) {
 | |
|       FreePool(PackageVersionName);
 | |
|     }
 | |
| 
 | |
|     FreePool(FmpImageInfoBuf);
 | |
|   }
 | |
| 
 | |
|   FreePool (HandleBuffer);
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get FMP handle by ImageTypeId and HardwareInstance.
 | |
| 
 | |
|   @param[in]     UpdateImageTypeId       Used to identify device firmware targeted by this update.
 | |
|   @param[in]     UpdateHardwareInstance  The HardwareInstance to target with this update.
 | |
|   @param[out]    NoHandles               The number of handles returned in HandleBuf.
 | |
|   @param[out]    HandleBuf               A pointer to the buffer to return the requested array of handles.
 | |
|   @param[out]    ResetRequiredBuf        A pointer to the buffer to return reset required flag for
 | |
|                                          the requested array of handles.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The array of handles and their reset required flag were returned in
 | |
|                                  HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
 | |
|                                  was returned in NoHandles.
 | |
|   @retval EFI_NOT_FOUND          No handles match the search.
 | |
|   @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the matching results.
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetFmpHandleBufferByType (
 | |
|   IN     EFI_GUID                     *UpdateImageTypeId,
 | |
|   IN     UINT64                       UpdateHardwareInstance,
 | |
|   OUT    UINTN                        *NoHandles, OPTIONAL
 | |
|   OUT    EFI_HANDLE                   **HandleBuf, OPTIONAL
 | |
|   OUT    BOOLEAN                      **ResetRequiredBuf OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_HANDLE                                    *HandleBuffer;
 | |
|   UINTN                                         NumberOfHandles;
 | |
|   EFI_HANDLE                                    *MatchedHandleBuffer;
 | |
|   BOOLEAN                                       *MatchedResetRequiredBuffer;
 | |
|   UINTN                                         MatchedNumberOfHandles;
 | |
|   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
 | |
|   UINTN                                         Index;
 | |
|   UINTN                                         ImageInfoSize;
 | |
|   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
 | |
|   UINT32                                        FmpImageInfoDescriptorVer;
 | |
|   UINT8                                         FmpImageInfoCount;
 | |
|   UINTN                                         DescriptorSize;
 | |
|   UINT32                                        PackageVersion;
 | |
|   CHAR16                                        *PackageVersionName;
 | |
|   UINTN                                         Index2;
 | |
|   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;
 | |
| 
 | |
|   if (NoHandles != NULL) {
 | |
|     *NoHandles = 0;
 | |
|   }
 | |
|   if (HandleBuf != NULL) {
 | |
|     *HandleBuf = NULL;
 | |
|   }
 | |
|   if (ResetRequiredBuf != NULL) {
 | |
|     *ResetRequiredBuf = NULL;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiFirmwareManagementProtocolGuid,
 | |
|                   NULL,
 | |
|                   &NumberOfHandles,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   MatchedNumberOfHandles = 0;
 | |
| 
 | |
|   MatchedHandleBuffer = NULL;
 | |
|   if (HandleBuf != NULL) {
 | |
|     MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);
 | |
|     if (MatchedHandleBuffer == NULL) {
 | |
|       FreePool (HandleBuffer);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   MatchedResetRequiredBuffer = NULL;
 | |
|   if (ResetRequiredBuf != NULL) {
 | |
|     MatchedResetRequiredBuffer = AllocateZeroPool (sizeof(BOOLEAN) * NumberOfHandles);
 | |
|     if (MatchedResetRequiredBuffer == NULL) {
 | |
|       if (MatchedHandleBuffer != NULL) {
 | |
|         FreePool (MatchedHandleBuffer);
 | |
|       }
 | |
|       FreePool (HandleBuffer);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NumberOfHandles; Index++) {
 | |
|     Status = gBS->HandleProtocol(
 | |
|                     HandleBuffer[Index],
 | |
|                     &gEfiFirmwareManagementProtocolGuid,
 | |
|                     (VOID **)&Fmp
 | |
|                     );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     ImageInfoSize = 0;
 | |
|     Status = Fmp->GetImageInfo (
 | |
|                     Fmp,
 | |
|                     &ImageInfoSize,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL,
 | |
|                     NULL
 | |
|                     );
 | |
|     if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
 | |
|     if (FmpImageInfoBuf == NULL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     PackageVersionName = NULL;
 | |
|     Status = Fmp->GetImageInfo (
 | |
|                     Fmp,
 | |
|                     &ImageInfoSize,               // ImageInfoSize
 | |
|                     FmpImageInfoBuf,              // ImageInfo
 | |
|                     &FmpImageInfoDescriptorVer,   // DescriptorVersion
 | |
|                     &FmpImageInfoCount,           // DescriptorCount
 | |
|                     &DescriptorSize,              // DescriptorSize
 | |
|                     &PackageVersion,              // PackageVersion
 | |
|                     &PackageVersionName           // PackageVersionName
 | |
|                     );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       FreePool(FmpImageInfoBuf);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (PackageVersionName != NULL) {
 | |
|       FreePool(PackageVersionName);
 | |
|     }
 | |
| 
 | |
|     TempFmpImageInfo = FmpImageInfoBuf;
 | |
|     for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
 | |
|       //
 | |
|       // Check if this FMP instance matches
 | |
|       //
 | |
|       if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
 | |
|         if ((UpdateHardwareInstance == 0) ||
 | |
|             ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
 | |
|              (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {
 | |
|           if (MatchedHandleBuffer != NULL) {
 | |
|             MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
 | |
|           }
 | |
|           if (MatchedResetRequiredBuffer != NULL) {
 | |
|             MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
 | |
|                                                                  IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
 | |
|                                                                  ((TempFmpImageInfo->AttributesSetting &
 | |
|                                                                  IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
 | |
|           }
 | |
|           MatchedNumberOfHandles++;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
 | |
|     }
 | |
|     FreePool(FmpImageInfoBuf);
 | |
|   }
 | |
| 
 | |
|   FreePool (HandleBuffer);
 | |
| 
 | |
|   if (MatchedNumberOfHandles == 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (NoHandles != NULL) {
 | |
|     *NoHandles = MatchedNumberOfHandles;
 | |
|   }
 | |
|   if (HandleBuf != NULL) {
 | |
|     *HandleBuf = MatchedHandleBuffer;
 | |
|   }
 | |
|   if (ResetRequiredBuf != NULL) {
 | |
|     *ResetRequiredBuf = MatchedResetRequiredBuffer;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return FmpImageInfoDescriptorVer by an FMP handle.
 | |
| 
 | |
|   @param[in]  Handle   A FMP handle.
 | |
| 
 | |
|   @return FmpImageInfoDescriptorVer associated with the FMP.
 | |
| **/
 | |
| UINT32
 | |
| GetFmpImageInfoDescriptorVer (
 | |
|   IN EFI_HANDLE                                   Handle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
 | |
|   UINTN                                         ImageInfoSize;
 | |
|   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
 | |
|   UINT32                                        FmpImageInfoDescriptorVer;
 | |
|   UINT8                                         FmpImageInfoCount;
 | |
|   UINTN                                         DescriptorSize;
 | |
|   UINT32                                        PackageVersion;
 | |
|   CHAR16                                        *PackageVersionName;
 | |
| 
 | |
|   Status = gBS->HandleProtocol(
 | |
|                   Handle,
 | |
|                   &gEfiFirmwareManagementProtocolGuid,
 | |
|                   (VOID **)&Fmp
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   ImageInfoSize = 0;
 | |
|   Status = Fmp->GetImageInfo (
 | |
|                   Fmp,
 | |
|                   &ImageInfoSize,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   NULL,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
 | |
|   if (FmpImageInfoBuf == NULL) {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   PackageVersionName = NULL;
 | |
|   Status = Fmp->GetImageInfo (
 | |
|                   Fmp,
 | |
|                   &ImageInfoSize,               // ImageInfoSize
 | |
|                   FmpImageInfoBuf,              // ImageInfo
 | |
|                   &FmpImageInfoDescriptorVer,   // DescriptorVersion
 | |
|                   &FmpImageInfoCount,           // DescriptorCount
 | |
|                   &DescriptorSize,              // DescriptorSize
 | |
|                   &PackageVersion,              // PackageVersion
 | |
|                   &PackageVersionName           // PackageVersionName
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     FreePool(FmpImageInfoBuf);
 | |
|     return 0;
 | |
|   }
 | |
|   return FmpImageInfoDescriptorVer;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Set FMP image data.
 | |
| 
 | |
|   @param[in]  Handle        A FMP handle.
 | |
|   @param[in]  ImageHeader   The payload image header.
 | |
|   @param[in]  PayloadIndex  The index of the payload.
 | |
| 
 | |
|   @return The status of FMP->SetImage.
 | |
| **/
 | |
| EFI_STATUS
 | |
| SetFmpImageData (
 | |
|   IN EFI_HANDLE                                   Handle,
 | |
|   IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
 | |
|   IN UINTN                                        PayloadIndex
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
 | |
|   UINT8                                         *Image;
 | |
|   VOID                                          *VendorCode;
 | |
|   CHAR16                                        *AbortReason;
 | |
|   EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
 | |
| 
 | |
|   Status = gBS->HandleProtocol(
 | |
|                   Handle,
 | |
|                   &gEfiFirmwareManagementProtocolGuid,
 | |
|                   (VOID **)&Fmp
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Lookup Firmware Management Progress Protocol before SetImage() is called
 | |
|   // This is an optional protocol that may not be present on Handle.
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (
 | |
|                   Handle,
 | |
|                   &gEdkiiFirmwareManagementProgressProtocolGuid,
 | |
|                   (VOID **)&mFmpProgress
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     mFmpProgress = NULL;
 | |
|   }
 | |
| 
 | |
|   if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|     Image = (UINT8 *)(ImageHeader + 1);
 | |
|   } else {
 | |
|     //
 | |
|     // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
 | |
|     // Header should exclude UpdateHardwareInstance field, and
 | |
|     // ImageCapsuleSupport field if version is 2.
 | |
|     //
 | |
|     if (ImageHeader->Version == 1) {
 | |
|       Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
 | |
|     } else {
 | |
|       Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (ImageHeader->UpdateVendorCodeSize == 0) {
 | |
|     VendorCode = NULL;
 | |
|   } else {
 | |
|     VendorCode = Image + ImageHeader->UpdateImageSize;
 | |
|   }
 | |
|   AbortReason = NULL;
 | |
|   DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));
 | |
|   DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
 | |
|   DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
 | |
|   DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
 | |
|   if (ImageHeader->Version >= 2) {
 | |
|     DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
 | |
|     if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|       DEBUG((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
 | |
|     }
 | |
|   }
 | |
|   DEBUG((DEBUG_INFO, "\n"));
 | |
| 
 | |
|   //
 | |
|   // Before calling SetImage(), reset the progress bar to 0%
 | |
|   //
 | |
|   ProgressCallback = UpdateImageProgress;
 | |
|   Status = UpdateImageProgress (0);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     ProgressCallback = NULL;
 | |
|   }
 | |
| 
 | |
|   Status = Fmp->SetImage(
 | |
|                   Fmp,
 | |
|                   ImageHeader->UpdateImageIndex,          // ImageIndex
 | |
|                   Image,                                  // Image
 | |
|                   ImageHeader->UpdateImageSize,           // ImageSize
 | |
|                   VendorCode,                             // VendorCode
 | |
|                   ProgressCallback,                       // Progress
 | |
|                   &AbortReason                            // AbortReason
 | |
|                   );
 | |
|   //
 | |
|   // Set the progress bar to 100% after returning from SetImage()
 | |
|   //
 | |
|   if (ProgressCallback != NULL) {
 | |
|     UpdateImageProgress (100);
 | |
|   }
 | |
| 
 | |
|   DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
 | |
|   if (AbortReason != NULL) {
 | |
|     DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
 | |
|     FreePool(AbortReason);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Clear mFmpProgress after SetImage() returns
 | |
|   //
 | |
|   mFmpProgress = NULL;
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Start a UEFI image in the FMP payload.
 | |
| 
 | |
|   @param[in]  ImageBuffer   A pointer to the memory location containing a copy of the image to be loaded..
 | |
|   @param[in]  ImageSize     The size in bytes of ImageBuffer.
 | |
| 
 | |
|   @return The status of gBS->LoadImage and gBS->StartImage.
 | |
| **/
 | |
| EFI_STATUS
 | |
| StartFmpImage (
 | |
|   IN VOID   *ImageBuffer,
 | |
|   IN UINTN  ImageSize
 | |
|   )
 | |
| {
 | |
|   MEMMAP_DEVICE_PATH                            MemMapNode;
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_HANDLE                                    ImageHandle;
 | |
|   EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;
 | |
|   UINTN                                         ExitDataSize;
 | |
| 
 | |
|   SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
 | |
|   MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;
 | |
|   MemMapNode.Header.SubType  = HW_MEMMAP_DP;
 | |
|   MemMapNode.MemoryType      = EfiBootServicesCode;
 | |
|   MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
 | |
|   MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
 | |
| 
 | |
|   DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
 | |
|   if (DriverDevicePath == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
 | |
|   Status = gBS->LoadImage(
 | |
|                   FALSE,
 | |
|                   gImageHandle,
 | |
|                   DriverDevicePath,
 | |
|                   ImageBuffer,
 | |
|                   ImageSize,
 | |
|                   &ImageHandle
 | |
|                   );
 | |
|   DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     //
 | |
|     // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
 | |
|     // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
 | |
|     // If the caller doesn't have the option to defer the execution of an image, we should
 | |
|     // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
 | |
|     //
 | |
|     if (Status == EFI_SECURITY_VIOLATION) {
 | |
|       gBS->UnloadImage (ImageHandle);
 | |
|     }
 | |
|     FreePool(DriverDevicePath);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
 | |
|   Status = gBS->StartImage(
 | |
|                   ImageHandle,
 | |
|                   &ExitDataSize,
 | |
|                   NULL
 | |
|                   );
 | |
|   DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
 | |
|   }
 | |
| 
 | |
|   FreePool(DriverDevicePath);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Record FMP capsule status.
 | |
| 
 | |
|   @param[in] Handle         A FMP handle.
 | |
|   @param[in] CapsuleHeader  The capsule image header
 | |
|   @param[in] CapsuleStatus  The capsule process stauts
 | |
|   @param[in] PayloadIndex   FMP payload index
 | |
|   @param[in] ImageHeader    FMP image header
 | |
|   @param[in] CapFileName    Capsule file name
 | |
| **/
 | |
| VOID
 | |
| RecordFmpCapsuleStatus (
 | |
|   IN EFI_HANDLE                                    Handle,  OPTIONAL
 | |
|   IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
 | |
|   IN EFI_STATUS                                    CapsuleStatus,
 | |
|   IN UINTN                                         PayloadIndex,
 | |
|   IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader,
 | |
|   IN CHAR16                                        *CapFileName   OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_DEVICE_PATH_PROTOCOL                      *FmpDevicePath;
 | |
|   UINT32                                        FmpImageInfoDescriptorVer;
 | |
|   EFI_STATUS                                    StatusEsrt;
 | |
|   ESRT_MANAGEMENT_PROTOCOL                      *EsrtProtocol;
 | |
|   EFI_SYSTEM_RESOURCE_ENTRY                     EsrtEntry;
 | |
| 
 | |
|   FmpDevicePath = NULL;
 | |
|   if (Handle != NULL) {
 | |
|     gBS->HandleProtocol(
 | |
|            Handle,
 | |
|            &gEfiDevicePathProtocolGuid,
 | |
|            (VOID **)&FmpDevicePath
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   RecordFmpCapsuleStatusVariable (
 | |
|     CapsuleHeader,
 | |
|     CapsuleStatus,
 | |
|     PayloadIndex,
 | |
|     ImageHeader,
 | |
|     FmpDevicePath,
 | |
|     CapFileName
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Update corresponding ESRT entry LastAttemp Status
 | |
|   //
 | |
|   Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   if (Handle == NULL) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update EsrtEntry For V1, V2 FMP instance.
 | |
|   // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
 | |
|   //
 | |
|   FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
 | |
|   if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
 | |
|     StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry);
 | |
|     if (!EFI_ERROR(StatusEsrt)){
 | |
|       if (!EFI_ERROR(CapsuleStatus)) {
 | |
|         EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
 | |
|       } else {
 | |
|         EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
 | |
|       }
 | |
|       EsrtEntry.LastAttemptVersion = 0;
 | |
|       EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Process Firmware management protocol data capsule.
 | |
| 
 | |
|   This function assumes the caller validated the capsule by using
 | |
|   ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
 | |
| 
 | |
|   This function need support nested FMP capsule.
 | |
| 
 | |
|   @param[in]  CapsuleHeader         Points to a capsule header.
 | |
|   @param[in]  CapFileName           Capsule file name.
 | |
|   @param[out] ResetRequired         Indicates whether reset is required or not.
 | |
| 
 | |
|   @retval EFI_SUCESS            Process Capsule Image successfully.
 | |
|   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
 | |
|   @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Not enough memory.
 | |
|   @retval EFI_NOT_READY         No FMP protocol to handle this FMP capsule.
 | |
| **/
 | |
| EFI_STATUS
 | |
| ProcessFmpCapsuleImage (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | |
|   IN CHAR16              *CapFileName,  OPTIONAL
 | |
|   OUT BOOLEAN            *ResetRequired OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
 | |
|   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
 | |
|   UINT64                                        *ItemOffsetList;
 | |
|   UINT32                                        ItemNum;
 | |
|   UINTN                                         Index;
 | |
|   EFI_HANDLE                                    *HandleBuffer;
 | |
|   BOOLEAN                                       *ResetRequiredBuffer;
 | |
|   UINTN                                         NumberOfHandles;
 | |
|   UINTN                                         DriverLen;
 | |
|   UINT64                                        UpdateHardwareInstance;
 | |
|   UINTN                                         Index2;
 | |
|   BOOLEAN                                       NotReady;
 | |
|   BOOLEAN                                       Abort;
 | |
| 
 | |
|   if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
 | |
|     return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
 | |
|   }
 | |
| 
 | |
|   NotReady = FALSE;
 | |
|   Abort = FALSE;
 | |
| 
 | |
|   DumpFmpCapsule(CapsuleHeader);
 | |
| 
 | |
|   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
 | |
| 
 | |
|   if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
 | |
| 
 | |
|   ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
 | |
| 
 | |
|   //
 | |
|   // capsule in which driver count and payload count are both zero is not processed.
 | |
|   //
 | |
|   if (ItemNum == 0) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 1. Try to load & start all the drivers within capsule
 | |
|   //
 | |
|   for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
 | |
|     if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
 | |
|         (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1)) {
 | |
|       //
 | |
|       // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
 | |
|       //
 | |
|       DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
 | |
|     } else {
 | |
|       DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
 | |
|     }
 | |
| 
 | |
|     Status = StartFmpImage (
 | |
|                (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
 | |
|                DriverLen
 | |
|                );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // 2. Route payload to right FMP instance
 | |
|   //
 | |
|   DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
 | |
| 
 | |
|   DumpAllFmpInfo ();
 | |
| 
 | |
|   //
 | |
|   // Check all the payload entry in capsule payload list
 | |
|   //
 | |
|   for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
 | |
|     ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
 | |
| 
 | |
|     UpdateHardwareInstance = 0;
 | |
|     ///
 | |
|     /// UpdateHardwareInstance field was added in Version 2
 | |
|     ///
 | |
|     if (ImageHeader->Version >= 2) {
 | |
|       UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
 | |
|     }
 | |
| 
 | |
|     Status = GetFmpHandleBufferByType (
 | |
|                &ImageHeader->UpdateImageTypeId,
 | |
|                UpdateHardwareInstance,
 | |
|                &NumberOfHandles,
 | |
|                &HandleBuffer,
 | |
|                &ResetRequiredBuffer
 | |
|                );
 | |
|     if (EFI_ERROR(Status) ||
 | |
|         (HandleBuffer == NULL) ||
 | |
|         (ResetRequiredBuffer == NULL)) {
 | |
|       NotReady = TRUE;
 | |
|       RecordFmpCapsuleStatus (
 | |
|         NULL,
 | |
|         CapsuleHeader,
 | |
|         EFI_NOT_READY,
 | |
|         Index - FmpCapsuleHeader->EmbeddedDriverCount,
 | |
|         ImageHeader,
 | |
|         CapFileName
 | |
|         );
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
 | |
|       if (Abort) {
 | |
|         RecordFmpCapsuleStatus (
 | |
|           HandleBuffer[Index2],
 | |
|           CapsuleHeader,
 | |
|           EFI_ABORTED,
 | |
|           Index - FmpCapsuleHeader->EmbeddedDriverCount,
 | |
|           ImageHeader,
 | |
|           CapFileName
 | |
|           );
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       Status = SetFmpImageData (
 | |
|                  HandleBuffer[Index2],
 | |
|                  ImageHeader,
 | |
|                  Index - FmpCapsuleHeader->EmbeddedDriverCount
 | |
|                  );
 | |
|       if (Status != EFI_SUCCESS) {
 | |
|         Abort = TRUE;
 | |
|       } else {
 | |
|         if (ResetRequired != NULL) {
 | |
|           *ResetRequired |= ResetRequiredBuffer[Index2];
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       RecordFmpCapsuleStatus (
 | |
|         HandleBuffer[Index2],
 | |
|         CapsuleHeader,
 | |
|         Status,
 | |
|         Index - FmpCapsuleHeader->EmbeddedDriverCount,
 | |
|         ImageHeader,
 | |
|         CapFileName
 | |
|         );
 | |
|     }
 | |
|     if (HandleBuffer != NULL) {
 | |
|       FreePool(HandleBuffer);
 | |
|     }
 | |
|     if (ResetRequiredBuffer != NULL) {
 | |
|       FreePool(ResetRequiredBuffer);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (NotReady) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // always return SUCCESS to indicate this capsule is processed.
 | |
|   // The status of SetImage is recorded in capsule result variable.
 | |
|   //
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return if there is a FMP header below capsule header.
 | |
| 
 | |
|   @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
 | |
| 
 | |
|   @retval TRUE  There is a FMP header below capsule header.
 | |
|   @retval FALSE There is not a FMP header below capsule header
 | |
| **/
 | |
| BOOLEAN
 | |
| IsNestedFmpCapsule (
 | |
|   IN EFI_CAPSULE_HEADER         *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                 Status;
 | |
|   EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
 | |
|   UINTN                      Index;
 | |
|   BOOLEAN                    EsrtGuidFound;
 | |
|   EFI_CAPSULE_HEADER         *NestedCapsuleHeader;
 | |
|   UINTN                      NestedCapsuleSize;
 | |
|   ESRT_MANAGEMENT_PROTOCOL   *EsrtProtocol;
 | |
|   EFI_SYSTEM_RESOURCE_ENTRY  Entry;
 | |
| 
 | |
|   EsrtGuidFound = FALSE;
 | |
|   if (mIsVirtualAddrConverted) {
 | |
|     if(mEsrtTable != NULL) {
 | |
|       EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
 | |
|       for (Index = 0; Index < mEsrtTable->FwResourceCount ; Index++, EsrtEntry++) {
 | |
|         if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
 | |
|           EsrtGuidFound = TRUE;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Check ESRT protocol
 | |
|     //
 | |
|     Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
 | |
|     if (!EFI_ERROR(Status)) {
 | |
|       Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);
 | |
|       if (!EFI_ERROR(Status)) {
 | |
|         EsrtGuidFound = TRUE;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Check Firmware Management Protocols
 | |
|     //
 | |
|     if (!EsrtGuidFound) {
 | |
|       Status = GetFmpHandleBufferByType (
 | |
|                  &CapsuleHeader->CapsuleGuid,
 | |
|                  0,
 | |
|                  NULL,
 | |
|                  NULL,
 | |
|                  NULL
 | |
|                  );
 | |
|       if (!EFI_ERROR(Status)) {
 | |
|         EsrtGuidFound = TRUE;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   if (!EsrtGuidFound) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check nested capsule header
 | |
|   // FMP GUID after ESRT one
 | |
|   //
 | |
|   NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
 | |
|   NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;
 | |
|   if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   if (!IsValidCapsuleHeader(NestedCapsuleHeader, NestedCapsuleSize)) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   if (!IsFmpCapsuleGuid(&NestedCapsuleHeader->CapsuleGuid)) {
 | |
|     return FALSE;
 | |
|   }
 | |
|   DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
 | |
| 
 | |
|   @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
 | |
| 
 | |
|   @retval TRUE  It is a system FMP.
 | |
|   @retval FALSE It is a device FMP.
 | |
| **/
 | |
| BOOLEAN
 | |
| IsFmpCapsule (
 | |
|   IN EFI_CAPSULE_HEADER         *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   if (IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
 | |
|     return TRUE;
 | |
|   }
 | |
|   if (IsNestedFmpCapsule(CapsuleHeader)) {
 | |
|     return TRUE;
 | |
|   }
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Those capsules supported by the firmwares.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   @param[in]  CapsuleHeader    Points to a capsule header.
 | |
| 
 | |
|   @retval EFI_SUCESS       Input capsule is supported by firmware.
 | |
|   @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
 | |
|   @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SupportCapsuleImage (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // check Display Capsule Guid
 | |
|   //
 | |
|   if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check capsule file name capsule
 | |
|   //
 | |
|   if (IsCapsuleNameCapsule(CapsuleHeader)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (IsFmpCapsule(CapsuleHeader)) {
 | |
|     //
 | |
|     // Fake capsule header is valid case in QueryCapsuleCpapbilities().
 | |
|     //
 | |
|     if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|     //
 | |
|     // Check layout of FMP capsule
 | |
|     //
 | |
|     return ValidateFmpCapsule(CapsuleHeader, NULL);
 | |
|   }
 | |
|   DEBUG((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The firmware implements to process the capsule image.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   @param[in]  CapsuleHeader         Points to a capsule header.
 | |
|   @param[in]  CapFileName           Capsule file name.
 | |
|   @param[out] ResetRequired         Indicates whether reset is required or not.
 | |
| 
 | |
|   @retval EFI_SUCESS            Process Capsule Image successfully.
 | |
|   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
 | |
|   @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Not enough memory.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ProcessThisCapsuleImage (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader,
 | |
|   IN CHAR16              *CapFileName,  OPTIONAL
 | |
|   OUT BOOLEAN            *ResetRequired OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
| 
 | |
|   if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
 | |
|     RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED);
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Display image in firmware update display capsule
 | |
|   //
 | |
|   if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
 | |
|     DEBUG((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
 | |
|     Status = DisplayCapsuleImage(CapsuleHeader);
 | |
|     RecordCapsuleStatusVariable(CapsuleHeader, Status);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check FMP capsule layout
 | |
|   //
 | |
|   if (IsFmpCapsule (CapsuleHeader)) {
 | |
|     DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
 | |
|     DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
 | |
|     Status = ValidateFmpCapsule(CapsuleHeader, NULL);
 | |
|     DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       RecordCapsuleStatusVariable(CapsuleHeader, Status);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Process EFI FMP Capsule
 | |
|     //
 | |
|     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
 | |
|     Status = ProcessFmpCapsuleImage(CapsuleHeader, CapFileName, ResetRequired);
 | |
|     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
 | |
| 
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The firmware implements to process the capsule image.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   @param[in]  CapsuleHeader         Points to a capsule header.
 | |
| 
 | |
|   @retval EFI_SUCESS            Process Capsule Image successfully.
 | |
|   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
 | |
|   @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Not enough memory.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ProcessCapsuleImage (
 | |
|   IN EFI_CAPSULE_HEADER  *CapsuleHeader
 | |
|   )
 | |
| {
 | |
|   return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback function executed when the EndOfDxe event group is signaled.
 | |
| 
 | |
|   @param[in] Event      Event whose notification function is being invoked.
 | |
|   @param[in] Context    The pointer to the notification function's context, which
 | |
|                         is implementation-dependent.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| DxeCapsuleLibEndOfDxe (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   mDxeCapsuleLibEndOfDxe = TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The constructor function.
 | |
| 
 | |
|   @param[in]  ImageHandle   The firmware allocated handle for the EFI image.
 | |
|   @param[in]  SystemTable   A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS   The constructor successfully .
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| DxeCapsuleLibConstructor (
 | |
|   IN EFI_HANDLE         ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE   *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_CALLBACK,
 | |
|                   DxeCapsuleLibEndOfDxe,
 | |
|                   NULL,
 | |
|                   &gEfiEndOfDxeEventGroupGuid,
 | |
|                   &mDxeCapsuleLibEndOfDxeEvent
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   InitCapsuleVariable();
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The destructor function closes the End of DXE event.
 | |
| 
 | |
|   @param  ImageHandle   The firmware allocated handle for the EFI image.
 | |
|   @param  SystemTable   A pointer to the EFI System Table.
 | |
| 
 | |
|   @retval EFI_SUCCESS   The destructor completed successfully.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| DxeCapsuleLibDestructor (
 | |
|   IN EFI_HANDLE         ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE   *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   //
 | |
|   // Close the End of DXE event.
 | |
|   //
 | |
|   Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 |