MdeModulePkg/CapsuleLib: Follow UEFI 22.2.3 to process FMP.

Previous logic does not follow UEFI 22.2.3 to process FMP strictly.
It may cause FMP image not be processed in some corner case.
The updated logic follows UEFI 22.2.3.

The way to check if a capsule is processed is also simplified.

The function - ProcessFmpCapsuleImage() is too big, so that
we created sub-functions - StartFmpImage(), DumpAllFmpInfo(),
GetFmpHandleBufferByType(), SetFmpImageData(), RecordFmpCapsuleStatus()
to improve the readability.

The function - ProcessTheseCapsules() is too big, so that
we created sub-functions - InitCapsulePtr(), AreAllImagesProcessed(),
PopulateCapsuleInConfigurationTable() to improve the readability.

Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Star Zeng <star.zeng@intel.com>
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
index 2bb6ac8..71e05bd 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -47,8 +47,6 @@
 #include <Protocol/FirmwareManagement.h>

 #include <Protocol/DevicePath.h>

 

-BOOLEAN            mAreAllImagesProcessed;

-

 EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable              = NULL;

 BOOLEAN                   mIsVirtualAddrConverted  = FALSE;

 BOOLEAN                   mDxeCapsuleLibEndOfDxe   = FALSE;

@@ -62,23 +60,6 @@
   );

 

 /**

-  Check if this FMP capsule is processed.

-

-  @param[in] CapsuleHeader  The capsule image header

-  @param[in] PayloadIndex   FMP payload index

-  @param[in] ImageHeader    FMP image header

-

-  @retval TRUE  This FMP capsule is processed.

-  @retval FALSE This FMP capsule is not processed.

-**/

-BOOLEAN

-IsFmpCapsuleProcessed (

-  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,

-  IN UINTN                                         PayloadIndex,

-  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader

-  );

-

