]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleLib.c
index 3ba3b9c9ccd20e1dd22d66815ba3d317917bd4a8..f38ab69e38fb22543d37c62aa0a331c3637b7609 100644 (file)
@@ -7,23 +7,16 @@
   buffer overflow, integer overflow.\r
 \r
   SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),\r
-  ValidateFmpCapsule(), DisplayCapsuleImage(), ConvertBmpToGopBlt() will\r
-  receive untrusted input and do basic validation.\r
+  ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and\r
+  performs basic validation.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
-  This program and the accompanying materials\r
-  are licensed and made available under the terms and conditions of the BSD License\r
-  which accompanies this distribution.  The full text of the license may be found at\r
-  http://opensource.org/licenses/bsd-license.php\r
-\r
-  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include <PiDxe.h>\r
 \r
-#include <IndustryStandard/Bmp.h>\r
 #include <IndustryStandard/WindowsUxCapsule.h>\r
 \r
 #include <Guid/FmpCapsule.h>\r
 #include <Library/CapsuleLib.h>\r
 #include <Library/DevicePathLib.h>\r
 #include <Library/UefiLib.h>\r
-#include <Library/PcdLib.h>\r
+#include <Library/BmpSupportLib.h>\r
 \r
 #include <Protocol/GraphicsOutput.h>\r
 #include <Protocol/EsrtManagement.h>\r
 #include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/FirmwareManagementProgress.h>\r
 #include <Protocol/DevicePath.h>\r
 \r
-BOOLEAN            mAreAllImagesProcessed;\r
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable                  = NULL;\r
+BOOLEAN                   mIsVirtualAddrConverted      = FALSE;\r
+\r
+BOOLEAN                   mDxeCapsuleLibEndOfDxe       = FALSE;\r
+EFI_EVENT                 mDxeCapsuleLibEndOfDxeEvent  = NULL;\r
 \r
-EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable              = NULL;\r
-BOOLEAN                   mIsVirtualAddrConverted  = FALSE;\r
-BOOLEAN                   mDxeCapsuleLibEndOfDxe   = FALSE;\r
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *mFmpProgress = NULL;\r
 \r
 /**\r
   Initialize capsule related variables.\r
@@ -61,23 +57,6 @@ InitCapsuleVariable (
   VOID\r
   );\r
 \r
-/**\r
-  Check if this FMP capsule is processed.\r
-\r
-  @param[in] CapsuleHeader  The capsule image header\r
-  @param[in] PayloadIndex   FMP payload index\r
-  @param[in] ImageHeader    FMP image header\r
-\r
-  @retval TRUE  This FMP capsule is processed.\r
-  @retval FALSE This FMP capsule is not processed.\r
-**/\r
-BOOLEAN\r
-IsFmpCapsuleProcessed (\r
-  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,\r
-  IN UINTN                                         PayloadIndex,\r
-  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader\r
-  );\r
-\r
 /**\r
   Record capsule status variable.\r
 \r
@@ -100,6 +79,7 @@ RecordCapsuleStatusVariable (
   @param[in] CapsuleStatus  The capsule process stauts\r
   @param[in] PayloadIndex   FMP payload index\r
   @param[in] ImageHeader    FMP image header\r
+  @param[in] FmpDevicePath  DevicePath associated with the FMP producer\r
 \r
   @retval EFI_SUCCESS          The capsule status variable is recorded.\r
   @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
@@ -109,25 +89,25 @@ RecordFmpCapsuleStatusVariable (
   IN EFI_CAPSULE_HEADER                            *CapsuleHeader,\r
   IN EFI_STATUS                                    CapsuleStatus,\r
   IN UINTN                                         PayloadIndex,\r
-  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader\r
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader,\r
+  IN EFI_DEVICE_PATH_PROTOCOL                      *FmpDevicePath OPTIONAL\r
   );\r
 \r
 /**\r
   Function indicate the current completion progress of the firmware\r
   update. Platform may override with own specific progress function.\r
 \r
-  @param[in]  Completion    A value between 1 and 100 indicating the current completion progress of the firmware update\r
+  @param[in]  Completion  A value between 1 and 100 indicating the current\r
+                          completion progress of the firmware update\r
 \r
-  @retval EFI_SUCESS    Input capsule is a correct FMP capsule.\r
+  @retval EFI_SUCESS             The capsule update progress was updated.\r
+  @retval EFI_INVALID_PARAMETER  Completion is greater than 100%.\r
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-Update_Image_Progress (\r
+UpdateImageProgress (\r
   IN UINTN  Completion\r
-  )\r
-{\r
-  return EFI_SUCCESS;\r
-}\r
+  );\r
 \r
 /**\r
   Return if this CapsuleGuid is a FMP capsule GUID or not.\r
@@ -265,7 +245,7 @@ ValidateFmpCapsule (
     //\r
     if (Index > 0) {\r
       if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {\r
-        DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));\r
+        DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));\r
         return EFI_INVALID_PARAMETER;\r
       }\r
     }\r
@@ -281,10 +261,6 @@ ValidateFmpCapsule (
     }\r
     FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];\r
 \r
-    if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {\r
-      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
     FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);\r
     if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||\r
         (ImageHeader->Version < 1)) {\r
@@ -294,6 +270,10 @@ ValidateFmpCapsule (
     if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
       FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
     }\r
+    if (FmpImageSize < FmpImageHeaderSize) {\r
+      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
 \r
     // No overflow\r
     if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {\r
@@ -321,262 +301,6 @@ ValidateFmpCapsule (
   return EFI_SUCCESS;\r
 }\r
 \r
-/**\r
-  Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer\r
-  is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt\r
-  buffer is passed in it will be used if it is big enough.\r
-\r
-  Caution: This function may receive untrusted input.\r
-\r
-  @param[in]       BmpImage      Pointer to BMP file\r
-  @param[in]       BmpImageSize  Number of bytes in BmpImage\r
-  @param[in, out]  GopBlt        Buffer containing GOP version of BmpImage.\r
-  @param[in, out]  GopBltSize    Size of GopBlt in bytes.\r
-  @param[out]      PixelHeight   Height of GopBlt/BmpImage in pixels\r
-  @param[out]      PixelWidth    Width of GopBlt/BmpImage in pixels\r
-\r
-  @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.\r
-  @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image\r
-  @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.\r
-                                GopBltSize will contain the required size.\r
-  @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.\r
-\r
-**/\r
-STATIC\r
-EFI_STATUS\r
-ConvertBmpToGopBlt (\r
-  IN     VOID      *BmpImage,\r
-  IN     UINTN     BmpImageSize,\r
-  IN OUT VOID      **GopBlt,\r
-  IN OUT UINTN     *GopBltSize,\r
-     OUT UINTN     *PixelHeight,\r
-     OUT UINTN     *PixelWidth\r
-  )\r
-{\r
-  UINT8                         *Image;\r
-  UINT8                         *ImageHeader;\r
-  BMP_IMAGE_HEADER              *BmpHeader;\r
-  BMP_COLOR_MAP                 *BmpColorMap;\r
-  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;\r
-  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;\r
-  UINT64                        BltBufferSize;\r
-  UINTN                         Index;\r
-  UINTN                         Height;\r
-  UINTN                         Width;\r
-  UINTN                         ImageIndex;\r
-  UINT32                        DataSizePerLine;\r
-  BOOLEAN                       IsAllocated;\r
-  UINT32                        ColorMapNum;\r
-\r
-  if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;\r
-\r
-  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // Doesn't support compress.\r
-  //\r
-  if (BmpHeader->CompressionType != 0) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // Only support BITMAPINFOHEADER format.\r
-  // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER\r
-  //\r
-  if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-\r
-  //\r
-  // The data size in each line must be 4 byte alignment.\r
-  //\r
-  DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);\r
-  BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);\r
-  if (BltBufferSize > (UINT32) ~0) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if ((BmpHeader->Size != BmpImageSize) ||\r
-      (BmpHeader->Size < BmpHeader->ImageOffset) ||\r
-      (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  //\r
-  // Calculate Color Map offset in the image.\r
-  //\r
-  Image       = BmpImage;\r
-  BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));\r
-  if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-\r
-  if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {\r
-    switch (BmpHeader->BitPerPixel) {\r
-      case 1:\r
-        ColorMapNum = 2;\r
-        break;\r
-      case 4:\r
-        ColorMapNum = 16;\r
-        break;\r
-      case 8:\r
-        ColorMapNum = 256;\r
-        break;\r
-      default:\r
-        ColorMapNum = 0;\r
-        break;\r
-      }\r
-    //\r
-    // BMP file may has padding data between the bmp header section and the bmp data section.\r
-    //\r
-    if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {\r
-      return EFI_INVALID_PARAMETER;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Calculate graphics image data address in the image\r
-  //\r
-  Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;\r
-  ImageHeader   = Image;\r
-\r
-  //\r
-  // Calculate the BltBuffer needed size.\r
-  //\r
-  BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);\r
-  //\r
-  // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow\r
-  //\r
-  if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {\r
-    return EFI_UNSUPPORTED;\r
-  }\r
-  BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));\r
-\r
-  IsAllocated   = FALSE;\r
-  if (*GopBlt == NULL) {\r
-    //\r
-    // GopBlt is not allocated by caller.\r
-    //\r
-    *GopBltSize = (UINTN) BltBufferSize;\r
-    *GopBlt     = AllocatePool (*GopBltSize);\r
-    IsAllocated = TRUE;\r
-    if (*GopBlt == NULL) {\r
-      return EFI_OUT_OF_RESOURCES;\r
-    }\r
-  } else {\r
-    //\r
-    // GopBlt has been allocated by caller.\r
-    //\r
-    if (*GopBltSize < (UINTN) BltBufferSize) {\r
-      *GopBltSize = (UINTN) BltBufferSize;\r
-      return EFI_BUFFER_TOO_SMALL;\r
-    }\r
-  }\r
-\r
-  *PixelWidth   = BmpHeader->PixelWidth;\r
-  *PixelHeight  = BmpHeader->PixelHeight;\r
-\r
-  //\r
-  // Convert image from BMP to Blt buffer format\r
-  //\r
-  BltBuffer = *GopBlt;\r
-  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {\r
-    Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];\r
-    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {\r
-      switch (BmpHeader->BitPerPixel) {\r
-      case 1:\r
-        //\r
-        // Convert 1-bit (2 colors) BMP to 24-bit color\r
-        //\r
-        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {\r
-          Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;\r
-          Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;\r
-          Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;\r
-          Blt++;\r
-          Width++;\r
-        }\r
-\r
-        Blt--;\r
-        Width--;\r
-        break;\r
-\r
-      case 4:\r
-        //\r
-        // Convert 4-bit (16 colors) BMP Palette to 24-bit color\r
-        //\r
-        Index       = (*Image) >> 4;\r
-        Blt->Red    = BmpColorMap[Index].Red;\r
-        Blt->Green  = BmpColorMap[Index].Green;\r
-        Blt->Blue   = BmpColorMap[Index].Blue;\r
-        if (Width < (BmpHeader->PixelWidth - 1)) {\r
-          Blt++;\r
-          Width++;\r
-          Index       = (*Image) & 0x0f;\r
-          Blt->Red    = BmpColorMap[Index].Red;\r
-          Blt->Green  = BmpColorMap[Index].Green;\r
-          Blt->Blue   = BmpColorMap[Index].Blue;\r
-        }\r
-        break;\r
-\r
-      case 8:\r
-        //\r
-        // Convert 8-bit (256 colors) BMP Palette to 24-bit color\r
-        //\r
-        Blt->Red    = BmpColorMap[*Image].Red;\r
-        Blt->Green  = BmpColorMap[*Image].Green;\r
-        Blt->Blue   = BmpColorMap[*Image].Blue;\r
-        break;\r
-\r
-      case 24:\r
-        //\r
-        // It is 24-bit BMP.\r
-        //\r
-        Blt->Blue   = *Image++;\r
-        Blt->Green  = *Image++;\r
-        Blt->Red    = *Image;\r
-        break;\r
-\r
-      case 32:\r
-        //\r
-        // it is 32-bit BMP. Skip pixel's highest byte\r
-        //\r
-        Blt->Blue  = *Image++;\r
-        Blt->Green = *Image++;\r
-        Blt->Red   = *Image++;\r
-        break;\r
-\r
-      default:\r
-        //\r
-        // Other bit format BMP is not supported.\r
-        //\r
-        if (IsAllocated) {\r
-          FreePool (*GopBlt);\r
-          *GopBlt = NULL;\r
-        }\r
-        return EFI_UNSUPPORTED;\r
-      };\r
-\r
-    }\r
-\r
-    ImageIndex = (UINTN) (Image - ImageHeader);\r
-    if ((ImageIndex % 4) != 0) {\r
-      //\r
-      // Bmp Image starts each row on a 32-bit boundary!\r
-      //\r
-      Image = Image + (4 - (ImageIndex % 4));\r
-    }\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-\r
 /**\r
   Those capsules supported by the firmwares.\r
 \r
@@ -601,8 +325,25 @@ DisplayCapsuleImage (
   UINTN                         Width;\r
   EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;\r
 \r
-  ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);\r
-  PayloadSize = (UINTN)(CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER));\r
+  //\r
+  // UX capsule doesn't have extended header entries.\r
+  //\r
+  if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+  //\r
+  // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().\r
+  //\r
+  PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;\r
+\r
+  //\r
+  // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.\r
+  // Further size check is performed by the logic translating BMP to GOP BLT.\r
+  //\r
+  if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
 \r
   if (ImagePayload->Version != 1) {\r
     return EFI_UNSUPPORTED;\r
@@ -635,10 +376,10 @@ DisplayCapsuleImage (
   Blt = NULL;\r
   Width = 0;\r
   Height = 0;\r
-  Status = ConvertBmpToGopBlt (\r
+  Status = TranslateBmpToGopBlt (\r
              ImagePayload + 1,\r
              PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),\r
-             (VOID **)&Blt,\r
+             &Blt,\r
              &BltSize,\r
              &Height,\r
              &Width\r
@@ -750,7 +491,7 @@ DumpFmpCapsule (
   for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
     DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));\r
   }\r
-  for (; Index < (UINTN)(FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount); Index++) {\r
+  for (; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {\r
     DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));\r
     ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
 \r
@@ -767,355 +508,780 @@ DumpFmpCapsule (
 }\r
 \r
 /**\r
-  Process Firmware management protocol data capsule.\r
-\r
-  This function assumes the caller validated the capsule by using\r
-  ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,\r
-  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and\r
-  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.\r
-\r
-  This function need support nested FMP capsule.\r
-\r
-  @param[in]   CapsuleHeader         Points to a capsule header.\r
-  @param[out]  AreAllImagesProcessed If all the FMP images in the capsule are processed.\r
-\r
-  @retval EFI_SUCESS            Process Capsule Image successfully.\r
-  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
-  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.\r
-  @retval EFI_OUT_OF_RESOURCES  Not enough memory.\r
+  Dump all FMP information.\r
 **/\r
