MdeModulePkg/DxeCapsuleLibFmp: Add DxeCapsuleLibFmp instance.

This instance handles Microsoft UX capsule, UEFI defined FMP capsule.
This instance should not assume any capsule image format.

Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@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: Liming Gao <liming.gao@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
new file mode 100644
index 0000000..b3d31b8
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -0,0 +1,1364 @@
+/** @file

+  DXE capsule library.

+

+  Caution: This module requires additional review when modified.

+  This module will have external input - capsule image.

+  This external input must be validated carefully to avoid security issue like

+  buffer overflow, integer overflow.

+

+  SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),

+  ValidateFmpCapsule(), DisplayCapsuleImage(), ConvertBmpToGopBlt() will

+  receive untrusted input and do basic validation.

+

+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include <PiDxe.h>

+

+#include <IndustryStandard/Bmp.h>

+#include <IndustryStandard/WindowsUxCapsule.h>

+

+#include <Guid/FmpCapsule.h>

+#include <Guid/SystemResourceTable.h>

+#include <Guid/EventGroup.h>

+

+#include <Library/BaseLib.h>

+#include <Library/DebugLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DxeServicesTableLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/CapsuleLib.h>

+#include <Library/DevicePathLib.h>

+#include <Library/UefiLib.h>

+#include <Library/PcdLib.h>

+

+#include <Protocol/GraphicsOutput.h>

+#include <Protocol/EsrtManagement.h>

+#include <Protocol/FirmwareManagement.h>

+#include <Protocol/DevicePath.h>

+

+BOOLEAN            mAreAllImagesProcessed;

+

+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable              = NULL;

+BOOLEAN                   mIsVirtualAddrConverted  = FALSE;

+BOOLEAN                   mDxeCapsuleLibEndOfDxe   = FALSE;

+

+/**

+  Initialize capsule related variables.

+**/

+VOID

+InitCapsuleVariable (

+  VOID

+  );

+

+/**

+  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

+  @param[in] CapsuleStatus  The capsule process stauts

+

+  @retval EFI_SUCCESS          The capsule status variable is recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+RecordCapsuleStatusVariable (

+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,

+  IN EFI_STATUS                                   CapsuleStatus

+  );

+

+/**

+  Record FMP capsule status variable.

+

+  @param[in] CapsuleHeader  The capsule image header

+  @param[in] CapsuleStatus  The capsule process stauts

+  @param[in] PayloadIndex   FMP payload index

+  @param[in] ImageHeader    FMP image header

+

+  @retval EFI_SUCCESS          The capsule status variable is recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+RecordFmpCapsuleStatusVariable (

+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,

+  IN EFI_STATUS                                    CapsuleStatus,

+  IN UINTN                                         PayloadIndex,

+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader

+  );

+

+/**

+  Function indicate the current completion progress of the firmware

+  update. Platform may override with own specific progress function.

+

+  @param[in]  Completion    A value between 1 and 100 indicating the current completion progress of the firmware update

+

+  @retval EFI_SUCESS    Input capsule is a correct FMP capsule.

+**/

+EFI_STATUS

+EFIAPI

+Update_Image_Progress (

+  IN UINTN  Completion

+  )

+{

+  return EFI_SUCCESS;

+}

+

+/**

+  Return if this CapsuleGuid is a FMP capsule GUID or not.

+

+  @param[in] CapsuleGuid A pointer to EFI_GUID

+

+  @retval TRUE  It is a FMP capsule GUID.

+  @retval FALSE It is not a FMP capsule GUID.

+**/

+BOOLEAN

+IsFmpCapsuleGuid (

+  IN EFI_GUID  *CapsuleGuid

+  )

+{

+  if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {

+    return TRUE;

+  }

+

+  return FALSE;

+}

+

+/**

+  Validate if it is valid capsule header

+

+  Caution: This function may receive untrusted input.

+

+  This function assumes the caller provided correct CapsuleHeader pointer

+  and CapsuleSize.

+

+  This function validates the fields in EFI_CAPSULE_HEADER.

+

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

+  @param[in]  CapsuleSize      Size of the whole capsule image.

+

+**/

+BOOLEAN

+IsValidCapsuleHeader (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,

+  IN UINT64              CapsuleSize

+  )

+{

+  if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {

+    return FALSE;

+  }

+  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {

+    return FALSE;

+  }

+  return TRUE;

+}

+

+/**

+  Validate Fmp capsules layout.

+

+  Caution: This function may receive untrusted input.

+

+  This function assumes the caller validated the capsule by using

+  IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.

+  The capsule buffer size is CapsuleHeader->CapsuleImageSize.

+

+  This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER

+  and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.

+

+  This function need support nested FMP capsule.

+

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

+  @param[out]  EmbeddedDriverCount  The EmbeddedDriverCount in the FMP capsule.

+

+  @retval EFI_SUCESS             Input capsule is a correct FMP capsule.

+  @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.

+**/

+EFI_STATUS

+ValidateFmpCapsule (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,

+  OUT UINT16             *EmbeddedDriverCount OPTIONAL

+  )

+{

+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;

+  UINT8                                        *EndOfCapsule;

+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;

+  UINT8                                        *EndOfPayload;

+  UINT64                                       *ItemOffsetList;

+  UINT32                                       ItemNum;

+  UINTN                                        Index;

+  UINTN                                        FmpCapsuleSize;

+  UINTN                                        FmpCapsuleHeaderSize;

+  UINT64                                       FmpImageSize;

+  UINTN                                        FmpImageHeaderSize;

+

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

+    return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);

+  }

+

+  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {

+    DEBUG((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));

+    return EFI_INVALID_PARAMETER;

+  }

+

+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);

+  EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;

+  FmpCapsuleSize   = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;

+

+  if (FmpCapsuleSize < sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {

+    DEBUG((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));

+    return EFI_INVALID_PARAMETER;

+  }

+

+  // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER

+  if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {

+    DEBUG((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));

+    return EFI_INVALID_PARAMETER;

+  }

+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);

+

+  // No overflow

+  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;

+

+  if ((FmpCapsuleSize - sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof(UINT64) < ItemNum) {

+    DEBUG((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));

+    return EFI_INVALID_PARAMETER;

+  }

+  FmpCapsuleHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof(UINT64)*ItemNum;

+

+  // Check ItemOffsetList

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

+    if (ItemOffsetList[Index] >= FmpCapsuleSize) {

+      DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));

+      return EFI_INVALID_PARAMETER;

+    }

+    if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {

+      DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));

+      return EFI_INVALID_PARAMETER;

+    }

+    //

+    // All the address in ItemOffsetList must be stored in ascending order

+    //

+    if (Index > 0) {

+      if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {

+        DEBUG((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));

+        return EFI_INVALID_PARAMETER;

+      }

+    }

+  }

+

+  // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER

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

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

+    if (Index == ItemNum - 1) {

+      EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);

+    } else {

+      EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];

+    }

+    FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];

+

+    if (FmpImageSize < OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {

+      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));

+      return EFI_INVALID_PARAMETER;

+    }

+    FmpImageHeaderSize = sizeof(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);

+    if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||

+        (ImageHeader->Version < 1)) {

+      DEBUG((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));

+      return EFI_INVALID_PARAMETER;

+    }

+    if (ImageHeader->Version < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {

+      FmpImageHeaderSize = OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);

+    }

+

+    // No overflow