-/**

   Record capsule status variable.

 

   @param[in] CapsuleHeader  The capsule image header

@@ -769,6 +750,520 @@
 }

 

 /**

+  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

@@ -779,65 +1274,38 @@
   This function need support nested FMP capsule.

 

   @param[in]   CapsuleHeader         Points to a capsule header.

-  @param[out]  AreAllImagesProcessed If all the FMP images in the capsule are processed.

 

   @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,

-  OUT BOOLEAN            *AreAllImagesProcessed

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader

   )

 {

   EFI_STATUS                                    Status;

-  EFI_STATUS                                    StatusEsrt;

-  EFI_STATUS                                    StatusRet;

   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;

   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;

-  UINT8                                         *Image;

-  EFI_HANDLE                                    ImageHandle;

   UINT64                                        *ItemOffsetList;

   UINT32                                        ItemNum;

   UINTN                                         Index;

-  UINTN                                         ExitDataSize;

   EFI_HANDLE                                    *HandleBuffer;

-  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;

   UINTN                                         NumberOfHandles;

-  UINTN                                         DescriptorSize;

-  UINT8                                         FmpImageInfoCount;

-  UINT32                                        FmpImageInfoDescriptorVer;

-  UINTN                                         ImageInfoSize;

-  UINT32                                        PackageVersion;

-  CHAR16                                        *PackageVersionName;

-  CHAR16                                        *AbortReason;

-  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;

-  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;

   UINTN                                         DriverLen;

-  UINTN                                         Index1;

+  UINT64                                        UpdateHardwareInstance;

   UINTN                                         Index2;

-  MEMMAP_DEVICE_PATH                            MemMapNode;

-  EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;

-  EFI_DEVICE_PATH_PROTOCOL                      *FmpDevicePath;

-  ESRT_MANAGEMENT_PROTOCOL                      *EsrtProtocol;

-  EFI_SYSTEM_RESOURCE_ENTRY                     EsrtEntry;

-  VOID                                          *VendorCode;

+  BOOLEAN                                       NotReady;

+  BOOLEAN                                       Abort;

 

   if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {

-    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), AreAllImagesProcessed);

+    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));

   }

 

-  ASSERT(AreAllImagesProcessed != NULL);

-

-  Status           = EFI_SUCCESS;

-  StatusRet        = EFI_NOT_FOUND;

-  HandleBuffer     = NULL;

-  ExitDataSize     = 0;

-  DriverDevicePath = NULL;

-  EsrtProtocol     = NULL;

-  *AreAllImagesProcessed = FALSE;

+  NotReady = FALSE;

+  Abort = FALSE;

 

   DumpFmpCapsule(CapsuleHeader);

 

@@ -854,35 +1322,15 @@
   // capsule in which driver count and payload count are both zero is not processed.

   //

   if (ItemNum == 0) {

-    *AreAllImagesProcessed = TRUE;

     return EFI_SUCCESS;

   }

 

   //

-  // Update corresponding ESRT entry LastAttemp Status

-  //

-  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);

-  if (EFI_ERROR (Status)) {

-    EsrtProtocol = NULL;

-  }

-

-  //

   // 1. Try to load & start all the drivers within capsule

   //

-  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)CapsuleHeader;

-  MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);

-

-  DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);

-  if (DriverDevicePath == NULL) {

-    return EFI_OUT_OF_RESOURCES;

-  }

-

   for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {

-    if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {

+    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

       //

@@ -891,32 +1339,13 @@
       DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];

     }

 

-    DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));

-    Status = gBS->LoadImage(

-                    FALSE,

-                    gImageHandle,

-                    DriverDevicePath,

-                    (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],

-                    DriverLen,

-                    &ImageHandle

-                    );

-    DEBUG((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));

-    if (EFI_ERROR(Status)) {

-      StatusRet = Status;

-      goto EXIT;

-    }

-

-    DEBUG((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));

-    Status = gBS->StartImage(

-                    ImageHandle,

-                    &ExitDataSize,

-                    NULL

-                    );

-    DEBUG((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));

+    Status = StartFmpImage (

+               (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],

+               DriverLen

+               );

     if (EFI_ERROR(Status)) {

       DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));

-      StatusRet = Status;

-      goto EXIT;

+      return Status;

     }

   }

 

@@ -925,207 +1354,80 @@
   //

   DEBUG((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));

 

-  Status = gBS->LocateHandleBuffer (

-                  ByProtocol,

-                  &gEfiFirmwareManagementProtocolGuid,

-                  NULL,

-                  &NumberOfHandles,

-                  &HandleBuffer

-                  );

-

-  if (!EFI_ERROR(Status)) {

-    for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {

-      Status = gBS->HandleProtocol(

-                      HandleBuffer[Index1],

-                      &gEfiFirmwareManagementProtocolGuid,

-                      (VOID **)&Fmp

-                      );

-      if (EFI_ERROR(Status)) {

-        continue;

-      }

-

-      FmpDevicePath = NULL;

-      gBS->HandleProtocol(

-             HandleBuffer[Index1],

-             &gEfiDevicePathProtocolGuid,

-             (VOID **)&FmpDevicePath

-             );

-

-      ImageInfoSize = 0;

-      Status = Fmp->GetImageInfo (

-                      Fmp,

-                      &ImageInfoSize,

-                      NULL,

-                      NULL,

-                      NULL,

-                      NULL,

-                      NULL,

-                      NULL

-                      );

-      if (Status != EFI_BUFFER_TOO_SMALL) {

-        continue;

-      }

-

-      FmpImageInfoBuf = NULL;

-      FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);

-      if (FmpImageInfoBuf == NULL) {

-        StatusRet = EFI_OUT_OF_RESOURCES;

-        goto EXIT;

-      }

-

-      PackageVersionName = NULL;

-      Status = Fmp->GetImageInfo (

-                      Fmp,

-                      &ImageInfoSize,               // ImageInfoSize

-                      FmpImageInfoBuf,              // ImageInfo

-                      &FmpImageInfoDescriptorVer,   // DescriptorVersion

-                      &FmpImageInfoCount,           // DescriptorCount

-                      &DescriptorSize,              // DescriptorSize

-                      &PackageVersion,              // PackageVersion

-                      &PackageVersionName           // PackageVersionName

-                      );

-

-      //

-      // If FMP GetInformation interface failed, skip this resource

-      //

-      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);

-      }

-

-      TempFmpImageInfo = FmpImageInfoBuf;

-      for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {

-        //

-        // 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]);

-

-          if (IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {

-            DEBUG((DEBUG_INFO, "FMP Capsule already processed (%g):", CapsuleHeader));

-            DEBUG((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));

-            DEBUG((DEBUG_INFO, "PayloadIndex - 0x%x, ImageIndex - 0x%x\n", Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader->UpdateImageIndex));

-            continue;

-          }

-

-          if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {

-            AbortReason = NULL;

-            if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {

-              if(ImageHeader->UpdateHardwareInstance != 0){

-                //

-                // FMP Version is >=2 & UpdateHardwareInstance Skip 2 case

-                //  1. FMP Image info Version < 3

-                //  2. HardwareInstance doesn't match

-                //

-                if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION ||

-                   ImageHeader->UpdateHardwareInstance != TempFmpImageInfo->HardwareInstance) {

-                  continue;

-                }

-              }

-              Image = (UINT8 *)(ImageHeader + 1);

-            } else {

-              //

-              // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.

-              // 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;

-            }

-            DEBUG((DEBUG_INFO, "Fmp->SetImage ...\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);

-            }

-            RecordFmpCapsuleStatusVariable(

-              CapsuleHeader,                                 // CapsuleGuid

-              Status,                                        // CapsuleStatus

-              Index - FmpCapsuleHeader->EmbeddedDriverCount, // PayloadIndex

-              ImageHeader,                                   // ImageHeader

-              FmpDevicePath                                  // FmpDevicePath

-              );

-            if (StatusRet != EFI_SUCCESS) {

-              StatusRet = Status;

-            }

-            //

-            // Update EsrtEntry For V1, V2 FMP instance. V3 FMP ESRT cache will be synced up through EsrtSyncFmp interface

-            //

-            if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION && EsrtProtocol != NULL) {

-               StatusEsrt = EsrtProtocol->GetEsrtEntry(&TempFmpImageInfo->ImageTypeId, &EsrtEntry);

-               if (!EFI_ERROR(StatusEsrt)){

-                 if (!EFI_ERROR(Status)) {

-                   EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;

-                 } else {

-                   EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;

-                 }

-                 EsrtEntry.LastAttemptVersion = 0;

-                 EsrtProtocol->UpdateEsrtEntry(&EsrtEntry);

-               }

-             }

-          }

-        }

-        //

-        // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version

-        //

-        TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);

-      }

-      FreePool(FmpImageInfoBuf);

-    }

-  }

+  DumpAllFmpInfo ();

 

   //

-  // final check for AreAllImagesProcessed

+  // Check all the payload entry in capsule payload list

   //

-  *AreAllImagesProcessed = TRUE;

   for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {

-    ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);

+    ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);

 

-    if (!IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {

-      *AreAllImagesProcessed = FALSE;

-      break;

+    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);

     }

   }

 

-EXIT:

-

-  if (HandleBuffer != NULL) {

-    FreePool(HandleBuffer);

+  if (NotReady) {

+    return EFI_NOT_READY;

   }

 

-  if (DriverDevicePath != NULL) {

-    FreePool(DriverDevicePath);

-  }

-

-  return StatusRet;

+  //

+  // always return SUCCESS to indicate this capsule is processed.

+  // The status of SetImage is recorded in capsule result variable.

+  //

+  return EFI_SUCCESS;

 }

 

 /**

@@ -1278,9 +1580,9 @@
   )

 {

   EFI_STATUS                   Status;

-  BOOLEAN                      AreAllImagesProcessed;

 

   if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {

+    RecordCapsuleStatusVariable(CapsuleHeader, EFI_UNSUPPORTED);

     return EFI_UNSUPPORTED;

   }

 

@@ -1303,6 +1605,7 @@
     Status = ValidateFmpCapsule(CapsuleHeader, NULL);

     DEBUG((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));

     if (EFI_ERROR(Status)) {

+      RecordCapsuleStatusVariable(CapsuleHeader, Status);

       return Status;

     }

 

@@ -1310,13 +1613,9 @@
     // Press EFI FMP Capsule

     //

     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));

-    Status = ProcessFmpCapsuleImage(CapsuleHeader, &AreAllImagesProcessed);

+    Status = ProcessFmpCapsuleImage(CapsuleHeader);

     DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));

 

-    if (!AreAllImagesProcessed) {

-      mAreAllImagesProcessed = FALSE;

-    }

-

     return Status;

   }

 

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
index 62257a4..ba3ff90 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -95,60 +95,23 @@
   );

 

 extern BOOLEAN                   mDxeCapsuleLibEndOfDxe;

-extern BOOLEAN                   mAreAllImagesProcessed;

 BOOLEAN                          mNeedReset;

 

+VOID                        **mCapsulePtr;

+EFI_STATUS                  *mCapsuleStatusArray;

+UINT32                      mCapsuleTotalNumber;

+

 /**

-

-  This routine is called to process capsules.

-

-  Caution: This function may receive untrusted input.

-

-  Each individual capsule result is recorded in capsule record variable.

-

-  @param[in]  NeedBlockDriver         TRUE: Need skip the FMP capsules with non zero EmbeddedDriverCount.

-                                      FALSE: No need to skip any FMP capsules.

-

-  @retval EFI_SUCCESS             There is no error when processing capsules.

-  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.

-

+  This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber.

 **/