-EFI_STATUS\r
-ProcessFmpCapsuleImage (\r
-  IN EFI_CAPSULE_HEADER  *CapsuleHeader,\r
-  OUT BOOLEAN            *AreAllImagesProcessed\r
+VOID\r
+DumpAllFmpInfo (\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS                                    Status;\r
-  EFI_STATUS                                    StatusEsrt;\r
-  EFI_STATUS                                    StatusRet;\r
-  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;\r
-  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;\r
-  UINT8                                         *Image;\r
-  EFI_HANDLE                                    ImageHandle;\r
-  UINT64                                        *ItemOffsetList;\r
-  UINT32                                        ItemNum;\r
-  UINTN                                         Index;\r
-  UINTN                                         ExitDataSize;\r
   EFI_HANDLE                                    *HandleBuffer;\r
-  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
   UINTN                                         NumberOfHandles;\r
-  UINTN                                         DescriptorSize;\r
-  UINT8                                         FmpImageInfoCount;\r
-  UINT32                                        FmpImageInfoDescriptorVer;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  UINTN                                         Index;\r
   UINTN                                         ImageInfoSize;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;\r
+  UINT32                                        FmpImageInfoDescriptorVer;\r
+  UINT8                                         FmpImageInfoCount;\r
+  UINTN                                         DescriptorSize;\r
   UINT32                                        PackageVersion;\r
   CHAR16                                        *PackageVersionName;\r
-  CHAR16                                        *AbortReason;\r
-  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;\r
-  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;\r
-  UINTN                                         DriverLen;\r
-  UINTN                                         Index1;\r
-  UINTN                                         Index2;\r
-  MEMMAP_DEVICE_PATH                            MemMapNode;\r
-  EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;\r
-  ESRT_MANAGEMENT_PROTOCOL                      *EsrtProtocol;\r
-  EFI_SYSTEM_RESOURCE_ENTRY                     EsrtEntry;\r
-  VOID                                          *VendorCode;\r
 \r
-  if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
-    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), AreAllImagesProcessed);\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  NULL,\r
+                  &NumberOfHandles,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return ;\r
   }\r
 \r
-  ASSERT(AreAllImagesProcessed != NULL);\r
+  for (Index = 0; Index < NumberOfHandles; Index++) {\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareManagementProtocolGuid,\r
+                    (VOID **)&Fmp\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
 \r
-  Status           = EFI_SUCCESS;\r
-  StatusRet        = EFI_NOT_FOUND;\r
-  HandleBuffer     = NULL;\r
-  ExitDataSize     = 0;\r
-  DriverDevicePath = NULL;\r
-  EsrtProtocol     = NULL;\r
-  *AreAllImagesProcessed = FALSE;\r
+    ImageInfoSize = 0;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL\r
+                    );\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      continue;\r
+    }\r
 \r
-  DumpFmpCapsule(CapsuleHeader);\r
+    FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+    if (FmpImageInfoBuf == NULL) {\r
+      continue;\r
+    }\r
 \r
-  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+    PackageVersionName = NULL;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,               // ImageInfoSize\r
+                    FmpImageInfoBuf,              // ImageInfo\r
+                    &FmpImageInfoDescriptorVer,   // DescriptorVersion\r
+                    &FmpImageInfoCount,           // DescriptorCount\r
+                    &DescriptorSize,              // DescriptorSize\r
+                    &PackageVersion,              // PackageVersion\r
+                    &PackageVersionName           // PackageVersionName\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      FreePool(FmpImageInfoBuf);\r
+      continue;\r
+    }\r
 \r
-  if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
-    return EFI_INVALID_PARAMETER;\r
+    DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));\r
+    DumpFmpImageInfo(\r
+      ImageInfoSize,               // ImageInfoSize\r
+      FmpImageInfoBuf,             // ImageInfo\r
+      FmpImageInfoDescriptorVer,   // DescriptorVersion\r
+      FmpImageInfoCount,           // DescriptorCount\r
+      DescriptorSize,              // DescriptorSize\r
+      PackageVersion,              // PackageVersion\r
+      PackageVersionName           // PackageVersionName\r
+      );\r
+\r
+    if (PackageVersionName != NULL) {\r
+      FreePool(PackageVersionName);\r
+    }\r
+\r
+    FreePool(FmpImageInfoBuf);\r
   }\r
-  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
 \r
-  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
+  FreePool (HandleBuffer);\r
 \r