+    if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {

+      DEBUG((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  if (ItemNum == 0) {

+    //

+    // No driver & payload element in FMP

+    //

+    EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);

+    if (EndOfPayload != EndOfCapsule) {

+      DEBUG((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));

+      return EFI_INVALID_PARAMETER;

+    }

+    return EFI_UNSUPPORTED;

+  }

+

+  if (EmbeddedDriverCount != NULL) {

+    *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;

+  }

+

+  return EFI_SUCCESS;

+}

+

+/**

+  Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer

+  is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt

+  buffer is passed in it will be used if it is big enough.

+

+  Caution: This function may receive untrusted input.

+

+  @param[in]       BmpImage      Pointer to BMP file

+  @param[in]       BmpImageSize  Number of bytes in BmpImage

+  @param[in, out]  GopBlt        Buffer containing GOP version of BmpImage.

+  @param[in, out]  GopBltSize    Size of GopBlt in bytes.

+  @param[out]      PixelHeight   Height of GopBlt/BmpImage in pixels

+  @param[out]      PixelWidth    Width of GopBlt/BmpImage in pixels

+

+  @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.

+  @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image

+  @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.

+                                GopBltSize will contain the required size.

+  @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.

+

+**/

+STATIC

+EFI_STATUS

+ConvertBmpToGopBlt (

+  IN     VOID      *BmpImage,

+  IN     UINTN     BmpImageSize,

+  IN OUT VOID      **GopBlt,

+  IN OUT UINTN     *GopBltSize,

+     OUT UINTN     *PixelHeight,

+     OUT UINTN     *PixelWidth

+  )

+{

+  UINT8                         *Image;

+  UINT8                         *ImageHeader;

+  BMP_IMAGE_HEADER              *BmpHeader;

+  BMP_COLOR_MAP                 *BmpColorMap;

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;

+  UINT64                        BltBufferSize;

+  UINTN                         Index;

+  UINTN                         Height;

+  UINTN                         Width;

+  UINTN                         ImageIndex;

+  UINT32                        DataSizePerLine;

+  BOOLEAN                       IsAllocated;

+  UINT32                        ColorMapNum;

+

+  if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;

+

+  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Doesn't support compress.

+  //

+  if (BmpHeader->CompressionType != 0) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Only support BITMAPINFOHEADER format.

+  // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER

+  //

+  if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // The data size in each line must be 4 byte alignment.

+  //

+  DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);

+  BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);

+  if (BltBufferSize > (UINT32) ~0) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if ((BmpHeader->Size != BmpImageSize) ||

+      (BmpHeader->Size < BmpHeader->ImageOffset) ||

+      (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  //

+  // Calculate Color Map offset in the image.

+  //

+  Image       = BmpImage;

+  BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));

+  if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {

+    return EFI_INVALID_PARAMETER;

+  }

+

+  if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {

+    switch (BmpHeader->BitPerPixel) {

+      case 1:

+        ColorMapNum = 2;

+        break;

+      case 4:

+        ColorMapNum = 16;

+        break;

+      case 8:

+        ColorMapNum = 256;

+        break;

+      default:

+        ColorMapNum = 0;

+        break;

+      }

+    //

+    // BMP file may has padding data between the bmp header section and the bmp data section.

+    //

+    if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {

+      return EFI_INVALID_PARAMETER;

+    }

+  }

+

+  //

+  // Calculate graphics image data address in the image

+  //

+  Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;

+  ImageHeader   = Image;

+

+  //

+  // Calculate the BltBuffer needed size.

+  //

+  BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);

+  //

+  // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow

+  //

+  if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {

+    return EFI_UNSUPPORTED;

+  }

+  BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

+

+  IsAllocated   = FALSE;

+  if (*GopBlt == NULL) {

+    //

+    // GopBlt is not allocated by caller.

+    //

+    *GopBltSize = (UINTN) BltBufferSize;

+    *GopBlt     = AllocatePool (*GopBltSize);

+    IsAllocated = TRUE;

+    if (*GopBlt == NULL) {

+      return EFI_OUT_OF_RESOURCES;

+    }

+  } else {

+    //

+    // GopBlt has been allocated by caller.

+    //

+    if (*GopBltSize < (UINTN) BltBufferSize) {

+      *GopBltSize = (UINTN) BltBufferSize;

+      return EFI_BUFFER_TOO_SMALL;

+    }

+  }

+

+  *PixelWidth   = BmpHeader->PixelWidth;

+  *PixelHeight  = BmpHeader->PixelHeight;

+

+  //

+  // Convert image from BMP to Blt buffer format

+  //

+  BltBuffer = *GopBlt;

+  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {

+    Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];

+    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {

+      switch (BmpHeader->BitPerPixel) {

+      case 1:

+        //

+        // Convert 1-bit (2 colors) BMP to 24-bit color

+        //

+        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {

+          Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;

+          Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;

+          Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;

+          Blt++;

+          Width++;

+        }

+

+        Blt--;

+        Width--;

+        break;

+

+      case 4:

+        //

+        // Convert 4-bit (16 colors) BMP Palette to 24-bit color

+        //

+        Index       = (*Image) >> 4;

+        Blt->Red    = BmpColorMap[Index].Red;

+        Blt->Green  = BmpColorMap[Index].Green;

+        Blt->Blue   = BmpColorMap[Index].Blue;

+        if (Width < (BmpHeader->PixelWidth - 1)) {

+          Blt++;

+          Width++;

+          Index       = (*Image) & 0x0f;

+          Blt->Red    = BmpColorMap[Index].Red;

+          Blt->Green  = BmpColorMap[Index].Green;

+          Blt->Blue   = BmpColorMap[Index].Blue;

+        }

+        break;

+

+      case 8:

+        //

+        // Convert 8-bit (256 colors) BMP Palette to 24-bit color

+        //

+        Blt->Red    = BmpColorMap[*Image].Red;

+        Blt->Green  = BmpColorMap[*Image].Green;

+        Blt->Blue   = BmpColorMap[*Image].Blue;

+        break;

+

+      case 24:

+        //

+        // It is 24-bit BMP.

+        //

+        Blt->Blue   = *Image++;

+        Blt->Green  = *Image++;

+        Blt->Red    = *Image;

+        break;

+

+      case 32:

+        //

+        // it is 32-bit BMP. Skip pixel's highest byte

+        //

+        Blt->Blue  = *Image++;

+        Blt->Green = *Image++;

+        Blt->Red   = *Image++;

+        break;

+

+      default:

+        //

+        // Other bit format BMP is not supported.

+        //

+        if (IsAllocated) {

+          FreePool (*GopBlt);

+          *GopBlt = NULL;

+        }

+        return EFI_UNSUPPORTED;

+      };

+

+    }

+

+    ImageIndex = (UINTN) (Image - ImageHeader);

+    if ((ImageIndex % 4) != 0) {

+      //

+      // Bmp Image starts each row on a 32-bit boundary!

+      //

+      Image = Image + (4 - (ImageIndex % 4));

+    }

+  }

+

+  return EFI_SUCCESS;

+}

+

+

+/**

+  Those capsules supported by the firmwares.

+

+  Caution: This function may receive untrusted input.

+

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

+

+  @retval EFI_SUCESS       Input capsule is supported by firmware.

+  @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.

+**/

+EFI_STATUS

+DisplayCapsuleImage (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader

+  )

+{

+  DISPLAY_DISPLAY_PAYLOAD       *ImagePayload;

+  UINTN                         PayloadSize;

+  EFI_STATUS                    Status;

+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;

+  UINTN                         BltSize;

+  UINTN                         Height;

+  UINTN                         Width;

+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;

+

+  ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);

+  PayloadSize = (UINTN)(CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER));

+

+  if (ImagePayload->Version != 1) {

+    return EFI_UNSUPPORTED;

+  }