-EFI_STATUS

-ProcessTheseCapsules (

-  IN BOOLEAN  NeedBlockDriver

+VOID

+InitCapsulePtr (

+  VOID

   )

 {

-  EFI_STATUS                  Status;

   EFI_PEI_HOB_POINTERS        HobPointer;

-  EFI_CAPSULE_HEADER          *CapsuleHeader;

-  UINT32                      Size;

-  UINT32                      CapsuleNumber;

-  UINT32                      CapsuleTotalNumber;

-  EFI_CAPSULE_TABLE           *CapsuleTable;

-  UINT32                      Index;

-  UINT32                      CacheIndex;

-  UINT32                      CacheNumber;

-  VOID                        **CapsulePtr;

-  VOID                        **CapsulePtrCache;

-  EFI_GUID                    *CapsuleGuidCache;

-  EFI_STATUS                  *CapsuleStatusArray;

-  BOOLEAN                     DisplayCapsuleExist;

-  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;

-  UINT16                      EmbeddedDriverCount;

+  UINTN                       Index;

 

-  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));

-

-  CapsuleNumber       = 0;

-  CapsuleTotalNumber  = 0;

-  CacheIndex          = 0;

-  CacheNumber         = 0;

-  CapsulePtr          = NULL;

-  CapsulePtrCache     = NULL;

