mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 05:28:13 +00:00 
			
		
		
		
	 032862642d
			
		
	
	
		032862642d
		
	
	
	
	
		
			
			Move the definition of variable "mEsrtTable" and "mIsVirtualAddrConverted" to DxeCapsuleLib.c. Cc: Jiewen Yao <jiewen.yao@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi <dandan.bi@intel.com> Reviewed-by: jiewen.yao@intel.com
		
			
				
	
	
		
			1712 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1712 lines
		
	
	
		
			58 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(), DisplayCapsuleImage(), ConvertBmpToGopBlt() will
 | |
|   receive untrusted input and do basic validation.
 | |
| 
 | |
|   Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
 | |
|   This program and the accompanying materials
 | |
|   are licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include <PiDxe.h>
 | |
| 
 | |
| #include <IndustryStandard/Bmp.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/PcdLib.h>
 | |
| 
 | |
| #include <Protocol/GraphicsOutput.h>
 | |
| #include <Protocol/EsrtManagement.h>
 | |
| #include <Protocol/FirmwareManagement.h>
 | |
| #include <Protocol/DevicePath.h>
 | |
| 
 | |
| EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable                  = NULL;
 | |
| BOOLEAN                   mIsVirtualAddrConverted      = FALSE;
 | |
| 
 | |
| BOOLEAN                   mDxeCapsuleLibEndOfDxe       = FALSE;
 | |
| EFI_EVENT                 mDxeCapsuleLibEndOfDxeEvent  = 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
 | |
| 
 | |
|   @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
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   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    Input capsule is a correct FMP capsule.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Update_Image_Progress (
 | |
|   IN UINTN  Completion
 | |
|   )
 | |
| {
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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, 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];
 | |
| 
 | |
|     if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {
 | |
|       DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|     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 < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|       FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
 | |
|     }
 | |
| 
 | |
|     // 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;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
 | |
|   is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
 | |
|   buffer is passed in it will be used if it is big enough.
 | |
| 
 | |
|   Caution: This function may receive untrusted input.
 | |
| 
 | |
|   @param[in]       BmpImage      Pointer to BMP file
 | |
|   @param[in]       BmpImageSize  Number of bytes in BmpImage
 | |
|   @param[in, out]  GopBlt        Buffer containing GOP version of BmpImage.
 | |
|   @param[in, out]  GopBltSize    Size of GopBlt in bytes.
 | |
|   @param[out]      PixelHeight   Height of GopBlt/BmpImage in pixels
 | |
|   @param[out]      PixelWidth    Width of GopBlt/BmpImage in pixels
 | |
| 
 | |
|   @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
 | |
|   @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
 | |
|   @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.
 | |
|                                 GopBltSize will contain the required size.
 | |
|   @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| ConvertBmpToGopBlt (
 | |
|   IN     VOID      *BmpImage,
 | |
|   IN     UINTN     BmpImageSize,
 | |
|   IN OUT VOID      **GopBlt,
 | |
|   IN OUT UINTN     *GopBltSize,
 | |
|      OUT UINTN     *PixelHeight,
 | |
|      OUT UINTN     *PixelWidth
 | |
|   )
 | |