-  //\r
-  // capsule in which driver count and payload count are both zero is not processed.\r
-  //\r
-  if (ItemNum == 0) {\r
-    *AreAllImagesProcessed = TRUE;\r
-    return EFI_SUCCESS;\r
+  return ;\r
+}\r
+\r
+/**\r
+  Get FMP handle by ImageTypeId and HardwareInstance.\r
+\r
+  @param[in]     UpdateImageTypeId       Used to identify device firmware targeted by this update.\r
+  @param[in]     UpdateHardwareInstance  The HardwareInstance to target with this update.\r
+  @param[out]    NoHandles               The number of handles returned in HandleBuf.\r
+  @param[out]    HandleBuf               A pointer to the buffer to return the requested array of handles.\r
+  @param[out]    ResetRequiredBuf        A pointer to the buffer to return reset required flag for\r
+                                         the requested array of handles.\r
+\r
+  @retval EFI_SUCCESS            The array of handles and their reset required flag were returned in\r
+                                 HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf\r
+                                 was returned in NoHandles.\r
+  @retval EFI_NOT_FOUND          No handles match the search.\r
+  @retval EFI_OUT_OF_RESOURCES   There is not enough pool memory to store the matching results.\r
+**/\r
+EFI_STATUS\r
+GetFmpHandleBufferByType (\r
+  IN     EFI_GUID                     *UpdateImageTypeId,\r
+  IN     UINT64                       UpdateHardwareInstance,\r
+  OUT    UINTN                        *NoHandles, OPTIONAL\r
+  OUT    EFI_HANDLE                   **HandleBuf, OPTIONAL\r
+  OUT    BOOLEAN                      **ResetRequiredBuf OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_HANDLE                                    *HandleBuffer;\r
+  UINTN                                         NumberOfHandles;\r
+  EFI_HANDLE                                    *MatchedHandleBuffer;\r
+  BOOLEAN                                       *MatchedResetRequiredBuffer;\r
+  UINTN                                         MatchedNumberOfHandles;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  UINTN                                         Index;\r
+  UINTN                                         ImageInfoSize;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;\r
+  UINT32                                        FmpImageInfoDescriptorVer;\r
+  UINT8                                         FmpImageInfoCount;\r
+  UINTN                                         DescriptorSize;\r
+  UINT32                                        PackageVersion;\r
+  CHAR16                                        *PackageVersionName;\r
+  UINTN                                         Index2;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;\r
+\r
+  if (NoHandles != NULL) {\r
+    *NoHandles = 0;\r
+  }\r
+  if (HandleBuf != NULL) {\r
+    *HandleBuf = NULL;\r
+  }\r
+  if (ResetRequiredBuf != NULL) {\r
+    *ResetRequiredBuf = NULL;\r
   }\r
 \r
-  //\r
-  // Update corresponding ESRT entry LastAttemp Status\r
-  //\r
-  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
-  if (EFI_ERROR (Status)) {\r
-    EsrtProtocol = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  NULL,\r
+                  &NumberOfHandles,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
   }\r
 \r
-  //\r
-  // 1. Try to load & start all the drivers within capsule\r
-  //\r
-  SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));\r
-  MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;\r
-  MemMapNode.Header.SubType  = HW_MEMMAP_DP;\r
-  MemMapNode.MemoryType      = EfiBootServicesCode;\r
-  MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;\r
-  MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);\r
+  MatchedNumberOfHandles = 0;\r
 \r
-  DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);\r
-  if (DriverDevicePath == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
+  MatchedHandleBuffer = NULL;\r
+  if (HandleBuf != NULL) {\r
+    MatchedHandleBuffer = AllocateZeroPool (sizeof(EFI_HANDLE) * NumberOfHandles);\r
+    if (MatchedHandleBuffer == NULL) {\r
+      FreePool (HandleBuffer);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
   }\r
 \r
-  for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
-    if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {\r
-      //\r
-      // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER\r
-      //\r
-      DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];\r
-    } else {\r
-      DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];\r
+  MatchedResetRequiredBuffer = NULL;\r
+  if (ResetRequiredBuf != NULL) {\r
+    MatchedResetRequiredBuffer = AllocateZeroPool (sizeof(BOOLEAN) * NumberOfHandles);\r
+    if (MatchedResetRequiredBuffer == NULL) {\r
+      if (MatchedHandleBuffer != NULL) {\r
+        FreePool (MatchedHandleBuffer);\r
+      }\r
+      FreePool (HandleBuffer);\r
+      return EFI_OUT_OF_RESOURCES;\r
     }\r
+  }\r
 \r
-    DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));\r
-    Status = gBS->LoadImage(\r
-                    FALSE,\r
-                    gImageHandle,\r
-                    DriverDevicePath,\r
-                    (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],\r
-                    DriverLen,\r
-                    &ImageHandle\r
+  for (Index = 0; Index < NumberOfHandles; Index++) {\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\r
+                    &gEfiFirmwareManagementProtocolGuid,\r
+                    (VOID **)&Fmp\r
                     );\r
-    DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));\r
     if (EFI_ERROR(Status)) {\r
-      StatusRet = Status;\r
-      goto EXIT;\r
+      continue;\r
     }\r
 \r
-    DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));\r
-    Status = gBS->StartImage(\r
-                    ImageHandle,\r
-                    &ExitDataSize,\r
+    ImageInfoSize = 0;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
+                    NULL,\r
                     NULL\r
                     );\r
-    DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));\r
+    if (Status != EFI_BUFFER_TOO_SMALL) {\r
+      continue;\r
+    }\r
+\r
+    FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+    if (FmpImageInfoBuf == NULL) {\r
+      continue;\r
+    }\r
+\r
+    PackageVersionName = NULL;\r
+    Status = Fmp->GetImageInfo (\r
+                    Fmp,\r
+                    &ImageInfoSize,               // ImageInfoSize\r
+                    FmpImageInfoBuf,              // ImageInfo\r
+                    &FmpImageInfoDescriptorVer,   // DescriptorVersion\r
+                    &FmpImageInfoCount,           // DescriptorCount\r
+                    &DescriptorSize,              // DescriptorSize\r
+                    &PackageVersion,              // PackageVersion\r
+                    &PackageVersionName           // PackageVersionName\r
+                    );\r
     if (EFI_ERROR(Status)) {\r
-      DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
-      StatusRet = Status;\r
-      goto EXIT;\r
+      FreePool(FmpImageInfoBuf);\r
+      continue;\r
+    }\r
+\r
+    if (PackageVersionName != NULL) {\r
+      FreePool(PackageVersionName);\r
     }\r
+\r
+    TempFmpImageInfo = FmpImageInfoBuf;\r
+    for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {\r
+      //\r
+      // Check if this FMP instance matches\r
+      //\r
+      if (CompareGuid(UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {\r
+        if ((UpdateHardwareInstance == 0) ||\r
+            ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&\r
+             (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance))) {\r
+          if (MatchedHandleBuffer != NULL) {\r
+            MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];\r
+          }\r
+          if (MatchedResetRequiredBuffer != NULL) {\r
+            MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &\r
+                                                                 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&\r
+                                                                 ((TempFmpImageInfo->AttributesSetting &\r
+                                                                 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));\r
+          }\r
+          MatchedNumberOfHandles++;\r
+          break;\r
+        }\r
+      }\r
+      TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);\r
+    }\r
+    FreePool(FmpImageInfoBuf);\r
   }\r
 \r
-  //\r
-  // 2. Route payload to right FMP instance\r
-  //\r
-  DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));\r
+  FreePool (HandleBuffer);\r
 \r