-  CapsuleGuidCache    = NULL;

-  DisplayCapsuleExist = FALSE;

-  EsrtManagement      = NULL;

-

-  Status = EFI_SUCCESS;

   //

   // Find all capsule images from hob

   //

@@ -157,61 +120,108 @@
     if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {

       HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid

     } else {

-      CapsuleTotalNumber++;

+      mCapsuleTotalNumber++;

     }

     HobPointer.Raw = GET_NEXT_HOB (HobPointer);

   }

 

-  if (CapsuleTotalNumber == 0) {

-    //

-    // We didn't find a hob, so had no errors.

-    //

-    DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));

-    Status = EFI_SUCCESS;

-    goto Done;

+  DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber));

+

+  if (mCapsuleTotalNumber == 0) {

+    return ;

   }

 

   //

   // Init temp Capsule Data table.

   //

-  CapsulePtr       = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);

-  ASSERT (CapsulePtr != NULL);

-  if (CapsulePtr == NULL) {

-    Status = EFI_OUT_OF_RESOURCES;

-    goto Done;

+  mCapsulePtr       = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);

+  if (mCapsulePtr == NULL) {

+    DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n"));

+    mCapsuleTotalNumber = 0;

+    return ;

   }

-  CapsulePtrCache  = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);

-  ASSERT (CapsulePtrCache != NULL);