| {
 | |
|   UINT8                         *Image;
 | |
|   UINT8                         *ImageHeader;
 | |
|   BMP_IMAGE_HEADER              *BmpHeader;
 | |
|   BMP_COLOR_MAP                 *BmpColorMap;
 | |
|   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
 | |
|   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
 | |
|   UINT64                        BltBufferSize;
 | |
|   UINTN                         Index;
 | |
|   UINTN                         Height;
 | |
|   UINTN                         Width;
 | |
|   UINTN                         ImageIndex;
 | |
|   UINT32                        DataSizePerLine;
 | |
|   BOOLEAN                       IsAllocated;
 | |
|   UINT32                        ColorMapNum;
 | |
| 
 | |
|   if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
 | |
| 
 | |
|   if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Doesn't support compress.
 | |
|   //
 | |
|   if (BmpHeader->CompressionType != 0) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Only support BITMAPINFOHEADER format.
 | |
|   // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
 | |
|   //
 | |
|   if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The data size in each line must be 4 byte alignment.
 | |
|   //
 | |
|   DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
 | |
|   BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
 | |
|   if (BltBufferSize > (UINT32) ~0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((BmpHeader->Size != BmpImageSize) ||
 | |
|       (BmpHeader->Size < BmpHeader->ImageOffset) ||
 | |
|       (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Calculate Color Map offset in the image.
 | |
|   //
 | |
|   Image       = BmpImage;
 | |
|   BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
 | |
|   if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
 | |
|     switch (BmpHeader->BitPerPixel) {
 | |
|       case 1:
 | |
|         ColorMapNum = 2;
 | |
|         break;
 | |
|       case 4:
 | |
|         ColorMapNum = 16;
 | |
|         break;
 | |
|       case 8:
 | |
|         ColorMapNum = 256;
 | |
|         break;
 | |
|       default:
 | |
|         ColorMapNum = 0;
 | |
|         break;
 | |
|       }
 | |
|     //
 | |
|     // BMP file may has padding data between the bmp header section and the bmp data section.
 | |
|     //
 | |
|     if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Calculate graphics image data address in the image
 | |
|   //
 | |
|   Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
 | |
|   ImageHeader   = Image;
 | |
| 
 | |
|   //
 | |
|   // Calculate the BltBuffer needed size.
 | |
|   //
 | |
|   BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
 | |
|   //
 | |
|   // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
 | |
|   //
 | |
|   if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
 | |
| 
 | |
|   IsAllocated   = FALSE;
 | |
|   if (*GopBlt == NULL) {
 | |
|     //
 | |
|     // GopBlt is not allocated by caller.
 | |
|     //
 | |
|     *GopBltSize = (UINTN) BltBufferSize;
 | |
|     *GopBlt     = AllocatePool (*GopBltSize);
 | |
|     IsAllocated = TRUE;
 | |
|     if (*GopBlt == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // GopBlt has been allocated by caller.
 | |
|     //
 | |
|     if (*GopBltSize < (UINTN) BltBufferSize) {
 | |
|       *GopBltSize = (UINTN) BltBufferSize;
 | |
|       return EFI_BUFFER_TOO_SMALL;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   *PixelWidth   = BmpHeader->PixelWidth;
 | |
|   *PixelHeight  = BmpHeader->PixelHeight;
 | |
| 
 | |
|   //
 | |
|   // Convert image from BMP to Blt buffer format
 | |
|   //
 | |
|   BltBuffer = *GopBlt;
 | |
|   for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
 | |
|     Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
 | |
|     for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
 | |
|       switch (BmpHeader->BitPerPixel) {
 | |
|       case 1:
 | |
|         //
 | |
|         // Convert 1-bit (2 colors) BMP to 24-bit color
 | |
|         //
 | |
|         for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
 | |
|           Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
 | |
|           Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
 | |
|           Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
 | |
|           Blt++;
 | |
|           Width++;
 | |
|         }
 | |
| 
 | |
|         Blt--;
 | |
|         Width--;
 | |
|         break;
 | |
| 
 | |
|       case 4:
 | |
|         //
 | |
|         // Convert 4-bit (16 colors) BMP Palette to 24-bit color
 | |
|         //
 | |
|         Index       = (*Image) >> 4;
 | |
|         Blt->Red    = BmpColorMap[Index].Red;
 | |
|         Blt->Green  = BmpColorMap[Index].Green;
 | |
|         Blt->Blue   = BmpColorMap[Index].Blue;
 | |
|         if (Width < (BmpHeader->PixelWidth - 1)) {
 | |
|           Blt++;
 | |
|           Width++;
 | |
|           Index       = (*Image) & 0x0f;
 | |
|           Blt->Red    = BmpColorMap[Index].Red;
 | |
|           Blt->Green  = BmpColorMap[Index].Green;
 | |
|           Blt->Blue   = BmpColorMap[Index].Blue;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|       case 8:
 | |
|         //
 | |
|         // Convert 8-bit (256 colors) BMP Palette to 24-bit color
 | |
|         //
 | |
|         Blt->Red    = BmpColorMap[*Image].Red;
 | |
|         Blt->Green  = BmpColorMap[*Image].Green;
 | |
|         Blt->Blue   = BmpColorMap[*Image].Blue;
 | |
|         break;
 | |
| 
 | |
|       case 24:
 | |
|         //
 | |
|         // It is 24-bit BMP.
 | |
|         //
 | |
|         Blt->Blue   = *Image++;
 | |
|         Blt->Green  = *Image++;
 | |
|         Blt->Red    = *Image;
 | |
|         break;
 | |
| 
 | |
|       case 32:
 | |
|         //
 | |
|         // it is 32-bit BMP. Skip pixel's highest byte
 | |
|         //
 | |
|         Blt->Blue  = *Image++;
 | |
|         Blt->Green = *Image++;
 | |
|         Blt->Red   = *Image++;
 | |
|         break;
 | |
| 
 | |
|       default:
 | |
|         //
 | |
|         // Other bit format BMP is not supported.
 | |
|         //
 | |
|         if (IsAllocated) {
 | |
|           FreePool (*GopBlt);
 | |
|           *GopBlt = NULL;
 | |
|         }
 | |
|         return EFI_UNSUPPORTED;
 | |
|       };
 | |
| 
 | |
|     }
 | |
| 
 | |
|     ImageIndex = (UINTN) Image - (UINTN) ImageHeader;
 | |
|     if ((ImageIndex % 4) != 0) {
 | |
|       //
 | |
|       // Bmp Image starts each row on a 32-bit boundary!
 | |
|       //
 | |
|       Image = Image + (4 - (ImageIndex % 4));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);
 | |
|   PayloadSize = CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER);
 | |
| 
 | |
|   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 = ConvertBmpToGopBlt (
 | |
|              ImagePayload + 1,
 | |
|              PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),
 | |
|              (VOID **)&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 >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|       DEBUG((DEBUG_VERBOSE, "    UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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);
 | |
|   }
 | |
| 
 | |
|   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[in,out] NoHandles               The number of handles returned in Buffer.
 | |
|   @param[out]    Buffer[out]             A pointer to the buffer to return the requested array of handles.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The array of handles was returned in Buffer, and the number of
 | |
|                                  handles in Buffer 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,
 | |
|   IN OUT UINTN                        *NoHandles,
 | |
|   OUT    EFI_HANDLE                   **Buffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                    Status;
 | |
|   EFI_HANDLE                                    *HandleBuffer;
 | |
|   UINTN                                         NumberOfHandles;
 | |
|   EFI_HANDLE                                    *MatchedHandleBuffer;
 | |
|   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;
 | |
| 
 | |
|   *NoHandles = 0;
 | |
|   *Buffer = NULL;
 | |
| 
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiFirmwareManagementProtocolGuid,
 | |
|                   NULL,
 | |
|                   &NumberOfHandles,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   MatchedNumberOfHandles = 0;
 | |
|   MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);
 | |
|   if (MatchedHandleBuffer == NULL) {
 | |
|     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))) {
 | |
|           MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
 | |
|           MatchedNumberOfHandles++;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
 | |
|     }
 | |
|     FreePool(FmpImageInfoBuf);
 | |
|   }
 | |
| 
 | |
|   if (MatchedNumberOfHandles == 0) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *NoHandles = MatchedNumberOfHandles;
 | |
|   *Buffer = MatchedHandleBuffer;
 | |
| 
 | |
|   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;
 | |
| 
 | |
|   Status = gBS->HandleProtocol(
 | |
|                   Handle,
 | |
|                   &gEfiFirmwareManagementProtocolGuid,
 | |
|                   (VOID **)&Fmp
 | |
|                   );
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   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
 | |
|     //
 | |
|     Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
 | |
|   }
 | |
| 
 | |
|   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 >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|     DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
 | |
|   }
 | |