-  Status = gBS->LocateHandleBuffer (\r
-                  ByProtocol,\r
+  if (MatchedNumberOfHandles == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (NoHandles != NULL) {\r
+    *NoHandles = MatchedNumberOfHandles;\r
+  }\r
+  if (HandleBuf != NULL) {\r
+    *HandleBuf = MatchedHandleBuffer;\r
+  }\r
+  if (ResetRequiredBuf != NULL) {\r
+    *ResetRequiredBuf = MatchedResetRequiredBuffer;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return FmpImageInfoDescriptorVer by an FMP handle.\r
+\r
+  @param[in]  Handle   A FMP handle.\r
+\r
+  @return FmpImageInfoDescriptorVer associated with the FMP.\r
+**/\r
+UINT32\r
+GetFmpImageInfoDescriptorVer (\r
+  IN EFI_HANDLE                                   Handle\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  UINTN                                         ImageInfoSize;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;\r
+  UINT32                                        FmpImageInfoDescriptorVer;\r
+  UINT8                                         FmpImageInfoCount;\r
+  UINTN                                         DescriptorSize;\r
+  UINT32                                        PackageVersion;\r
+  CHAR16                                        *PackageVersionName;\r
+\r
+  Status = gBS->HandleProtocol(\r
+                  Handle,\r
                   &gEfiFirmwareManagementProtocolGuid,\r
+                  (VOID **)&Fmp\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return 0;\r
+  }\r
+\r
+  ImageInfoSize = 0;\r
+  Status = Fmp->GetImageInfo (\r
+                  Fmp,\r
+                  &ImageInfoSize,\r
                   NULL,\r
-                  &NumberOfHandles,\r
-                  &HandleBuffer\r
+                  NULL,\r
+                  NULL,\r
+                  NULL,\r
+                  NULL,\r
+                  NULL\r
                   );\r
+  if (Status != EFI_BUFFER_TOO_SMALL) {\r
+    return 0;\r
+  }\r
 \r
-  if (!EFI_ERROR(Status)) {\r
-    for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {\r
-      Status = gBS->HandleProtocol(\r
-                      HandleBuffer[Index1],\r
-                      &gEfiFirmwareManagementProtocolGuid,\r
-                      (VOID **)&Fmp\r
-                      );\r
-      if (EFI_ERROR(Status)) {\r
-        continue;\r
-      }\r
+  FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+  if (FmpImageInfoBuf == NULL) {\r
+    return 0;\r
+  }\r
 \r
-      ImageInfoSize = 0;\r
-      Status = Fmp->GetImageInfo (\r
-                      Fmp,\r
-                      &ImageInfoSize,\r
-                      NULL,\r
-                      NULL,\r
-                      NULL,\r
-                      NULL,\r
-                      NULL,\r
-                      NULL\r
-                      );\r
-      if (Status != EFI_BUFFER_TOO_SMALL) {\r
-        continue;\r
-      }\r
+  PackageVersionName = NULL;\r
+  Status = Fmp->GetImageInfo (\r
+                  Fmp,\r
+                  &ImageInfoSize,               // ImageInfoSize\r
+                  FmpImageInfoBuf,              // ImageInfo\r
+                  &FmpImageInfoDescriptorVer,   // DescriptorVersion\r
+                  &FmpImageInfoCount,           // DescriptorCount\r
+                  &DescriptorSize,              // DescriptorSize\r
+                  &PackageVersion,              // PackageVersion\r
+                  &PackageVersionName           // PackageVersionName\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool(FmpImageInfoBuf);\r
+    return 0;\r
+  }\r
+  return FmpImageInfoDescriptorVer;\r
+}\r
 \r
-      FmpImageInfoBuf = NULL;\r
-      FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
-      if (FmpImageInfoBuf == NULL) {\r
-        StatusRet = EFI_OUT_OF_RESOURCES;\r
-        goto EXIT;\r
-      }\r
+/**\r
+  Set FMP image data.\r
 \r
-      PackageVersionName = NULL;\r
-      Status = Fmp->GetImageInfo (\r
-                      Fmp,\r
-                      &ImageInfoSize,               // ImageInfoSize\r
-                      FmpImageInfoBuf,              // ImageInfo\r
-                      &FmpImageInfoDescriptorVer,   // DescriptorVersion\r
-                      &FmpImageInfoCount,           // DescriptorCount\r
-                      &DescriptorSize,              // DescriptorSize\r
-                      &PackageVersion,              // PackageVersion\r
-                      &PackageVersionName           // PackageVersionName\r
-                      );\r
+  @param[in]  Handle        A FMP handle.\r
+  @param[in]  ImageHeader   The payload image header.\r
+  @param[in]  PayloadIndex  The index of the payload.\r
 \r
-      //\r
-      // If FMP GetInformation interface failed, skip this resource\r
-      //\r
-      if (EFI_ERROR(Status)) {\r
-        FreePool(FmpImageInfoBuf);\r
-        continue;\r
-      }\r
+  @return The status of FMP->SetImage.\r
+**/\r
+EFI_STATUS\r
+SetFmpImageData (\r
+  IN EFI_HANDLE                                   Handle,\r
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
+  IN UINTN                                        PayloadIndex\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  UINT8                                         *Image;\r
+  VOID                                          *VendorCode;\r
+  CHAR16                                        *AbortReason;\r
+  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;\r
 \r
-      DEBUG((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));\r
-      DumpFmpImageInfo(\r
-        ImageInfoSize,               // ImageInfoSize\r
-        FmpImageInfoBuf,             // ImageInfo\r
-        FmpImageInfoDescriptorVer,   // DescriptorVersion\r
-        FmpImageInfoCount,           // DescriptorCount\r
-        DescriptorSize,              // DescriptorSize\r
-        PackageVersion,              // PackageVersion\r
-        PackageVersionName           // PackageVersionName\r
-        );\r
+  Status = gBS->HandleProtocol(\r
+                  Handle,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  (VOID **)&Fmp\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
 \r
-      if (PackageVersionName != NULL) {\r
-        FreePool(PackageVersionName);\r
-      }\r
+  //\r
+  // Lookup Firmware Management Progress Protocol before SetImage() is called\r
+  // This is an optional protocol that may not be present on Handle.\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEdkiiFirmwareManagementProgressProtocolGuid,\r
+                  (VOID **)&mFmpProgress\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    mFmpProgress = NULL;\r
+  }\r
 \r
-      TempFmpImageInfo = FmpImageInfoBuf;\r
-      for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {\r
-        //\r
-        // Check all the payload entry in capsule payload list\r
-        //\r
-        for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
-          ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
-\r
-          if (IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {\r
-            DEBUG((DEBUG_INFO, "FMP Capsule already processed (%g):", CapsuleHeader));\r
-            DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));\r
-            DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ImageIndex - 0x%x\n", Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader->UpdateImageIndex));\r
-            continue;\r
-          }\r
+  if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+    Image = (UINT8 *)(ImageHeader + 1);\r
+  } else {\r
+    //\r
+    // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,\r
+    // Header should exclude UpdateHardwareInstance field\r
+    //\r
+    Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
+  }\r
 \r
-          if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&\r
-              ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {\r
-            AbortReason = NULL;\r
-            if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
-              if(ImageHeader->UpdateHardwareInstance != 0){\r
-                //\r
-                // FMP Version is >=2 & UpdateHardwareInstance Skip 2 case\r
-                //  1. FMP Image info Version < 3\r
-                //  2. HardwareInstance doesn't match\r
-                //\r
-                if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION ||\r
-                   ImageHeader->UpdateHardwareInstance != TempFmpImageInfo->HardwareInstance) {\r
-                  continue;\r
-                }\r
-              }\r
-              Image = (UINT8 *)(ImageHeader + 1);\r
-            } else {\r
-              //\r
-              // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.\r
-              // Header should exclude UpdateHardwareInstance field\r
-              //\r
-              Image = (UINT8 *)ImageHeader + OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r
-            }\r
-\r
-            if (ImageHeader->UpdateVendorCodeSize == 0) {\r
-              VendorCode = NULL;\r
-            } else {\r
-              VendorCode = Image + ImageHeader->UpdateImageSize;\r
-            }\r
-            DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));\r
-            Status = Fmp->SetImage(\r
-                            Fmp,\r
-                            ImageHeader->UpdateImageIndex,          // ImageIndex\r
-                            Image,                                  // Image\r
-                            ImageHeader->UpdateImageSize,           // ImageSize\r
-                            VendorCode,                                   // VendorCode\r
-                            Update_Image_Progress,                  // Progress\r
-                            &AbortReason                            // AbortReason\r
-                            );\r
-            DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));\r
-            if (AbortReason != NULL) {\r
-              DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));\r
-              FreePool(AbortReason);\r
-            }\r
-            RecordFmpCapsuleStatusVariable(\r
-              CapsuleHeader,                                 // CapsuleGuid\r
-              Status,                                        // CapsuleStatus\r
-              Index - FmpCapsuleHeader->EmbeddedDriverCount, // PayloadIndex\r
-              ImageHeader                                    // ImageHeader\r
-              );\r
-            if (StatusRet != EFI_SUCCESS) {\r
-              StatusRet = Status;\r
-            }\r
-            //\r
-            // Update EsrtEntry For V1, V2 FMP instance. V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface\r
-            //\r
-            if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION && EsrtProtocol != NULL) {\r
-               StatusEsrt = EsrtProtocol->GetEsrtEntry(&TempFmpImageInfo->ImageTypeId, &EsrtEntry);\r
-               if (!EFI_ERROR(StatusEsrt)){\r
-                 if (!EFI_ERROR(Status)) {\r
-                   EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
-                 } else {\r
-                   EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
-                 }\r
-                 EsrtEntry.LastAttemptVersion = 0;\r
-                 EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);\r
-               }\r
-             }\r
-          }\r
-        }\r
-        //\r
-        // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version\r
-        //\r
-        TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);\r
+  if (ImageHeader->UpdateVendorCodeSize == 0) {\r
+    VendorCode = NULL;\r
+  } else {\r
+    VendorCode = Image + ImageHeader->UpdateImageSize;\r
+  }\r
+  AbortReason = NULL;\r
+  DEBUG((DEBUG_INFO, "Fmp->SetImage ...\n"));\r
+  DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));\r
+  DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));\r
+  DEBUG((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));\r
+  if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+    DEBUG((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));\r
+  }\r
+  DEBUG((DEBUG_INFO, "\n"));\r
+\r
+  //\r
+  // Before calling SetImage(), reset the progress bar to 0%\r
+  //\r
+  ProgressCallback = UpdateImageProgress;\r
+  Status = UpdateImageProgress (0);\r
+  if (EFI_ERROR (Status)) {\r
+    ProgressCallback = NULL;\r
+  }\r
+\r
+  Status = Fmp->SetImage(\r
+                  Fmp,\r
+                  ImageHeader->UpdateImageIndex,          // ImageIndex\r
+                  Image,                                  // Image\r
+                  ImageHeader->UpdateImageSize,           // ImageSize\r
+                  VendorCode,                             // VendorCode\r
+                  ProgressCallback,                       // Progress\r
+                  &AbortReason                            // AbortReason\r
+                  );\r
+  //\r
+  // Set the progress bar to 100% after returning from SetImage()\r
+  //\r
+  if (ProgressCallback != NULL) {\r
+    UpdateImageProgress (100);\r
+  }\r
+\r
+  DEBUG((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));\r
+  if (AbortReason != NULL) {\r
+    DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));\r
+    FreePool(AbortReason);\r
+  }\r
+\r
+  //\r
+  // Clear mFmpProgress after SetImage() returns\r
+  //\r
+  mFmpProgress = NULL;\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Start a UEFI image in the FMP payload.\r
+\r
+  @param[in]  ImageBuffer   A pointer to the memory location containing a copy of the image to be loaded..\r
+  @param[in]  ImageSize     The size in bytes of ImageBuffer.\r
+\r
+  @return The status of gBS->LoadImage and gBS->StartImage.\r
+**/\r
+EFI_STATUS\r
+StartFmpImage (\r
+  IN VOID   *ImageBuffer,\r
+  IN UINTN  ImageSize\r
+  )\r
+{\r
+  MEMMAP_DEVICE_PATH                            MemMapNode;\r
+  EFI_STATUS                                    Status;\r
+  EFI_HANDLE                                    ImageHandle;\r
+  EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;\r
+  UINTN                                         ExitDataSize;\r
+\r
+  SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));\r
+  MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;\r
+  MemMapNode.Header.SubType  = HW_MEMMAP_DP;\r
+  MemMapNode.MemoryType      = EfiBootServicesCode;\r
+  MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;\r
+  MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);\r
+\r
+  DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);\r
+  if (DriverDevicePath == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));\r
+  Status = gBS->LoadImage(\r
+                  FALSE,\r
+                  gImageHandle,\r
+                  DriverDevicePath,\r
+                  ImageBuffer,\r
+                  ImageSize,\r
+                  &ImageHandle\r
+                  );\r
+  DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool(DriverDevicePath);\r
+    return Status;\r
+  }\r
+\r
+  DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));\r
+  Status = gBS->StartImage(\r
+                  ImageHandle,\r
+                  &ExitDataSize,\r
+                  NULL\r
+                  );\r
+  DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
+  }\r
+\r
+  FreePool(DriverDevicePath);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Record FMP capsule status.\r
+\r
+  @param[in]  Handle        A FMP handle.\r
+  @param[in] CapsuleHeader  The capsule image header\r
+  @param[in] CapsuleStatus  The capsule process stauts\r
+  @param[in] PayloadIndex   FMP payload index\r
+  @param[in] ImageHeader    FMP image header\r
+**/\r
+VOID\r
+RecordFmpCapsuleStatus (\r
+  IN EFI_HANDLE                                    Handle,  OPTIONAL\r
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,\r
+  IN EFI_STATUS                                    CapsuleStatus,\r
+  IN UINTN                                         PayloadIndex,\r
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_DEVICE_PATH_PROTOCOL                      *FmpDevicePath;\r
+  UINT32                                        FmpImageInfoDescriptorVer;\r
+  EFI_STATUS                                    StatusEsrt;\r
+  ESRT_MANAGEMENT_PROTOCOL                      *EsrtProtocol;\r
+  EFI_SYSTEM_RESOURCE_ENTRY                     EsrtEntry;\r
+\r
+  FmpDevicePath = NULL;\r
+  if (Handle != NULL) {\r
+    gBS->HandleProtocol(\r
+           Handle,\r
+           &gEfiDevicePathProtocolGuid,\r
+           (VOID **)&FmpDevicePath\r
+           );\r
+  }\r
+\r
+  RecordFmpCapsuleStatusVariable (\r
+    CapsuleHeader,\r
+    CapsuleStatus,\r
+    PayloadIndex,\r
+    ImageHeader,\r
+    FmpDevicePath\r
+    );\r
+\r
+  //\r
+  // Update corresponding ESRT entry LastAttemp Status\r
+  //\r
+  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  if (Handle == NULL) {\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Update EsrtEntry For V1, V2 FMP instance.\r
+  // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface\r
+  //\r
+  FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);\r
+  if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {\r
+    StatusEsrt = EsrtProtocol->GetEsrtEntry(&ImageHeader->UpdateImageTypeId, &EsrtEntry);\r
+    if (!EFI_ERROR(StatusEsrt)){\r
+      if (!EFI_ERROR(CapsuleStatus)) {\r
+        EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+      } else {\r
+        EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
       }\r
-      FreePool(FmpImageInfoBuf);\r
+      EsrtEntry.LastAttemptVersion = 0;\r
+      EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);\r
     }\r
   }\r