+  if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {

+    return EFI_UNSUPPORTED;

+  }

+  //

+  // Only Support Bitmap by now

+  //

+  if (ImagePayload->ImageType != 0) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Try to open GOP

+  //

+  Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);

+  if (EFI_ERROR (Status)) {

+    Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);

+    if (EFI_ERROR(Status)) {

+      return EFI_UNSUPPORTED;

+    }

+  }

+

+  if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {

+    return EFI_UNSUPPORTED;

+  }

+

+  Blt = NULL;

+  Width = 0;

+  Height = 0;

+  Status = ConvertBmpToGopBlt (

+             ImagePayload + 1,

+             PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),

+             (VOID **)&Blt,

+             &BltSize,

+             &Height,

+             &Width

+             );

+

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

+  Status = GraphicsOutput->Blt (

+                             GraphicsOutput,

+                             Blt,

+                             EfiBltBufferToVideo,

+                             0,

+                             0,

+                             (UINTN) ImagePayload->OffsetX,

+                             (UINTN) ImagePayload->OffsetY,

+                             Width,

+                             Height,

+                             Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)

+                             );

+

+  FreePool(Blt);

+

+  return Status;

+}

+

+/**

+  Dump FMP information.

+

+  @param[in] ImageInfoSize       The size of ImageInfo, in bytes.

+  @param[in] ImageInfo           A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.

+  @param[in] DescriptorVersion   The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.

+  @param[in] DescriptorCount     The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.

+  @param[in] DescriptorSize      The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.

+  @param[in] PackageVersion      The version of package.

+  @param[in] PackageVersionName  The version name of package.

+**/

+VOID

+DumpFmpImageInfo (

+  IN UINTN                           ImageInfoSize,

+  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR   *ImageInfo,

+  IN UINT32                          DescriptorVersion,

+  IN UINT8                           DescriptorCount,

+  IN UINTN                           DescriptorSize,

+  IN UINT32                          PackageVersion,

+  IN CHAR16                          *PackageVersionName

+  )

+{

+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *CurrentImageInfo;

+  UINTN                                         Index;

+

+  DEBUG((DEBUG_VERBOSE, "  DescriptorVersion  - 0x%x\n", DescriptorVersion));

+  DEBUG((DEBUG_VERBOSE, "  DescriptorCount    - 0x%x\n", DescriptorCount));

+  DEBUG((DEBUG_VERBOSE, "  DescriptorSize     - 0x%x\n", DescriptorSize));

+  DEBUG((DEBUG_VERBOSE, "  PackageVersion     - 0x%x\n", PackageVersion));

+  DEBUG((DEBUG_VERBOSE, "  PackageVersionName - %s\n\n", PackageVersionName));

+  CurrentImageInfo = ImageInfo;

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

+    DEBUG((DEBUG_VERBOSE, "  ImageDescriptor (%d)\n", Index));

+    DEBUG((DEBUG_VERBOSE, "    ImageIndex                  - 0x%x\n", CurrentImageInfo->ImageIndex));

+    DEBUG((DEBUG_VERBOSE, "    ImageTypeId                 - %g\n", &CurrentImageInfo->ImageTypeId));

+    DEBUG((DEBUG_VERBOSE, "    ImageId                     - 0x%lx\n", CurrentImageInfo->ImageId));

+    DEBUG((DEBUG_VERBOSE, "    ImageIdName                 - %s\n", CurrentImageInfo->ImageIdName));

+    DEBUG((DEBUG_VERBOSE, "    Version                     - 0x%x\n", CurrentImageInfo->Version));

+    DEBUG((DEBUG_VERBOSE, "    VersionName                 - %s\n", CurrentImageInfo->VersionName));

+    DEBUG((DEBUG_VERBOSE, "    Size                        - 0x%x\n", CurrentImageInfo->Size));

+    DEBUG((DEBUG_VERBOSE, "    AttributesSupported         - 0x%lx\n", CurrentImageInfo->AttributesSupported));

+    DEBUG((DEBUG_VERBOSE, "    AttributesSetting           - 0x%lx\n", CurrentImageInfo->AttributesSetting));

+    DEBUG((DEBUG_VERBOSE, "    Compatibilities             - 0x%lx\n", CurrentImageInfo->Compatibilities));

+    if (DescriptorVersion > 1) {

+      DEBUG((DEBUG_VERBOSE, "    LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));

+      if (DescriptorVersion > 2) {

+        DEBUG((DEBUG_VERBOSE, "    LastAttemptVersion          - 0x%x\n", CurrentImageInfo->LastAttemptVersion));

+        DEBUG((DEBUG_VERBOSE, "    LastAttemptStatus           - 0x%x\n", CurrentImageInfo->LastAttemptStatus));

+        DEBUG((DEBUG_VERBOSE, "    HardwareInstance            - 0x%lx\n", CurrentImageInfo->HardwareInstance));

+      }

+    }

+    //

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

+    //

+    CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);

+  }

+}

+

+/**

+  Dump a non-nested FMP capsule.

+

+  @param[in]  CapsuleHeader  A pointer to CapsuleHeader

+**/

+VOID

+DumpFmpCapsule (

+  IN EFI_CAPSULE_HEADER                *CapsuleHeader

+  )

+{

+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;

+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;

+  UINTN                                         Index;

+  UINT64                                        *ItemOffsetList;

+

+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);

+

+  DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));

+  DEBUG((DEBUG_VERBOSE, "  Version                - 0x%x\n", FmpCapsuleHeader->Version));

+  DEBUG((DEBUG_VERBOSE, "  EmbeddedDriverCount    - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));

+  DEBUG((DEBUG_VERBOSE, "  PayloadItemCount       - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));

+

+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);

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

+    DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));

+  }

+  for (; Index < (UINTN)(FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount); Index++) {

+    DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));

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

+

+    DEBUG((DEBUG_VERBOSE, "  ImageHeader:\n"));

+    DEBUG((DEBUG_VERBOSE, "    Version                - 0x%x\n", ImageHeader->Version));

+    DEBUG((DEBUG_VERBOSE, "    UpdateImageTypeId      - %g\n", &ImageHeader->UpdateImageTypeId));

+    DEBUG((DEBUG_VERBOSE, "    UpdateImageIndex       - 0x%x\n", ImageHeader->UpdateImageIndex));

+    DEBUG((DEBUG_VERBOSE, "    UpdateImageSize        - 0x%x\n", ImageHeader->UpdateImageSize));

+    DEBUG((DEBUG_VERBOSE, "    UpdateVendorCodeSize   - 0x%x\n", ImageHeader->UpdateVendorCodeSize));

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

+      DEBUG((DEBUG_VERBOSE, "    UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));

+    }

+  }

+}

+

+/**

+  Process Firmware management protocol data capsule.

+

+  This function assumes the caller validated the capsule by using

+  ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,

+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and

+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.

+

+  This function need support nested FMP capsule.

+

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

+  @param[in]  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.

+**/

+EFI_STATUS

+ProcessFmpCapsuleImage (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,

+  OUT BOOLEAN            *AreAllImagesProcessed

+  )

+{

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

+  UINTN                                         Index2;

+  MEMMAP_DEVICE_PATH                            MemMapNode;

+  EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;

+  ESRT_MANAGEMENT_PROTOCOL                      *EsrtProtocol;

+  EFI_SYSTEM_RESOURCE_ENTRY                     EsrtEntry;

+  VOID                                          *VendorCode;

+

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

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

+  }

+

+  ASSERT(AreAllImagesProcessed != NULL);

+