|   DEBUG((DEBUG_INFO, "\n"));
 | |
|   Status = Fmp->SetImage(
 | |
|                   Fmp,
 | |
|                   ImageHeader->UpdateImageIndex,          // ImageIndex
 | |
|                   Image,                                  // Image
 | |
|                   ImageHeader->UpdateImageSize,           // ImageSize
 | |
|                   VendorCode,                             // VendorCode
 | |
|                   Update_Image_Progress,                  // Progress
 | |
|                   &AbortReason                            // AbortReason
 | |
|                   );
 | |
|   DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
 | |
|   if (AbortReason != NULL) {
 | |
|     DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
 | |
|     FreePool(AbortReason);
 | |
|   }
 | |
| 
 | |
|   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)) {
 | |
|     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
 | |
| **/
 | |
| 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
 | |
|   )
 | |
| {
 | |
|   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
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // 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 EsrtSyncFmp 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.
 | |
| 
 | |
|   @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
 | |
|   )
 | |
| {
 | |
|   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;
 | |
|   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));
 | |
|   }
 | |
| 
 | |
|   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;
 | |
|     if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
 | |
|       UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
 | |
|     }
 | |
| 
 | |
|     Status = GetFmpHandleBufferByType (
 | |
|                &ImageHeader->UpdateImageTypeId,
 | |
|                UpdateHardwareInstance,
 | |
|                &NumberOfHandles,
 | |
|                &HandleBuffer
 | |
|                );
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       NotReady = TRUE;
 | |