+}\r
+\r
+/**\r
+  Process Firmware management protocol data capsule.\r
+\r
+  This function assumes the caller validated the capsule by using\r
+  ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.\r
+\r
+  This function need support nested FMP capsule.\r
+\r
+  @param[in]  CapsuleHeader         Points to a capsule header.\r
+  @param[out] ResetRequired         Indicates whether reset is required or not.\r
+\r
+  @retval EFI_SUCESS            Process Capsule Image successfully.\r
+  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
+  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.\r
+  @retval EFI_NOT_READY         No FMP protocol to handle this FMP capsule.\r
+**/\r
+EFI_STATUS\r
+ProcessFmpCapsuleImage (\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,\r
+  OUT BOOLEAN            *ResetRequired OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;\r
+  UINT64                                        *ItemOffsetList;\r
+  UINT32                                        ItemNum;\r
+  UINTN                                         Index;\r
+  EFI_HANDLE                                    *HandleBuffer;\r
+  BOOLEAN                                       *ResetRequiredBuffer;\r
+  UINTN                                         NumberOfHandles;\r
+  UINTN                                         DriverLen;\r
+  UINT64                                        UpdateHardwareInstance;\r
+  UINTN                                         Index2;\r
+  BOOLEAN                                       NotReady;\r
+  BOOLEAN                                       Abort;\r
+\r
+  if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {\r
+    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), ResetRequired);\r
+  }\r
+\r
+  NotReady = FALSE;\r
+  Abort = FALSE;\r
+\r
+  DumpFmpCapsule(CapsuleHeader);\r
+\r
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);\r
+\r
+  if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+\r
+  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
 \r
   //\r