+  Status           = EFI_SUCCESS;

+  StatusRet        = EFI_NOT_FOUND;

+  HandleBuffer     = NULL;

+  ExitDataSize     = 0;

+  DriverDevicePath = NULL;

+  EsrtProtocol     = NULL;

+  *AreAllImagesProcessed = FALSE;

+

+  DumpFmpCapsule(CapsuleHeader);

+

+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);

+

+  if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {

+    return EFI_INVALID_PARAMETER;

+  }

+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);

+

+  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;

+

+  //

+  // capsule in which driver count and payload count are both zero is not processed.

+  //

+  if (ItemNum == 0) {

+    *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) {

+      //

+      // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER

+      //

+      DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];

+    } else {

+      DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];

+    }

+

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

+    if (EFI_ERROR(Status)) {

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

+      StatusRet = Status;

+      goto EXIT;

+    }

+  }

+

+  //

+  // 2. Route payload to right FMP instance

+  //

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

+      }

+

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

+              ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {

+            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

+              );

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

+    }

+  }

+

+  //

+  // final check for AreAllImagesProcessed

+  //

+  *AreAllImagesProcessed = TRUE;

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

+      *AreAllImagesProcessed = FALSE;

+      break;

+    }

+  }

+

+EXIT:

+

+  if (HandleBuffer != NULL) {

+    FreePool(HandleBuffer);

+  }

+

+  if (DriverDevicePath != NULL) {

+    FreePool(DriverDevicePath);

+  }

+

+  return StatusRet;

+}

+

+/**

+  Return if there is a FMP header below capsule header.

+

+  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER

+

+  @retval TRUE  There is a FMP header below capsule header.

+  @retval FALSE There is not a FMP header below capsule header

+**/

+BOOLEAN

+IsNestedFmpCapsule (

+  IN EFI_CAPSULE_HEADER         *CapsuleHeader

+  )

+{

+  EFI_STATUS                 Status;

+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;

+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;

+  UINTN                      Index;

+  BOOLEAN                    EsrtGuidFound;

+  EFI_CAPSULE_HEADER         *NestedCapsuleHeader;

+  UINTN                      NestedCapsuleSize;

+  ESRT_MANAGEMENT_PROTOCOL   *EsrtProtocol;

+  EFI_SYSTEM_RESOURCE_ENTRY  Entry;

+

+  EsrtGuidFound = FALSE;

+

+  //

+  // Check ESRT protocol

+  //

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

+  if (!EFI_ERROR(Status)) {

+    Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);

+    if (!EFI_ERROR(Status)) {

+      EsrtGuidFound = TRUE;

+    }

+  }

+

+  //

+  // Check ESRT configuration table

+  //

+  if (!EsrtGuidFound) {

+    Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);

+    if (!EFI_ERROR(Status)) {

+      ASSERT (Esrt != NULL);

+      EsrtEntry = (VOID *)(Esrt + 1);

+      for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {

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

+          EsrtGuidFound = TRUE;

+          break;

+        }

+      }

+    }

+  }

+  if (!EsrtGuidFound) {

+    return FALSE;

+  }

+

+  //

+  // Check nested capsule header

+  // FMP GUID after ESRT one

+  //

+  NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);

+  NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;

+  if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {

+    return FALSE;

+  }

+  if (!IsValidCapsuleHeader(NestedCapsuleHeader, NestedCapsuleSize)) {

+    return FALSE;

+  }

+  if (!IsFmpCapsuleGuid(&NestedCapsuleHeader->CapsuleGuid)) {

+    return FALSE;

+  }

+  DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));

+  return TRUE;

+}

+

+/**

+  Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.

+

+  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER

+

+  @retval TRUE  It is a system FMP.

+  @retval FALSE It is a device FMP.

+**/

+BOOLEAN

+IsFmpCapsule (

+  IN EFI_CAPSULE_HEADER         *CapsuleHeader

+  )

+{

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

+    return TRUE;

+  }

+  if (IsNestedFmpCapsule(CapsuleHeader)) {

+    return TRUE;

+  }

+  return FALSE;

+}

+

+/**

+  Those capsules supported by the firmwares.

+

+  Caution: This function may receive untrusted input.

+

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

+

+  @retval EFI_SUCESS       Input capsule is supported by firmware.

+  @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.

+  @retval EFI_INVALID_PARAMETER Input capsule layout is not correct

+**/

+EFI_STATUS

+EFIAPI

+SupportCapsuleImage (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader

+  )

+{

+  //

+  // check Display Capsule Guid

+  //

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

+    return EFI_SUCCESS;

+  }

+

+  if (IsFmpCapsule(CapsuleHeader)) {

+    //

+    // Check layout of FMP capsule

+    //

+    return ValidateFmpCapsule(CapsuleHeader, NULL);

+  }

+  DEBUG((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));

+  return EFI_UNSUPPORTED;

+}

+

+/**

+  The firmware implements to process the capsule image.

+

+  Caution: This function may receive untrusted input.

+

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

+

+  @retval EFI_SUCESS            Process Capsule Image successfully.

+  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.

+  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.

+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.

+**/

+EFI_STATUS

+EFIAPI

+ProcessCapsuleImage (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader

+  )

+{

+  EFI_STATUS                   Status;

+  BOOLEAN                      AreAllImagesProcessed;

+

+  if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Display image in firmware update display capsule

+  //

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

+    DEBUG((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));

+    Status = DisplayCapsuleImage(CapsuleHeader);

+    RecordCapsuleStatusVariable(CapsuleHeader, Status);

+    return Status;

+  }

+

+  //

+  // Check FMP capsule layout

+  //

+  if (IsFmpCapsule (CapsuleHeader)) {

+    DEBUG((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));

+    DEBUG((DEBUG_INFO, "ValidateFmpCapsule ...\n"));

+    Status = ValidateFmpCapsule(CapsuleHeader, NULL);

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

+    if (EFI_ERROR(Status)) {

+      return Status;

+    }

+

+    //

+    // Press EFI FMP Capsule

+    //

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

+    Status = ProcessFmpCapsuleImage(CapsuleHeader, &AreAllImagesProcessed);

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

+

+    if (!AreAllImagesProcessed) {

+      mAreAllImagesProcessed = FALSE;

+    }

+

+    return Status;

+  }

+

+  return EFI_UNSUPPORTED;

+}

+

+/**

+  Callback function executed when the EndOfDxe event group is signaled.

+

+  @param[in] Event      Event whose notification function is being invoked.

+  @param[in] Context    The pointer to the notification function's context, which

+                        is implementation-dependent.

+**/

+VOID

+EFIAPI

+DxeCapsuleLibEndOfDxe (

+  IN EFI_EVENT  Event,

+  IN VOID       *Context

+  )

+{

+  mDxeCapsuleLibEndOfDxe = TRUE;

+}

+

+/**

+  The constructor function.

+

+  @param[in]  ImageHandle   The firmware allocated handle for the EFI image.

+  @param[in]  SystemTable   A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS   The constructor successfully .

+**/

+EFI_STATUS

+EFIAPI

+DxeCapsuleLibConstructor (

+  IN EFI_HANDLE         ImageHandle,

+  IN EFI_SYSTEM_TABLE   *SystemTable

+  )