-  if (CapsulePtrCache == NULL) {

-    Status = EFI_OUT_OF_RESOURCES;

-    goto Done;

+  mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber);

+  if (mCapsuleStatusArray == NULL) {

+    DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n"));

+    FreePool (mCapsulePtr);

+    mCapsulePtr = NULL;

+    mCapsuleTotalNumber = 0;

+    return ;

   }

-  CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);

-  ASSERT (CapsuleGuidCache != NULL);

-  if (CapsuleGuidCache == NULL) {

-    Status = EFI_OUT_OF_RESOURCES;

-    goto Done;

-  }

-  CapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * CapsuleTotalNumber);

-  ASSERT (CapsuleStatusArray != NULL);

-  if (CapsuleStatusArray == NULL) {

-    Status = EFI_OUT_OF_RESOURCES;

-    goto Done;

-  }

+  SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY);

 

   //

   // Find all capsule images from hob

   //

   HobPointer.Raw = GetHobList ();

+  Index = 0;

   while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {

-    CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;

+    mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;

     HobPointer.Raw = GET_NEXT_HOB (HobPointer);

   }

+}

 

-  //

-  // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install

-  // capsuleTable to configure table with EFI_CAPSULE_GUID

-  //

+/**

+  This function returns if all capsule images are processed.

+

+  @retval TRUE   All capsule images are processed.

+  @retval FALSE  Not all capsule images are processed.

+**/

+BOOLEAN

+AreAllImagesProcessed (

+  VOID

+  )

+{

+  UINTN  Index;

+

+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {

+    if (mCapsuleStatusArray[Index] == EFI_NOT_READY) {

+      return FALSE;

+    }

+  }

+

+  return TRUE;

+}

+

+/**

+  This function populates capsule in the configuration table.

+**/

+VOID

+PopulateCapsuleInConfigurationTable (

+  VOID

+  )

+{

+  VOID                        **CapsulePtrCache;

+  EFI_GUID                    *CapsuleGuidCache;

+  EFI_CAPSULE_HEADER          *CapsuleHeader;

+  EFI_CAPSULE_TABLE           *CapsuleTable;

+  UINT32                      CacheIndex;

+  UINT32                      CacheNumber;

+  UINT32                      CapsuleNumber;

+  UINTN                       Index;

+  UINTN                       Size;

+  EFI_STATUS                  Status;

+

+  if (mCapsuleTotalNumber == 0) {

+    return ;

+  }

+

+  CapsulePtrCache     = NULL;

+  CapsuleGuidCache    = NULL;

+  CacheIndex          = 0;

+  CacheNumber         = 0;

+

+  CapsulePtrCache  = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);

+  if (CapsulePtrCache == NULL) {

+    DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n"));

+    return ;

+  }

+  CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber);

+  if (CapsuleGuidCache == NULL) {

+    DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n"));

+    FreePool (CapsulePtrCache);

+    return ;

+  }

 

   //

   // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating

@@ -223,9 +233,8 @@
   // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an

   // array for later sorting capsules by CapsuleGuid.

   //

-  for (Index = 0; Index < CapsuleTotalNumber; Index++) {

-    CapsuleStatusArray [Index] = EFI_UNSUPPORTED;

-    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];

+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {

+    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];

     if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {

       //

       // For each capsule, we compare it with known CapsuleGuid in the CacheArray.

@@ -254,38 +263,90 @@
   // will look in EFI System Table and search for the capsule's Guid and associated

   // pointer to retrieve the data.

   //

-  CacheIndex = 0;

-  while (CacheIndex < CacheNumber) {

+  for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) {

     CapsuleNumber = 0;

-    for (Index = 0; Index < CapsuleTotalNumber; Index++) {

-      CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];

+    for (Index = 0; Index < mCapsuleTotalNumber; Index++) {

+      CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];

       if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {

         if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {

           //

           // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.

           //

           CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;

-          //

-          // When a Capsule is listed in CapsulePtrCache, it will be reported in ConfigurationTable

-          // So, report the CapsuleStatus as "processed successfully".

-          //

-          CapsuleStatusArray [Index] = EFI_SUCCESS;

         }

       }

     }

     if (CapsuleNumber != 0) {

       Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);

       CapsuleTable = AllocateRuntimePool (Size);

-      ASSERT (CapsuleTable != NULL);

       if (CapsuleTable == NULL) {

-        return EFI_OUT_OF_RESOURCES;

+        DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));