-  // final check for AreAllImagesProcessed\r
+  // capsule in which driver count and payload count are both zero is not processed.\r
   //\r
-  *AreAllImagesProcessed = TRUE;\r
-  for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
-    ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+  if (ItemNum == 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
 \r
-    if (!IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {\r
-      *AreAllImagesProcessed = FALSE;\r
-      break;\r
+  //\r
+  // 1. Try to load & start all the drivers within capsule\r
+  //\r
+  for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {\r
+    if ((FmpCapsuleHeader->PayloadItemCount == 0) &&\r
+        (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1)) {\r
+      //\r
+      // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER\r
+      //\r
+      DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];\r
+    } else {\r
+      DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];\r
+    }\r
+\r
+    Status = StartFmpImage (\r
+               (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],\r
+               DriverLen\r
+               );\r
+    if (EFI_ERROR(Status)) {\r
+      DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));\r
+      return Status;\r
     }\r
   }\r
 \r
-EXIT:\r
+  //\r
+  // 2. Route payload to right FMP instance\r
+  //\r
+  DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));\r
+\r
+  DumpAllFmpInfo ();\r
 \r
-  if (HandleBuffer != NULL) {\r
-    FreePool(HandleBuffer);\r
+  //\r
+  // Check all the payload entry in capsule payload list\r
+  //\r
+  for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r
+    ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+\r
+    UpdateHardwareInstance = 0;\r
+    if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+      UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;\r
+    }\r
+\r
+    Status = GetFmpHandleBufferByType (\r
+               &ImageHeader->UpdateImageTypeId,\r
+               UpdateHardwareInstance,\r
+               &NumberOfHandles,\r
+               &HandleBuffer,\r
+               &ResetRequiredBuffer\r
+               );\r
+    if (EFI_ERROR(Status) ||\r
+        (HandleBuffer == NULL) ||\r
+        (ResetRequiredBuffer == NULL)) {\r
+      NotReady = TRUE;\r
+      RecordFmpCapsuleStatus (\r
+        NULL,\r
+        CapsuleHeader,\r
+        EFI_NOT_READY,\r
+        Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
+        ImageHeader\r
+        );\r
+      continue;\r
+    }\r
+\r
+    for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {\r
+      if (Abort) {\r
+        RecordFmpCapsuleStatus (\r
+          HandleBuffer[Index2],\r
+          CapsuleHeader,\r
+          EFI_ABORTED,\r
+          Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
+          ImageHeader\r
+          );\r
+        continue;\r
+      }\r
+\r
+      Status = SetFmpImageData (\r
+                 HandleBuffer[Index2],\r
+                 ImageHeader,\r
+                 Index - FmpCapsuleHeader->EmbeddedDriverCount\r
+                 );\r
+      if (Status != EFI_SUCCESS) {\r
+        Abort = TRUE;\r
+      } else {\r
+        if (ResetRequired != NULL) {\r
+          *ResetRequired |= ResetRequiredBuffer[Index2];\r
+        }\r
+      }\r
+\r
+      RecordFmpCapsuleStatus (\r
+        HandleBuffer[Index2],\r
+        CapsuleHeader,\r
+        Status,\r
+        Index - FmpCapsuleHeader->EmbeddedDriverCount,\r
+        ImageHeader\r
+        );\r
+    }\r
+    if (HandleBuffer != NULL) {\r
+      FreePool(HandleBuffer);\r
+    }\r
+    if (ResetRequiredBuffer != NULL) {\r
+      FreePool(ResetRequiredBuffer);\r
+    }\r
   }\r
 \r