+{

+  EFI_EVENT     EndOfDxeEvent;

+  EFI_STATUS    Status;

+

+  Status = gBS->CreateEventEx (

+                  EVT_NOTIFY_SIGNAL,

+                  TPL_CALLBACK,

+                  DxeCapsuleLibEndOfDxe,

+                  NULL,

+                  &gEfiEndOfDxeEventGroupGuid,

+                  &EndOfDxeEvent

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  InitCapsuleVariable();

+

+  return EFI_SUCCESS;

+}

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
new file mode 100644
index 0000000..5e437dc
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
@@ -0,0 +1,80 @@
+## @file

+#  Capsule library instance for DXE_DRIVER.

+#

+#  Capsule library instance for DXE_DRIVER module types.

+#

+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+#  This program and the accompanying materials

+#  are licensed and made available under the terms and conditions of the BSD License

+#  which accompanies this distribution.  The full text of the license may be found at

+#  http://opensource.org/licenses/bsd-license.php

+#

+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = DxeCapsuleLib

+  MODULE_UNI_FILE                = DxeCapsuleLib.uni

+  FILE_GUID                      = 534E35DE-8EB3-47b3-A4E0-72A571E50733

+  MODULE_TYPE                    = DXE_DRIVER

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = CapsuleLib|DXE_DRIVER UEFI_APPLICATION

+  CONSTRUCTOR                    = DxeCapsuleLibConstructor

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+

+[Sources]

+  DxeCapsuleLib.c

+  DxeCapsuleProcessLib.c

+  DxeCapsuleReportLib.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  MemoryAllocationLib

+  DxeServicesTableLib

+  UefiBootServicesTableLib

+  DevicePathLib

+  ReportStatusCodeLib

+  PrintLib

+  HobLib

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax                               ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag      ## CONSUMES

+

+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule                ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin    ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd      ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware        ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess   ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed    ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem         ## CONSUMES

+

+[Protocols]

+  gEsrtManagementProtocolGuid             ## CONSUMES

+  gEfiFirmwareManagementProtocolGuid      ## SOMETIMES_CONSUMES

+  gEdkiiVariableLockProtocolGuid          ## SOMETIMES_CONSUMES

+

+[Guids]

+  gEfiFmpCapsuleGuid                      ## SOMETIMES_CONSUMES ## GUID

+  gWindowsUxCapsuleGuid                   ## SOMETIMES_CONSUMES ## GUID

+  gEfiSystemResourceTableGuid             ## SOMETIMES_CONSUMES ## GUID

+  gEfiCapsuleReportGuid                   ## CONSUMES ## Variable

+  gEfiCapsuleVendorGuid                   ## CONSUMES ## Variable

+  gEfiEndOfDxeEventGroupGuid              ## CONSUMES ## Event

+

+[Depex]

+  gEfiVariableWriteArchProtocolGuid

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
new file mode 100644
index 0000000..05a80d0
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
@@ -0,0 +1,22 @@
+// /** @file

+// Capsule library instance for DXE_DRIVER.

+//

+// Capsule library instance for DXE_DRIVER module types.

+//

+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+//

+// This program and the accompanying materials

+// are licensed and made available under the terms and conditions of the BSD License

+// which accompanies this distribution.  The full text of the license may be found at

+// http://opensource.org/licenses/bsd-license.php

+//

+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+//

+// **/

+

+

+#string STR_MODULE_ABSTRACT             #language en-US "Capsule Support Library"

+

+#string STR_MODULE_DESCRIPTION          #language en-US "Capsule library instance for DXE_DRIVER module types."

+

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
new file mode 100644
index 0000000..62257a4
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -0,0 +1,475 @@
+/** @file

+  DXE capsule process.

+

+  Caution: This module requires additional review when modified.

+  This module will have external input - capsule image.

+  This external input must be validated carefully to avoid security issue like

+  buffer overflow, integer overflow.

+

+  ProcessCapsules(), ProcessTheseCapsules() will receive untrusted

+  input and do basic validation.

+

+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include <PiDxe.h>

+#include <Protocol/EsrtManagement.h>

+

+#include <Library/BaseLib.h>

+#include <Library/DebugLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiLib.h>

+#include <Library/PcdLib.h>

+#include <Library/HobLib.h>

+#include <Library/ReportStatusCodeLib.h>

+#include <Library/CapsuleLib.h>

+

+#include <IndustryStandard/WindowsUxCapsule.h>

+

+/**

+  Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.

+

+  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER

+

+  @retval TRUE  It is a system FMP.

+  @retval FALSE It is a device FMP.

+**/

+BOOLEAN

+IsFmpCapsule (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader

+  );

+

+/**

+  Validate Fmp capsules layout.

+

+  Caution: This function may receive untrusted input.

+

+  This function assumes the caller validated the capsule by using

+  IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.

+  The capsule buffer size is CapsuleHeader->CapsuleImageSize.

+

+  This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER

+  and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.

+

+  This function need support nested FMP capsule.

+

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

+  @param[out]  EmbeddedDriverCount  The EmbeddedDriverCount in the FMP capsule.

+

+  @retval EFI_SUCESS             Input capsule is a correct FMP capsule.

+  @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.

+**/

+EFI_STATUS

+ValidateFmpCapsule (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,

+  OUT UINT16             *EmbeddedDriverCount OPTIONAL

+  );

+

+/**

+  Validate if it is valid capsule header

+

+  This function assumes the caller provided correct CapsuleHeader pointer

+  and CapsuleSize.

+

+  This function validates the fields in EFI_CAPSULE_HEADER.

+

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

+  @param[in]  CapsuleSize      Size of the whole capsule image.

+

+**/

+BOOLEAN

+IsValidCapsuleHeader (

+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,

+  IN UINT64              CapsuleSize

+  );

+

+extern BOOLEAN                   mDxeCapsuleLibEndOfDxe;

+extern BOOLEAN                   mAreAllImagesProcessed;

+BOOLEAN                          mNeedReset;

+

+/**

+

+  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.

+

+**/

+EFI_STATUS

+ProcessTheseCapsules (

+  IN BOOLEAN  NeedBlockDriver

+  )

+{

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

+

+  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

+  //

+  HobPointer.Raw = GetHobList ();

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

+    if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {

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

+    } else {

+      CapsuleTotalNumber++;

+    }

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

+  }

+

+  //

+  // Init temp Capsule Data table.

+  //

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

+  ASSERT (CapsulePtr != NULL);

+  if (CapsulePtr == NULL) {

+    Status = EFI_OUT_OF_RESOURCES;

+    goto Done;

+  }

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

+  ASSERT (CapsulePtrCache != NULL);

+  if (CapsulePtrCache == NULL) {

+    Status = EFI_OUT_OF_RESOURCES;

+    goto Done;

+  }

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

+  }

+

+  //

+  // Find all capsule images from hob

+  //

+  HobPointer.Raw = GetHobList ();

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

+    CapsulePtr [CapsuleNumber++] = (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

+  //

+

+  //

+  // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating

+  // System to have information persist across a system reset. EFI System Table must

+  // point to an array of capsules that contains the same CapsuleGuid value. And agents

+  // searching for this type capsule will look in EFI System Table and search for the

+  // capsule's Guid and associated pointer to retrieve the data. Two steps below describes

+  // how to sorting the capsules by the unique guid and install the array to EFI System Table.

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

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

+      //

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

+      // If already has the Guid, skip it. Whereas, record it in the CacheArray as

+      // an additional one.

+      //

+      CacheIndex = 0;

+      while (CacheIndex < CacheNumber) {

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

+          break;

+        }

+        CacheIndex++;

+      }

+      if (CacheIndex == CacheNumber) {

+        CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));

+      }

+    }

+  }

+

+  //

+  // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules

+  // whose guid is the same as it, and malloc memory for an array which preceding

+  // with UINT32. The array fills with entry point of capsules that have the same

+  // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install