|       RecordFmpCapsuleStatus (
 | |
|         NULL,
 | |
|         CapsuleHeader,
 | |
|         EFI_NOT_READY,
 | |
|         Index - FmpCapsuleHeader->EmbeddedDriverCount,
 | |
|         ImageHeader
 | |
|         );
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
 | |
|       if (Abort) {
 | |
|         RecordFmpCapsuleStatus (
 | |
|           HandleBuffer[Index2],
 | |
|           CapsuleHeader,
 | |
|           EFI_ABORTED,
 | |
|           Index - FmpCapsuleHeader->EmbeddedDriverCount,
 | |
|           ImageHeader
 | |
|           );
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       Status = SetFmpImageData (
 | |
|                  HandleBuffer[Index2],
 | |
|                  ImageHeader,
 | |
|                  Index - FmpCapsuleHeader->EmbeddedDriverCount
 | |
|                  );
 | |
|       if (Status != EFI_SUCCESS) {
 | |
|         Abort = TRUE;
 | |
|       }
 | |
| 
 | |
|       RecordFmpCapsuleStatus (
 | |
|         HandleBuffer[Index2],
 | |
|         CapsuleHeader,
 | |
|         Status,
 | |
|         Index - FmpCapsuleHeader->EmbeddedDriverCount,
 | |
|         ImageHeader
 | |
|         );
 | |
|     }
 | |
|     if (HandleBuffer != NULL) {
 | |
|       FreePool(HandleBuffer);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   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_TABLE  *Esrt;
 | |
|   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 ESRT configuration table
 | |
|     //
 | |
|     if (!EsrtGuidFound) {
 | |
|       Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
 | |
|       if (!EFI_ERROR(Status)) {
 | |
|         ASSERT (Esrt != NULL);
 | |
|         EsrtEntry = (VOID *)(Esrt + 1);
 | |
|         for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
 | |
|           if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
 | |
|             EsrtGuidFound = TRUE;
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   if (IsFmpCapsule(CapsuleHeader)) {
 | |
|     //
 | |
|     // 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.
 | |
| 
 | |
|   @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
 | |
|   )
 | |
| {
 | |
|   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;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Press EFI FMP Capsule
 | |
|     //
 | |
|     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
 | |
|     Status = ProcessFmpCapsuleImage(CapsuleHeader);
 | |
|     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
 | |
| 
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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;
 | |
| }
 |