+        continue;

       }

       CapsuleTable->CapsuleArrayNumber =  CapsuleNumber;

       CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));

       Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);

-      ASSERT_EFI_ERROR (Status);

+      if (EFI_ERROR (Status)) {

+        DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));

+      }

     }

-    CacheIndex++;

+  }

+

+  FreePool(CapsuleGuidCache);

+  FreePool(CapsulePtrCache);

+}

+

+/**

+

+  This routine is called to process capsules.

+

+  Caution: This function may receive untrusted input.

+

+  Each individual capsule result is recorded in capsule record variable.

+

+  @param[in]  FirstRound         TRUE:  First round. Need skip the FMP capsules with non zero EmbeddedDriverCount.

+                                 FALSE: Process rest FMP capsules.

+

+  @retval EFI_SUCCESS             There is no error when processing capsules.

+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.

+

+**/

+EFI_STATUS

+ProcessTheseCapsules (

+  IN BOOLEAN  FirstRound

+  )

+{

+  EFI_STATUS                  Status;

+  EFI_CAPSULE_HEADER          *CapsuleHeader;

+  UINT32                      Index;

+  BOOLEAN                     DisplayCapsuleExist;

+  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;

+  UINT16                      EmbeddedDriverCount;

+

+  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));

+

+  if (FirstRound) {

+    InitCapsulePtr ();

+  }

+

+  if (mCapsuleTotalNumber == 0) {

+    //

+    // We didn't find a hob, so had no errors.

+    //

+    DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));

+    return EFI_SUCCESS;

+  }

+

+  if (AreAllImagesProcessed ()) {

+    return EFI_SUCCESS;

+  }

+

+  //

+  // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install

+  // capsuleTable to configure table with EFI_CAPSULE_GUID

+  //

+  if (FirstRound) {

+    PopulateCapsuleInConfigurationTable ();

   }

 

   REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));

@@ -293,15 +354,16 @@
   //

   // If Windows UX capsule exist, process it first

   //

-  for (Index = 0; Index < CapsuleTotalNumber; Index++) {

-    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];

-    if (CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {

+  DisplayCapsuleExist = FALSE;

+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {

+    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];

+    if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {

       DEBUG ((DEBUG_INFO, "ProcessCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));

       DisplayCapsuleExist = TRUE;

       DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));

       Status = ProcessCapsuleImage (CapsuleHeader);

+      mCapsuleStatusArray [Index] = EFI_SUCCESS;

       DEBUG((DEBUG_INFO, "ProcessCapsuleImage (Ux) - %r\n", Status));

-      CapsuleStatusArray [Index] = Status;

       break;

     }

   }

@@ -316,38 +378,48 @@
   //

   // All capsules left are recognized by platform.

   //

-  for (Index = 0; Index < CapsuleTotalNumber; Index++) {

-    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];

-    if (!CompareGuid(&CapsuleHeader->CapsuleGuid ,&gWindowsUxCapsuleGuid)) {

+  for (Index = 0; Index < mCapsuleTotalNumber; Index++) {

+    if (mCapsuleStatusArray [Index] != EFI_NOT_READY) {

+      // already processed

+      continue;

+    }

+    CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];

+    if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {

       //

       // Call capsule library to process capsule image.

       //

       EmbeddedDriverCount = 0;

       if (IsFmpCapsule(CapsuleHeader)) {

-        Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount);

+        Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount);

         if (EFI_ERROR(Status)) {

           DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));

+          mCapsuleStatusArray [Index] = EFI_ABORTED;

           continue;

         }

+      } else {

+        mCapsuleStatusArray [Index] = EFI_ABORTED;

+        continue;

       }

 