+  // this array into EFI System Table, so that agents searching for this type capsule

+  // 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) {

+    CapsuleNumber = 0;

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

+      CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [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;

+      }

+      CapsuleTable->CapsuleArrayNumber =  CapsuleNumber;

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

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

+      ASSERT_EFI_ERROR (Status);

+    }

+    CacheIndex++;

+  }

+

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

+

+  //

+  // 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)) {

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

+      DisplayCapsuleExist = TRUE;

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

+      Status = ProcessCapsuleImage (CapsuleHeader);

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

+      CapsuleStatusArray [Index] = Status;

+      break;

+    }

+  }

+

+  if (!DisplayCapsuleExist) {

+    //

+    // Display Capsule not found. Display the default string.

+    //

+    Print (L"Updating the firmware ......\r\n");

+  }

+

+  //

+  // All capsules left are recognized by platform.

+  //

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

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

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

+      //

+      // Call capsule library to process capsule image.

+      //

+      EmbeddedDriverCount = 0;

+      if (IsFmpCapsule(CapsuleHeader)) {

+        Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount);

+        if (EFI_ERROR(Status)) {

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

+          continue;

+        }

+      }

+

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

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

+        Status = ProcessCapsuleImage (CapsuleHeader);

+        CapsuleStatusArray [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 ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||

+            IsFmpCapsule(CapsuleHeader)) {

+          mNeedReset = TRUE;

+        }

+      }

+    }

+  }

+

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

+  //

+  // Always sync ESRT Cache from FMP Instance

+  //

+  if (!EFI_ERROR(Status)) {

+    EsrtManagement->SyncEsrtFmp();

+  }

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

+}

+

+/**

+  Do reset system.

+**/

+VOID

+DoResetSystem (

+  VOID

+  )

+{

+  UINTN                         Index;

+

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

+

+  Print(L"Capsule Request Cold Reboot.\n");

+  DEBUG((DEBUG_INFO, "Capsule Request Cold Reboot."));

+

+  for (Index = 5; Index > 0; Index--) {

+    Print(L"\rResetting system in %d seconds ...", Index);

+    DEBUG((DEBUG_INFO, "\rResetting system in %d seconds ...", Index));

+    gBS->Stall(1000000);

+  }

+

+  gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);

+

+  CpuDeadLoop();

+}

+

+/**

+

+  This routine is called to process capsules.

+

+  Caution: This function may receive untrusted input.

+

+  The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.

+  If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.

+

+  This routine should be called twice in BDS.

+  1) The first call must be before EndOfDxe. The system capsules is processed.

+     If device capsule FMP protocols are exposted at this time and device FMP

+     capsule has zero EmbeddedDriverCount, the device capsules are processed.

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

+     System may reset in this function, if reset is required by capsule and

+     all capsules are processed.

+     If not all capsules are processed, reset will be defered to second call.

+

+  2) The second call must be after EndOfDxe and after ConnectAll, so that all

+     device capsule FMP protocols are exposed.

+     The system capsules are skipped. If the device capsules are NOT processed

+     in first call, they are processed here.

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

+     System may reset in this function, if reset is required by capsule

+     processed in first call and second call.

+

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

+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.

+

+**/

+EFI_STATUS

+EFIAPI

+ProcessCapsules (

+  VOID

+  )

+{

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

+      DoResetSystem();

+    }

+  } else {

+    Status = ProcessTheseCapsules(FALSE);

+    //

+    // Reboot System if required after all capsule processed

+    //

+    if (mNeedReset) {

+      DoResetSystem();

+    }

+  }

+  return Status;

+}

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
new file mode 100644
index 0000000..07e9e46
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
@@ -0,0 +1,57 @@
+/** @file

+  DXE capsule process.

+  Dummy function for runtime module, because CapsuleDxeRuntime

+  does not need call ProcessCapsules().

+

+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include <PiDxe.h>

+#include <Library/CapsuleLib.h>

+

+/**

+

+  This routine is called to process capsules.

+

+  Caution: This function may receive untrusted input.

+

+  The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.

+  If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.

+

+  This routine should be called twice in BDS.

+  1) The first call must be before EndOfDxe. The system capsules is processed.

+     If device capsule FMP protocols are exposted at this time and device FMP

+     capsule has zero EmbeddedDriverCount, the device capsules are processed.

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

+     System may reset in this function, if reset is required by capsule and

+     all capsules are processed.

+     If not all capsules are processed, reset will be defered to second call.

+

+  2) The second call must be after EndOfDxe and after ConnectAll, so that all

+     device capsule FMP protocols are exposed.

+     The system capsules are skipped. If the device capsules are NOT processed

+     in first call, they are processed here.

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

+     System may reset in this function, if reset is required by capsule

+     processed in first call and second call.

+

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

+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.

+

+**/

+EFI_STATUS

+EFIAPI

+ProcessCapsules (

+  VOID

+  )

+{

+  return EFI_UNSUPPORTED;

+}

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
new file mode 100644
index 0000000..a0ed2d0
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
@@ -0,0 +1,489 @@
+/** @file

+  DXE capsule report related function.

+

+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include <PiDxe.h>

+#include <Protocol/FirmwareManagement.h>

+#include <Protocol/VariableLock.h>

+#include <Guid/CapsuleReport.h>

+#include <Guid/FmpCapsule.h>

+#include <Guid/CapsuleVendor.h>

+

+#include <Library/BaseLib.h>

+#include <Library/DebugLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+#include <Library/MemoryAllocationLib.h>

+#include <Library/UefiLib.h>

+#include <Library/PcdLib.h>

+#include <Library/HobLib.h>

+#include <Library/PrintLib.h>

+#include <Library/ReportStatusCodeLib.h>

+#include <Library/CapsuleLib.h>

+

+#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.

+

+  @return Current capsule last variable index.

+  @retval -1  No current capsule last variable.

+**/

+INTN

+GetCurrentCapsuleLastIndex (

+  VOID

+  )

+{

+  UINTN                            Size;

+  CHAR16                           CapsuleLastStr[sizeof("Capsule####")];

+  EFI_STATUS                       Status;

+  UINT16                           CurrentIndex;

+

+  Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator

+  Status = gRT->GetVariable(

+                  L"CapsuleLast",

+                  &gEfiCapsuleReportGuid,

+                  NULL,

+                  &Size,

+                  CapsuleLastStr

+                  );

+  if (EFI_ERROR(Status)) {

+    return -1;

+  }

+  CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);

+  return CurrentIndex;

+}

+

+/**

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

+          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.

+  @retval -1  No new capsule status variable index.

+**/

+INTN

+GetNewCapsuleResultIndex (

+  VOID

+  )

+{

+  INTN                             CurrentIndex;

+

+  CurrentIndex = GetCurrentCapsuleLastIndex();

+  if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {

+    return -1;

+  }

+

+  return CurrentIndex + 1;

+}

+