-  if (DriverDevicePath != NULL) {\r
-    FreePool(DriverDevicePath);\r
+  if (NotReady) {\r
+    return EFI_NOT_READY;\r
   }\r
 \r
-  return StatusRet;\r
+  //\r
+  // always return SUCCESS to indicate this capsule is processed.\r
+  // The status of SetImage is recorded in capsule result variable.\r
+  //\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
@@ -1132,7 +1298,6 @@ IsNestedFmpCapsule (
   )\r
 {\r
   EFI_STATUS                 Status;\r
-  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;\r
   EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;\r
   UINTN                      Index;\r
   BOOLEAN                    EsrtGuidFound;\r
@@ -1142,33 +1307,43 @@ IsNestedFmpCapsule (
   EFI_SYSTEM_RESOURCE_ENTRY  Entry;\r
 \r
   EsrtGuidFound = FALSE;\r
-\r
-  //\r
-  // Check ESRT protocol\r
-  //\r
-  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
-  if (!EFI_ERROR(Status)) {\r
-    Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);\r
-    if (!EFI_ERROR(Status)) {\r
-      EsrtGuidFound = TRUE;\r
-    }\r
-  }\r
-\r
-  //\r
-  // Check ESRT configuration table\r
-  //\r
-  if (!EsrtGuidFound) {\r
-    Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
-    if (!EFI_ERROR(Status)) {\r
-      ASSERT (Esrt != NULL);\r
-      EsrtEntry = (VOID *)(Esrt + 1);\r
-      for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
+  if (mIsVirtualAddrConverted) {\r
+    if(mEsrtTable != NULL) {\r
+      EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);\r
+      for (Index = 0; Index < mEsrtTable->FwResourceCount ; Index++, EsrtEntry++) {\r
         if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {\r
           EsrtGuidFound = TRUE;\r
           break;\r
         }\r
       }\r
     }\r
+  } else {\r
+    //\r
+    // Check ESRT protocol\r
+    //\r
+    Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);\r
+    if (!EFI_ERROR(Status)) {\r
+      Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);\r
+      if (!EFI_ERROR(Status)) {\r
+        EsrtGuidFound = TRUE;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Check Firmware Management Protocols\r
+    //\r
+    if (!EsrtGuidFound) {\r
+      Status = GetFmpHandleBufferByType (\r
+                 &CapsuleHeader->CapsuleGuid,\r
+                 0,\r
+                 NULL,\r
+                 NULL,\r
+                 NULL\r
+                 );\r
+      if (!EFI_ERROR(Status)) {\r
+        EsrtGuidFound = TRUE;\r
+      }\r
+    }\r
   }\r
   if (!EsrtGuidFound) {\r
     return FALSE;\r
@@ -1240,6 +1415,12 @@ SupportCapsuleImage (
   }\r
 \r
   if (IsFmpCapsule(CapsuleHeader)) {\r
+    //\r
+    // Fake capsule header is valid case in QueryCapsuleCpapbilities().\r
+    //\r
+    if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {\r
+      return EFI_SUCCESS;\r
+    }\r
     //\r
     // Check layout of FMP capsule\r
     //\r
@@ -1255,6 +1436,7 @@ SupportCapsuleImage (
   Caution: This function may receive untrusted input.\r
 \r
   @param[in]  CapsuleHeader         Points to a capsule header.\r
+  @param[out] ResetRequired         Indicates whether reset is required or not.\r
 \r
   @retval EFI_SUCESS            Process Capsule Image successfully.\r
   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
@@ -1263,14 +1445,15 @@ SupportCapsuleImage (
 **/\r
 EFI_STATUS\r
 EFIAPI\r
-ProcessCapsuleImage (\r
-  IN EFI_CAPSULE_HEADER  *CapsuleHeader\r
+ProcessThisCapsuleImage (\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,\r
+  OUT BOOLEAN            *ResetRequired OPTIONAL\r
   )\r
 {\r
   EFI_STATUS                   Status;\r
-  BOOLEAN                      AreAllImagesProcessed;\r
 \r
   if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {\r
+    RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED);\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
@@ -1293,26 +1476,44 @@ ProcessCapsuleImage (
     Status = ValidateFmpCapsule(CapsuleHeader, NULL);\r
     DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));\r
     if (EFI_ERROR(Status)) {\r
+      RecordCapsuleStatusVariable(CapsuleHeader, Status);\r
       return Status;\r
     }\r
 \r
     //\r
-    // Press EFI FMP Capsule\r
+    // Process EFI FMP Capsule\r
     //\r
     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));\r
-    Status = ProcessFmpCapsuleImage(CapsuleHeader, &AreAllImagesProcessed);\r
+    Status = ProcessFmpCapsuleImage(CapsuleHeader, ResetRequired);\r
     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));\r
 \r
-    if (!AreAllImagesProcessed) {\r
-      mAreAllImagesProcessed = FALSE;\r
-    }\r
-\r
     return Status;\r
   }\r
 \r
   return EFI_UNSUPPORTED;\r
 }\r
 \r
+/**\r
+  The firmware implements to process the capsule image.\r
+\r
+  Caution: This function may receive untrusted input.\r
+\r
+  @param[in]  CapsuleHeader         Points to a capsule header.\r
+\r
+  @retval EFI_SUCESS            Process Capsule Image successfully.\r
+  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.\r
+  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.\r
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ProcessCapsuleImage (\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader\r
+  )\r
+{\r
+  return ProcessThisCapsuleImage (CapsuleHeader, NULL);\r
+}\r
+\r
 /**\r
   Callback function executed when the EndOfDxe event group is signaled.\r
 \r
@@ -1345,7 +1546,6 @@ DxeCapsuleLibConstructor (
   IN EFI_SYSTEM_TABLE   *SystemTable\r
   )\r
 {\r
-  EFI_EVENT     EndOfDxeEvent;\r
   EFI_STATUS    Status;\r
 \r
   Status = gBS->CreateEventEx (\r
@@ -1354,7 +1554,7 @@ DxeCapsuleLibConstructor (
                   DxeCapsuleLibEndOfDxe,\r
                   NULL,\r
                   &gEfiEndOfDxeEventGroupGuid,\r
-                  &EndOfDxeEvent\r
+                  &mDxeCapsuleLibEndOfDxeEvent\r
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
@@ -1362,3 +1562,29 @@ DxeCapsuleLibConstructor (
 \r
   return EFI_SUCCESS;\r
 }\r
+\r
+/**\r
+  The destructor function closes the End of DXE event.\r
+\r
+  @param  ImageHandle   The firmware allocated handle for the EFI image.\r
+  @param  SystemTable   A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS   The destructor completed successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeCapsuleLibDestructor (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+\r
+  //\r
+  // Close the End of DXE event.\r
+  //\r
+  Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r