-      if ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) {

+      if ((!FirstRound) || (EmbeddedDriverCount == 0)) {

         DEBUG((DEBUG_INFO, "ProcessCapsuleImage - 0x%x\n", CapsuleHeader));

         Status = ProcessCapsuleImage (CapsuleHeader);

-        CapsuleStatusArray [Index] = Status;

+        mCapsuleStatusArray [Index] = Status;

         DEBUG((DEBUG_INFO, "ProcessCapsuleImage - %r\n", Status));

 

-        if (EFI_ERROR(Status)) {

-          REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));

-          DEBUG ((DEBUG_ERROR, "Capsule process failed. reset the system!\n"));

-          Print (L"Firmware update failed...\r\n");

-        } else {

-          REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));

-        }

+        if (Status != EFI_NOT_READY) {

+          if (EFI_ERROR(Status)) {

+            REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));

+            DEBUG ((DEBUG_ERROR, "Capsule process failed!\n"));

+            Print (L"Firmware update failed...\r\n");

+          } else {

+            REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));

+          }

 

-        if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||

-            IsFmpCapsule(CapsuleHeader)) {

-          mNeedReset = TRUE;

+          if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||

+              IsFmpCapsule(CapsuleHeader)) {

+            mNeedReset = TRUE;

+          }

         }

       }

     }

@@ -362,20 +434,6 @@
   }

   Status = EFI_SUCCESS;

 

-Done:

-  //

-  // Free the allocated temp memory space.

-  //

-  if (CapsuleGuidCache != NULL) {

-    FreePool(CapsuleGuidCache);

-  }

-  if (CapsulePtrCache != NULL) {

-    FreePool(CapsulePtrCache);

-  }

-  if (CapsulePtr != NULL) {

-    FreePool(CapsulePtr);

-  }

-

   REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));

 

   return Status;

@@ -446,20 +504,13 @@
   EFI_STATUS                    Status;

 

   if (!mDxeCapsuleLibEndOfDxe) {

-    //

-    // Initialize mAreAllImagesProcessed to be TRUE.

-    //

-    // It will be updated to FALSE in ProcessTheseCapsules()->ProcessCapsuleImage(),

-    // if there is any FMP image in any FMP capsule not processed.

-    //

-    mAreAllImagesProcessed = TRUE;

-

     Status = ProcessTheseCapsules(TRUE);

+

     //

     // Reboot System if and only if all capsule processed.

     // If not, defer reset to 2nd process.

     //

-    if (mNeedReset && mAreAllImagesProcessed) {

+    if (mNeedReset && AreAllImagesProcessed()) {

       DoResetSystem();

     }

   } else {

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
index ce79a5a..3a9bb6e 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
@@ -35,17 +35,6 @@
 

 #include <IndustryStandard/WindowsUxCapsule.h>

 

-typedef struct {

-  EFI_CAPSULE_RESULT_VARIABLE_HEADER  CapsuleResultHeader;

-  EFI_CAPSULE_RESULT_VARIABLE_FMP     CapsuleResultFmp;

-} CAPSULE_RESULT_VARIABLE_CACHE;

-

-#define CAPSULE_RESULT_VARIABLE_CACHE_COUNT   0x10

-

-CAPSULE_RESULT_VARIABLE_CACHE *mCapsuleResultVariableCache;

-UINTN                         mCapsuleResultVariableCacheMaxCount;

-UINTN                         mCapsuleResultVariableCacheCount;

-

 /**

   Get current capsule last variable index.

 

@@ -78,92 +67,6 @@
 }

 

 /**

-  Check if this FMP capsule is processed.

-

-  @param[in] CapsuleHeader  The capsule image header

-  @param[in] PayloadIndex   FMP payload index

-  @param[in] ImageHeader    FMP image header

-

-  @retval TRUE  This FMP capsule is processed.

-  @retval FALSE This FMP capsule is not processed.

-**/

-BOOLEAN

-IsFmpCapsuleProcessed (

-  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,

-  IN UINTN                                         PayloadIndex,

-  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader

-  )

-{

-  UINTN                               Index;

-  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResult;

-  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultFmp;

-

-  for (Index = 0; Index < mCapsuleResultVariableCacheCount; Index++) {

-    //

-    // Check

-    //

-    CapsuleResult = &mCapsuleResultVariableCache[Index].CapsuleResultHeader;

-    if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {

-      if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {

-        if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) {

-          CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);

-          if (CompareGuid(&CapsuleResultFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId) &&

-              (CapsuleResultFmp->UpdateImageIndex == ImageHeader->UpdateImageIndex) &&

-              (CapsuleResultFmp->PayloadIndex == PayloadIndex) ) {

-            return TRUE;

-          }

-        }

-      }

-    }

-  }

-

-  return FALSE;

-}