+/**

+  Write a new capsule status variable.

+

+  @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 recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+WriteNewCapsuleResultVariable (

+  IN VOID    *CapsuleResult,

+  IN UINTN   CapsuleResultSize

+  )

+{

+  INTN                                CapsuleResultIndex;

+  CHAR16                              CapsuleResultStr[sizeof("Capsule####")];

+  UINTN                               Size;

+  EFI_STATUS                          Status;

+

+  CapsuleResultIndex = GetNewCapsuleResultIndex();

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

+  if (CapsuleResultIndex == -1) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+  UnicodeSPrint(

+    CapsuleResultStr,

+    sizeof(CapsuleResultStr),

+    L"Capsule%04x",

+    CapsuleResultIndex

+    );

+

+  Status = gRT->SetVariable(

+                  CapsuleResultStr,

+                  &gEfiCapsuleReportGuid,

+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,

+                  CapsuleResultSize,

+                  CapsuleResult

+                  );

+  if (!EFI_ERROR(Status)) {

+    Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator

+    DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));

+    Status = gRT->SetVariable(

+                    L"CapsuleLast",

+                    &gEfiCapsuleReportGuid,

+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,

+                    Size,

+                    CapsuleResultStr

+                    );

+  }

+

+  return Status;

+}

+

+/**

+  Record capsule status variable and to local cache.

+

+  @param[in] CapsuleHeader  The capsule image header

+  @param[in] CapsuleStatus  The capsule process stauts

+

+  @retval EFI_SUCCESS          The capsule status variable is recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+RecordCapsuleStatusVariable (

+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,

+  IN EFI_STATUS                                   CapsuleStatus

+  )

+{

+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  CapsuleResultVariable;

+  EFI_STATUS                          Status;

+

+  CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);

+  CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);

+  ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));

+  gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);

+  CapsuleResultVariable.CapsuleStatus = CapsuleStatus;

+

+  //

+  // Save Local Cache

+  //

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

+

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

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

+  }

+  return Status;

+}

+

+/**

+  Record FMP capsule status variable and to local cache.

+

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

+

+  @retval EFI_SUCCESS          The capsule status variable is recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+RecordFmpCapsuleStatusVariable (

+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,

+  IN EFI_STATUS                                    CapsuleStatus,

+  IN UINTN                                         PayloadIndex,

+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader

+  )

+{

+  UINT8                               CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)];

+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResultVariableHeader;

+  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultVariableFmp;

+  EFI_STATUS                          Status;

+

+  CapsuleResultVariableHeader = (VOID *)&CapsuleResultVariable[0];

+  CapsuleResultVariableHeader->VariableTotalSize = sizeof(CapsuleResultVariable);

+  CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);

+  ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));

+  gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);

+  CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;

+

+  CapsuleResultVariableFmp = (VOID *)&CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)];

+  CapsuleResultVariableFmp->Version = 0x1;

+  CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;

+  CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;

+  CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);

+

+  //

+  // Save Local Cache

+  //

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

+

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

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

+  }

+  return Status;

+}

+

+/**

+  Initialize CapsuleMax variables.

+**/

+VOID

+InitCapsuleMaxVariable (

+  VOID

+  )

+{

+  EFI_STATUS                       Status;

+  UINTN                            Size;

+  CHAR16                           CapsuleMaxStr[sizeof("Capsule####")];

+  EDKII_VARIABLE_LOCK_PROTOCOL     *VariableLock;

+

+  UnicodeSPrint(

+    CapsuleMaxStr,

+    sizeof(CapsuleMaxStr),

+    L"Capsule%04x",

+    PcdGet16(PcdCapsuleMax)

+    );

+

+  Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator

+  Status = gRT->SetVariable(

+                  L"CapsuleMax",

+                  &gEfiCapsuleReportGuid,

+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,

+                  Size,

+                  CapsuleMaxStr

+                  );

+  if (!EFI_ERROR(Status)) {

+    // Lock it per UEFI spec.

+    Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);

+    if (!EFI_ERROR(Status)) {

+      Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);

+      ASSERT_EFI_ERROR(Status);

+    }

+  }

+}

+

+/**

+  Initialize CapsuleLast variables.

+**/

+VOID

+InitCapsuleLastVariable (

+  VOID

+  )

+{

+  EFI_STATUS                       Status;

+  EFI_BOOT_MODE                    BootMode;

+  EDKII_VARIABLE_LOCK_PROTOCOL     *VariableLock;

+  VOID                             *CapsuleResult;

+  UINTN                            Size;

+  CHAR16                           CapsuleLastStr[sizeof("Capsule####")];

+

+  BootMode = GetBootModeHob();

+  if (BootMode == BOOT_ON_FLASH_UPDATE) {

+    Status = gRT->SetVariable(

+                    L"CapsuleLast",

+                    &gEfiCapsuleReportGuid,

+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,

+                    0,

+                    NULL

+                    );

+    // Do not lock it because it will be updated later.

+  } else {

+    //

+    // Check if OS/APP cleared L"Capsule####"

+    //

+    ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));

+    Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator

+    Status = gRT->GetVariable(

+                    L"CapsuleLast",

+                    &gEfiCapsuleReportGuid,

+                    NULL,

+                    &Size,

+                    CapsuleLastStr

+                    );

+    if (!EFI_ERROR(Status)) {

+      //

+      // L"CapsuleLast" is got, check if data is there.

+      //

+      Status = GetVariable2 (

+                 CapsuleLastStr,

+                 &gEfiCapsuleReportGuid,

+                 (VOID **) &CapsuleResult,

+                 NULL

+                 );

+      if (EFI_ERROR(Status)) {

+        //

+        // If no data, delete L"CapsuleLast"

+        //

+        Status = gRT->SetVariable(

+                        L"CapsuleLast",

+                        &gEfiCapsuleReportGuid,

+                        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,

+                        0,

+                        NULL

+                        );

+      }

+    }

+

+    // Lock it in normal boot path per UEFI spec.

+    Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);

+    if (!EFI_ERROR(Status)) {

+      Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);

+      ASSERT_EFI_ERROR(Status);

+    }

+  }

+}

+

+/**

+  Initialize capsule update variables.

+**/

+VOID

+InitCapsuleUpdateVariable (

+  VOID

+  )

+{

+  EFI_STATUS                     Status;

+  UINTN                          Index;

+  CHAR16                         CapsuleVarName[30];

+  CHAR16                         *TempVarName;

+

+  //

+  // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...

+  // as early as possible which will avoid the next time boot after the capsule update

+  // will still into the capsule loop

+  //

+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);

+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);

+  Index = 0;

+  while (TRUE) {

+    if (Index > 0) {

+      UnicodeValueToString (TempVarName, 0, Index, 0);

+    }

+    Status = gRT->SetVariable (

+                    CapsuleVarName,

+                    &gEfiCapsuleVendorGuid,

+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,

+                    0,

+                    (VOID *)NULL

+                    );

+    if (EFI_ERROR (Status)) {

+      //

+      // There is no capsule variables, quit

+      //

+      break;

+    }

+    Index++;

+  }

+}

+

+/**

+  Initialize capsule related variables.

+**/

+VOID

+InitCapsuleVariable (

+  VOID

+  )

+{

+  InitCapsuleUpdateVariable();

+  InitCapsuleMaxVariable();

+  InitCapsuleLastVariable();

+  //

+  // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"

+  // to check status and delete them.

+  //

+}

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
new file mode 100644
index 0000000..bf550e5
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
@@ -0,0 +1,91 @@
+/** @file

+  DXE capsule report related function.

+  Dummy function for runtime module, because CapsuleDxeRuntime

+  does not need record capsule status variable.

+

+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include <PiDxe.h>

+#include <Protocol/FirmwareManagement.h>

+#include <Guid/FmpCapsule.h>

+#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

+  @param[in] CapsuleStatus  The capsule process stauts

+

+  @retval EFI_SUCCESS          The capsule status variable is recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+RecordCapsuleStatusVariable (

+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,

+  IN EFI_STATUS                                   CapsuleStatus

+  )

+{

+  return EFI_UNSUPPORTED;

+}

+

+/**

+  Record FMP capsule status variable and to local cache.

+

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

+

+  @retval EFI_SUCCESS          The capsule status variable is recorded.

+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.

+**/

+EFI_STATUS

+RecordFmpCapsuleStatusVariable (

+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,

+  IN EFI_STATUS                                    CapsuleStatus,

+  IN UINTN                                         PayloadIndex,

+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader

+  )

+{

+  return EFI_UNSUPPORTED;

+}

+

+/**

+  Initialize capsule related variables.

+**/

+VOID

+InitCapsuleVariable (

+  VOID

+  )

+{

+  return;

+}

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
new file mode 100644
index 0000000..8801439
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
@@ -0,0 +1,112 @@
+/** @file

+  Capsule library runtime support.

+

+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+  This program and the accompanying materials

+  are licensed and made available under the terms and conditions of the BSD License

+  which accompanies this distribution.  The full text of the license may be found at

+  http://opensource.org/licenses/bsd-license.php

+

+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+

+**/

+

+#include <PiDxe.h>

+

+#include <Guid/FmpCapsule.h>

+#include <Guid/SystemResourceTable.h>

+#include <Guid/EventGroup.h>

+

+#include <Library/BaseLib.h>

+#include <Library/DebugLib.h>

+#include <Library/BaseMemoryLib.h>

+#include <Library/DxeServicesTableLib.h>

+#include <Library/UefiBootServicesTableLib.h>

+#include <Library/UefiRuntimeServicesTableLib.h>

+#include <Library/MemoryAllocationLib.h>

+

+extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;

+extern BOOLEAN                   mIsVirtualAddrConverted;

+

+/**

+  Convert EsrtTable physical address to virtual address.

+

+  @param[in] Event      Event whose notification function is being invoked.

+  @param[in] Context    The pointer to the notification function's context, which

+                        is implementation-dependent.

+**/

+VOID

+EFIAPI

+DxeCapsuleLibVirtualAddressChangeEvent (

+  IN  EFI_EVENT   Event,

+  IN  VOID        *Context

+  )

+{

+  UINTN                    Index;

+  EFI_CONFIGURATION_TABLE  *ConfigEntry;

+

+  //

+  // Get Esrt table first

+  //

+  ConfigEntry = gST->ConfigurationTable;

+  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {

+    if (CompareGuid(&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {

+      break;

+    }

+    ConfigEntry++;

+  }

+

+  //

+  // If no Esrt table installed in Configure Table

+  //

+  if (Index < gST->NumberOfTableEntries) {

+    //

+    // Search Esrt to check given capsule is qualified

+    //

+    mEsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *) ConfigEntry->VendorTable;

+

+    //

+    // Update protocol pointer to Esrt Table.

+    //

+    gRT->ConvertPointer (0x00, (VOID**) &(mEsrtTable));

+  }

+

+  mIsVirtualAddrConverted = TRUE;

+

+}

+

+/**

+  The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.

+

+  @param  ImageHandle   The firmware allocated handle for the EFI image.

+  @param  SystemTable   A pointer to the EFI System Table.

+

+  @retval EFI_SUCCESS   The constructor successfully .

+**/

+EFI_STATUS

+EFIAPI

+DxeRuntimeCapsuleLibConstructor (

+  IN EFI_HANDLE         ImageHandle,

+  IN EFI_SYSTEM_TABLE   *SystemTable

+  )

+{

+  EFI_STATUS     Status;

+  EFI_EVENT      Event;

+

+  //

+  // Make sure we can handle virtual address changes.

+  //

+  Event = NULL;

+  Status = gBS->CreateEventEx (

+                  EVT_NOTIFY_SIGNAL,

+                  TPL_NOTIFY,

+                  DxeCapsuleLibVirtualAddressChangeEvent,

+                  NULL,

+                  &gEfiEventVirtualAddressChangeGuid,

+                  &Event

+                  );

+  ASSERT_EFI_ERROR (Status);

+

+  return EFI_SUCCESS;

+}

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
new file mode 100644
index 0000000..88a3c61
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
@@ -0,0 +1,83 @@
+## @file

+#  Capsule library instance for DXE_RUNTIME_DRIVER.

+#

+#  Capsule library instance for DXE_RUNTIME_DRIVER module types.

+#

+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+#  This program and the accompanying materials

+#  are licensed and made available under the terms and conditions of the BSD License

+#  which accompanies this distribution.  The full text of the license may be found at

+#  http://opensource.org/licenses/bsd-license.php

+#

+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+#

+##

+

+[Defines]

+  INF_VERSION                    = 0x00010005

+  BASE_NAME                      = DxeRuntimeCapsuleLib

+  MODULE_UNI_FILE                = DxeRuntimeCapsuleLib.uni

+  FILE_GUID                      = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A

+  MODULE_TYPE                    = DXE_DRIVER

+  VERSION_STRING                 = 1.0

+  LIBRARY_CLASS                  = CapsuleLib|DXE_RUNTIME_DRIVER

+  CONSTRUCTOR                    = DxeCapsuleLibConstructor

+  CONSTRUCTOR                    = DxeRuntimeCapsuleLibConstructor

+

+#

+# The following information is for reference only and not required by the build tools.

+#

+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC

+#

+

+[Sources]

+  DxeCapsuleLib.c

+  DxeCapsuleProcessLibNull.c

+  DxeCapsuleReportLibNull.c

+  DxeCapsuleRuntime.c

+

+[Packages]

+  MdePkg/MdePkg.dec

+  MdeModulePkg/MdeModulePkg.dec

+

+[LibraryClasses]

+  BaseLib

+  BaseMemoryLib

+  DebugLib

+  MemoryAllocationLib

+  DxeServicesTableLib

+  UefiBootServicesTableLib

+  DevicePathLib

+  ReportStatusCodeLib

+  PrintLib

+  HobLib

+

+[Pcd]

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax                               ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag      ## CONSUMES

+

+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule                ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin    ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd      ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware        ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess   ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed    ## CONSUMES

+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem         ## CONSUMES

+

+[Protocols]

+  gEsrtManagementProtocolGuid             ## CONSUMES

+  gEfiFirmwareManagementProtocolGuid      ## SOMETIMES_CONSUMES

+  gEdkiiVariableLockProtocolGuid          ## SOMETIMES_CONSUMES

+

+[Guids]

+  gEfiFmpCapsuleGuid                      ## SOMETIMES_CONSUMES ## GUID

+  gWindowsUxCapsuleGuid                   ## SOMETIMES_CONSUMES ## GUID

+  gEfiSystemResourceTableGuid             ## SOMETIMES_CONSUMES ## GUID

+  gEfiCapsuleReportGuid                   ## CONSUMES ## Variable

+  gEfiCapsuleVendorGuid                   ## CONSUMES ## Variable

+  gEfiEndOfDxeEventGroupGuid              ## CONSUMES ## Event

+  gEfiEventVirtualAddressChangeGuid       ## CONSUMES ## Event

+

+[Depex]

+  gEfiVariableWriteArchProtocolGuid

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
new file mode 100644
index 0000000..cd89b13
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
@@ -0,0 +1,22 @@
+// /** @file

+// Capsule library instance for DXE_RUNTIME_DRIVER.

+//

+// Capsule library instance for DXE_RUNTIME_DRIVER module types.

+//

+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>

+//

+// This program and the accompanying materials

+// are licensed and made available under the terms and conditions of the BSD License

+// which accompanies this distribution.  The full text of the license may be found at

+// http://opensource.org/licenses/bsd-license.php

+//

+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

+//

+// **/

+

+

+#string STR_MODULE_ABSTRACT             #language en-US "Capsule Support Library"

+

+#string STR_MODULE_DESCRIPTION          #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."

+