-

-/**

-  Write a new capsule status variable cache.

-

-  @param[in] CapsuleResult      The capsule status variable

-  @param[in] CapsuleResultSize  The size of the capsule stauts variable in bytes

-

-  @retval EFI_SUCCESS          The capsule status variable is cached.

-  @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.

-**/

-EFI_STATUS

-WriteNewCapsuleResultVariableCache (

-  IN VOID    *CapsuleResult,

-  IN UINTN   CapsuleResultSize

-  )

-{

-  if (CapsuleResultSize > sizeof(CAPSULE_RESULT_VARIABLE_CACHE)) {

-    CapsuleResultSize = sizeof(CAPSULE_RESULT_VARIABLE_CACHE);

-  }

-

-  if (mCapsuleResultVariableCacheCount == mCapsuleResultVariableCacheMaxCount) {

-    mCapsuleResultVariableCache = ReallocatePool(

-                                    mCapsuleResultVariableCacheMaxCount * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),

-                                    (mCapsuleResultVariableCacheMaxCount + CAPSULE_RESULT_VARIABLE_CACHE_COUNT) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),

-                                    mCapsuleResultVariableCache

-                                    );

-    if (mCapsuleResultVariableCache == NULL) {

-      return EFI_OUT_OF_RESOURCES;

-    }

-    mCapsuleResultVariableCacheMaxCount += CAPSULE_RESULT_VARIABLE_CACHE_COUNT;

-  }

-

-  ASSERT(mCapsuleResultVariableCacheCount < mCapsuleResultVariableCacheMaxCount);

-  ASSERT(mCapsuleResultVariableCache != NULL);

-  CopyMem(

-    &mCapsuleResultVariableCache[mCapsuleResultVariableCacheCount],

-    CapsuleResult,

-    CapsuleResultSize

-    );

-  mCapsuleResultVariableCacheCount++;

-

-  return EFI_SUCCESS;

-}

-

-/**

   Get a new capsule status variable index.

 

   @return A new capsule status variable index.

@@ -262,11 +165,7 @@
   gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);

   CapsuleResultVariable.CapsuleStatus = CapsuleStatus;

 

-  //

-  // Save Local Cache

-  //

-  Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));

-

+  Status = EFI_SUCCESS;

   if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {

     Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));

   }

@@ -338,11 +237,7 @@
     DevicePathStr = NULL;

   }

 

-  //

-  // Save Local Cache

-  //

-  Status = WriteNewCapsuleResultVariableCache(CapsuleResultVariable, CapsuleResultVariableSize);

-

+  Status = EFI_SUCCESS;

   if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {

     Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);

   }

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
index 6ab198d..a6860ef 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
@@ -20,26 +20,6 @@
 #include <Library/CapsuleLib.h>

 

 /**

-  Check if this FMP capsule is processed.

-

-  @param[in] CapsuleHeader  The capsule image header

-  @param[in] PayloadIndex   FMP payload index

-  @param[in] ImageHeader    FMP image header

-

-  @retval TRUE  This FMP capsule is processed.

-  @retval FALSE This FMP capsule is not processed.

-**/

-BOOLEAN

-IsFmpCapsuleProcessed (

-  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,

-  IN UINTN                                         PayloadIndex,

-  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader

-  )

-{

-  return FALSE;

-}

-

-/**

   Record capsule status variable and to local cache.

 

   @param[in] CapsuleHeader  The capsule image header