This instance handles Microsoft UX capsule, UEFI defined device FMP capsule,
and EDKII system FMP capsule.

Cc: Feng Tian <feng.t...@intel.com>
Cc: Star Zeng <star.z...@intel.com>
Cc: Michael D Kinney <michael.d.kin...@intel.com>
Cc: Liming Gao <liming....@intel.com>
Cc: Chao Zhang <chao.b.zh...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen....@intel.com>
Reviewed-by: Liming Gao <liming....@intel.com>
---
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c          | 1543 
++++++++++++++++++++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf        |   82 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni        |   22 +
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c   |  517 +++++++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c    |  447 ++++++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c      |  112 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf |   85 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni |   22 +
 8 files changed, 2830 insertions(+)

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c 
b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
new file mode 100644
index 0000000..e35ac6f
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -0,0 +1,1543 @@
+/** @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/EdkiiSystemFmpCapsule.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/EdkiiSystemCapsuleLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/DevicePath.h>
+
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable              = NULL;
+BOOLEAN                   mIsVirtualAddrConverted  = FALSE;
+BOOLEAN                   mDxeCapsuleLibEndOfDxe   = FALSE;
+
+GUID      *mEdkiiSystemFmpCapsuleImageTypeIdGuid;
+UINTN     mEdkiiSystemFmpCapsuleImageTypeIdGuidCount;
+
+/**
+  Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable(
+  VOID
+  );
+
+/**
+  Check if this FMP capsule is recorded.
+
+  @param CapsuleHeader  The capsule image header
+  @param PayloadIndex   FMP payload index
+  @param ImageHeader    FMP image header
+
+  @retval TRUE  This FMP capsule is recorded.
+  @retval FALSE This FMP capsule is not recorded.
+**/
+BOOLEAN
+IsFmpCapsuleVariableRecorded(
+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,
+  IN UINTN                                        PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader
+  );
+
+/**
+  Record capsule status variable.
+
+  @param CapsuleHeader  The capsule image header
+  @param 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 CapsuleHeader  The capsule image header
+  @param CapsuleStatus  The capsule process stauts
+  @param PayloadIndex   FMP payload index
+  @param 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  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 FMP is a system FMP or a device FMP, based upon FmpImageInfo.
+
+  @param[in] FmpImageHeader A pointer to 
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
+
+  @retval TRUE  It is a system FMP.
+  @retval FALSE It is a device FMP.
+**/
+BOOLEAN
+IsSystemFmpImage (
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER   *FmpImageHeader
+  )
+{
+  GUID      *Guid;
+  UINTN     Count;
+  UINTN     Index;
+
+  Guid = mEdkiiSystemFmpCapsuleImageTypeIdGuid;
+  Count = mEdkiiSystemFmpCapsuleImageTypeIdGuidCount;
+
+  for (Index = 0; Index < Count; Index++, Guid++) {
+    if (CompareGuid(&FmpImageHeader->UpdateImageTypeId, Guid)) {
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  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;
+}
+
+/**
+  This function assumes the input Capusule image already passes basic check in
+  ValidateFmpCapsule().
+
+  Criteria of system FMP capsule is:
+  1) FmpCapsuleHeader->EmbeddedDriverCount is 0.
+  2) FmpCapsuleHeader->PayloadItemCount is not 0.
+  3) All ImageHeader->UpdateImageTypeId matches 
PcdEdkiiSystemFmpCapsuleImageTypeIdGuid.
+
+  @param  CapsuleHeader    Points to a capsule header.
+
+  @retval TRUE   Input capsule is a correct system FMP capsule.
+  @retval FALSE  Input capsule is not a correct system FMP capsule.
+**/
+BOOLEAN
+IsSystemFmpCapsuleImage (
+  IN EFI_CAPSULE_HEADER *CapsuleHeader
+  )
+{
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+  UINT64                                       *ItemOffsetList;
+  UINT32                                       ItemNum;
+  UINTN                                        Index;
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) 
CapsuleHeader + CapsuleHeader->HeaderSize);
+
+  if (FmpCapsuleHeader->EmbeddedDriverCount != 0) {
+    return FALSE;
+  }
+
+  if (FmpCapsuleHeader->PayloadItemCount == 0) {
+    return FALSE;
+  }
+
+  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + 
FmpCapsuleHeader->PayloadItemCount;
+
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+  for (Index = 0; Index < ItemNum; Index++) {
+    ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 
*)FmpCapsuleHeader + ItemOffsetList[Index]);
+    if (!IsSystemFmpImage(ImageHeader)) {
+      return FALSE;
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+  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  CapsuleHeader    Points to a capsule header.
+  @param  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]  IsSystemFmp          If it is a system FMP.
+  @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 BOOLEAN           *IsSystemFmp, OPTIONAL
+  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), IsSystemFmp, EmbeddedDriverCount);
+  }
+
+  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+    DEBUG((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_ERROR, "ItemOffsetList[%d](0x%lx) >= 
FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
+      return EFI_INVALID_PARAMETER;
+    }
+    if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
+      DEBUG((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_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((EFI_D_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", 
EndOfPayload, EndOfCapsule));
+      return EFI_INVALID_PARAMETER;
+    }
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Check in system FMP capsule
+  //
+  if (IsSystemFmp != NULL) {
+    *IsSystemFmp = IsSystemFmpCapsuleImage(CapsuleHeader);
+  }
+
+  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  BmpImage      Pointer to BMP file
+  @param  BmpImageSize  Number of bytes in BmpImage
+  @param  GopBlt        Buffer containing GOP version of BmpImage.
+  @param  GopBltSize    Size of GopBlt in bytes.
+  @param  PixelHeight   Height of GopBlt/BmpImage in pixels
+  @param  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  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 ImageInfoSize       The size of ImageInfo, in bytes.
+  @param ImageInfo           A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param DescriptorVersion   The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param DescriptorCount     The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param DescriptorSize      The size of an individual 
EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+  @param PackageVersion      The version of package.
+  @param 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  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 System 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 assumes nested FMP capsule is handled by 
ProcessFmpCapsuleImage.
+
+  @param  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
+DispatchSystemFmpImages (
+  IN EFI_CAPSULE_HEADER *CapsuleHeader
+  )
+{
+  UINTN                                         Length;
+  VOID                                          *Image;
+  EFI_STATUS                                    Status;
+  VOID                                          *AuthenticatedImage;
+  UINTN                                         AuthenticatedImageSize;
+  UINT32                                        LastAttemptVersion;
+  UINT32                                        LastAttemptStatus;
+  VOID                                          *DispatchFvImage;
+  UINTN                                         DispatchFvImageSize;
+  EFI_HANDLE                                    FvProtocolHandle;
+  EFI_FIRMWARE_VOLUME_HEADER                    *FvImage;
+  BOOLEAN                                       Result;
+  UINTN                                         ItemIndex;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
+  UINT64                                        *ItemOffsetList;
+
+  DEBUG((EFI_D_INFO, "DispatchSystemFmpImages\n"));
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 
*)CapsuleHeader + CapsuleHeader->HeaderSize);
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+  for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; 
ItemIndex++) {
+    ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 
*)FmpCapsuleHeader + ItemOffsetList[ItemIndex]);
+    if (ImageHeader->Version >= 
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+      Image = (UINT8 *)(ImageHeader + 1);
+    } else {
+      //
+      // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, 
only match ImageTypeId.
+      // Header should exclude UpdateHardwareInstance field
+      //
+      Image = (UINT8 *)ImageHeader + 
OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+    }
+    Length = ImageHeader->UpdateImageSize;
+
+    //
+    // Verify
+    //
+    Status = CapsuleAuthenticateSystemFirmware(Image, Length, FALSE, 
&LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, 
&AuthenticatedImageSize);
+    if (EFI_ERROR(Status)) {
+      DEBUG((EFI_D_INFO, "SystemFirmwareAuthenticateImage - %r\n", Status));
+      return Status;
+    }
+
+    //
+    // Get FV
+    //
+    Result = ExtractDriverFvImage(AuthenticatedImage, AuthenticatedImageSize, 
&DispatchFvImage, &DispatchFvImageSize);
+    if (Result) {
+      DEBUG((EFI_D_INFO, "ExtractDriverFvImage\n"));
+      //
+      // Dispatch
+      //
+      if (((EFI_FIRMWARE_VOLUME_HEADER *)DispatchFvImage)->FvLength == 
DispatchFvImageSize) {
+        FvImage = AllocatePages(EFI_SIZE_TO_PAGES(DispatchFvImageSize));
+        if (FvImage != NULL) {
+          CopyMem(FvImage, DispatchFvImage, DispatchFvImageSize);
+          Status = gDS->ProcessFirmwareVolume(
+                          (VOID *)FvImage,
+                          (UINTN)FvImage->FvLength,
+                          &FvProtocolHandle
+                          );
+          DEBUG((EFI_D_INFO, "ProcessFirmwareVolume - %r\n", Status));
+          if (!EFI_ERROR(Status)) {
+            gDS->Dispatch();
+            DEBUG((EFI_D_INFO, "Dispatch Done\n"));
+          }
+        }
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  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  CapsuleHeader         Points to a capsule header.
+  @param  IsSystemFmp           If this capsule is a system FMP capsule.
+
+  @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,
+  IN BOOLEAN            IsSystemFmp
+  )
+{
+  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), IsSystemFmp);
+  }
+
+  Status           = EFI_SUCCESS;
+  StatusRet        = EFI_NOT_FOUND;
+  HandleBuffer     = NULL;
+  ExitDataSize     = 0;
+  DriverDevicePath = NULL;
+  EsrtProtocol     = NULL;
+
+  DumpFmpCapsule(CapsuleHeader);
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) 
CapsuleHeader + CapsuleHeader->HeaderSize);
+
+  if (FmpCapsuleHeader->Version > 
EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+    return EFI_INVALID_PARAMETER;
+  }
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + 
FmpCapsuleHeader->PayloadItemCount;
+
+  //
+  // capsule in which driver count and payload count are both zero is not 
processed.
+  //
+  if (ItemNum == 0) {
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Update corresponding ESRT entry LastAttemp Status
+  //
+  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID 
**)&EsrtProtocol);
+  if (EFI_ERROR (Status)) {
+    EsrtProtocol = NULL;
+  }
+
+  //
+  // 1. For system FMP, the images are insides of FmpPayload
+  //
+  if (IsSystemFmp) {
+    Status = DispatchSystemFmpImages(CapsuleHeader);
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  }
+
+  //
+  // 2. 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((EFI_D_INFO, "FmpCapsule: LoadImage ...\n"));
+    Status = gBS->LoadImage(
+                    FALSE,
+                    gImageHandle,
+                    DriverDevicePath,
+                    (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
+                    DriverLen,
+                    &ImageHandle
+                    );
+    DEBUG((EFI_D_INFO, "FmpCapsule: LoadImage - %r\n", Status));
+    if (EFI_ERROR(Status)) {
+      StatusRet = Status;
+      goto EXIT;
+    }
+
+    DEBUG((EFI_D_INFO, "FmpCapsule: StartImage ...\n"));
+    Status = gBS->StartImage(
+                    ImageHandle,
+                    &ExitDataSize,
+                    NULL
+                    );
+    DEBUG((EFI_D_INFO, "FmpCapsule: StartImage - %r\n", Status));
+    if (EFI_ERROR(Status)) {
+      DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+      StatusRet = Status;
+      goto EXIT;
+    }
+  }
+
+  //
+  // 3. Route payload to right FMP instance
+  //
+  DEBUG((EFI_D_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((EFI_D_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 (IsFmpCapsuleVariableRecorded(CapsuleHeader, Index - 
FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {
+            DEBUG((EFI_D_INFO, "FMP Capsule already processed (%g):", 
CapsuleHeader));
+            DEBUG((EFI_D_INFO, "ImageTypeId - %g, ", 
ImageHeader->UpdateImageTypeId));
+            DEBUG((EFI_D_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((EFI_D_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((EFI_D_INFO, "Fmp->SetImage - %r\n", Status));
+            if (AbortReason != NULL) {
+              DEBUG ((EFI_D_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);
+    }
+  }
+
+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)) {
+      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 ((EFI_D_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  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, NULL);
+  }
+  DEBUG((EFI_D_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  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                      IsSystemFmp;
+
+  if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Display image in firmware update display capsule
+  //
+  if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+    DEBUG((EFI_D_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
+    Status = DisplayCapsuleImage(CapsuleHeader);
+    RecordCapsuleStatusVariable(CapsuleHeader, Status);
+    return Status;
+  }
+
+  //
+  // Check FMP capsule layout
+  //
+  if (IsFmpCapsule (CapsuleHeader)) {
+    DEBUG((EFI_D_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
+    DEBUG((EFI_D_INFO, "ValidateFmpCapsule ...\n"));
+    Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, NULL);
+    DEBUG((EFI_D_INFO, "ValidateFmpCapsule - %r\n", Status));
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+
+    //
+    // Press EFI FMP Capsule
+    //
+    DEBUG((EFI_D_INFO, "ProcessFmpCapsuleImage ...\n"));
+    Status = ProcessFmpCapsuleImage(CapsuleHeader, IsSystemFmp);
+    DEBUG((EFI_D_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
+
+    return Status;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Callback function executed when the EndOfDxe event group is signaled.
+
+  @param[in] Event      Event whose notification function is being invoked.
+  @param[in] Context    The pointer to the notification function's context, 
which
+                        is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibEndOfDxe(
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  mDxeCapsuleLibEndOfDxe = TRUE;
+}
+
+/**
+  The constructor function.
+
+  @param  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
+DxeCapsuleLibConstructor(
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_EVENT     EndOfDxeEvent;
+  EFI_STATUS    Status;
+
+  mEdkiiSystemFmpCapsuleImageTypeIdGuidCount = 
PcdGetSize(PcdEdkiiSystemFmpCapsuleImageTypeIdGuid) / sizeof(GUID);
+  mEdkiiSystemFmpCapsuleImageTypeIdGuid = 
AllocateCopyPool(mEdkiiSystemFmpCapsuleImageTypeIdGuidCount * sizeof(GUID), 
PcdGetPtr(PcdEdkiiSystemFmpCapsuleImageTypeIdGuid));
+  ASSERT(mEdkiiSystemFmpCapsuleImageTypeIdGuid != NULL);
+
+  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..e957b7b
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
@@ -0,0 +1,82 @@
+## @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
+  EdkiiSystemCapsuleLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiSystemFmpCapsuleImageTypeIdGuid  ## 
CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem
+
+[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..13379b2
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -0,0 +1,517 @@
+/** @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]  IsSystemFmp          If it is a system FMP.
+  @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 BOOLEAN           *IsSystemFmp, OPTIONAL
+  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  CapsuleHeader    Points to a capsule header.
+  @param  CapsuleSize      Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader(
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  IN UINT64              CapsuleSize
+  );
+
+extern BOOLEAN                   mDxeCapsuleLibEndOfDxe;
+
+/**
+
+  This routine is called to process capsules.
+
+  Caution: This function may receive untrusted input.
+
+  Each individual capsule result is recorded in capsule record variable.
+  System may reset in this function, if reset is required by capsule.
+
+  @param  IsSystemCapsule         TRUE: This function need process system 
capsules only.
+                                  FALSE: This function need process non-system 
capsules only.
+  @param  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  IsSystemCapsule,
+  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;
+  BOOLEAN                     NeedReset;
+  EFI_STATUS                  *CapsuleStatusArray;
+  BOOLEAN                     DisplayCapsuleExist;
+  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;
+  BOOLEAN                     IsSystemFmp;
+  UINT16                      EmbeddedDriverCount;
+
+  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, 
(PcdGet32(PcdStatusCodeSubClassCapsule) | 
PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));
+
+  CapsuleNumber       = 0;
+  CapsuleTotalNumber  = 0;
+  CacheIndex          = 0;
+  CacheNumber         = 0;
+  CapsulePtr          = NULL;
+  CapsulePtrCache     = NULL;
+  CapsuleGuidCache    = NULL;
+  NeedReset           = FALSE;
+  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 ((EFI_D_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);
+  }
+
+  if (!IsSystemCapsule) {
+    //
+    //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, 
(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 ((EFI_D_INFO, "ProcessCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));
+      DisplayCapsuleExist = TRUE;
+      DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));
+      Status = ProcessCapsuleImage (CapsuleHeader);
+      DEBUG((EFI_D_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.
+      //
+      IsSystemFmp = FALSE;
+      EmbeddedDriverCount = 0;
+      if (IsFmpCapsule(CapsuleHeader)) {
+        Status = ValidateFmpCapsule(CapsuleHeader, &IsSystemFmp, 
&EmbeddedDriverCount);
+        if (EFI_ERROR(Status)) {
+          DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));
+          continue;
+        }
+      }
+
+      if ((IsSystemFmp == IsSystemCapsule) &&
+          ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) ) {
+        DEBUG((EFI_D_INFO, "ProcessCapsuleImage - 0x%x\n", CapsuleHeader));
+        Status = ProcessCapsuleImage (CapsuleHeader);
+        CapsuleStatusArray [Index] = Status;
+        DEBUG((EFI_D_INFO, "ProcessCapsuleImage - %r\n", Status));
+
+        if (EFI_ERROR(Status)) {
+          REPORT_STATUS_CODE(EFI_ERROR_CODE, 
(PcdGet32(PcdStatusCodeSubClassCapsule) | 
PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));
+          DEBUG ((DEBUG_ERROR, "Capsule process failed. reset the system!\n"));
+          Print (L"Firmware update failed...\r\n");
+          NeedReset = TRUE;
+        } else {
+          REPORT_STATUS_CODE(EFI_PROGRESS_CODE, 
(PcdGet32(PcdStatusCodeSubClassCapsule) | 
PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));
+        }
+
+        if ((CapsuleHeader->Flags & 
PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||
+            IsFmpCapsule(CapsuleHeader)) {
+          NeedReset = TRUE;
+        }
+      }
+    }
+  }
+
+  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID 
**)&EsrtManagement);
+  //
+  // Always sync ESRT Cache from FMP Instance
+  //
+  if (!EFI_ERROR(Status)) {
+    EsrtManagement->SyncEsrtFmp();
+  }
+  Status = EFI_SUCCESS;
+
+  //
+  // Reboot System if required after all capsule processed
+  //
+  if (NeedReset) {
+    REPORT_STATUS_CODE(EFI_PROGRESS_CODE, 
(PcdGet32(PcdStatusCodeSubClassCapsule) | 
PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));
+    REPORT_STATUS_CODE(EFI_PROGRESS_CODE, 
(PcdGet32(PcdStatusCodeSubClassCapsule) | 
PcdGet32(PcdCapsuleStatusCodeResettingSystem)));
+
+    Print(L"Capsule Request Cold Reboot.\n");
+    DEBUG((EFI_D_INFO, "Capsule Request Cold Reboot."));
+
+    for (Index = 5; Index > 0; Index--) {
+      Print(L"\rResetting system in %d seconds ...", Index);
+      DEBUG((EFI_D_INFO, "\rResetting system in %d seconds ...", Index));
+      gBS->Stall (1000000);
+    }
+
+    gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+    CpuDeadLoop ();
+  }
+
+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, 
(PcdGet32(PcdStatusCodeSubClassCapsule) | 
PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));
+
+  return Status;
+}
+
+/**
+
+  This routine is called to process system capsules.
+
+  Caution: This function may receive untrusted input.
+
+  The non-system capsules are skipped.
+  Each individual capsule result is recorded in capsule record variable.
+  System may reset in this function, if reset is required by capsule.
+
+  @retval EFI_SUCCESS             There is no error when processing capsules.
+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.
+
+**/
+EFI_STATUS
+ProcessSystemCapsules(
+  VOID
+  )
+{
+  return ProcessTheseCapsules(TRUE, TRUE);
+}
+
+/**
+
+  This routine is called to process non-system capsules.
+
+  Caution: This function may receive untrusted input.
+
+  The system capsules are skipped.
+  Each individual capsule result is recorded in capsule record variable.
+
+  @param  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
+ProcessNonSystemCapsules(
+  IN BOOLEAN  NeedBlockDriver
+  )
+{
+  return ProcessTheseCapsules(FALSE, NeedBlockDriver);
+}
+
+/**
+
+  This routine is called to process capsules.
+
+  Caution: This function may receive untrusted input.
+
+  If the current boot mode is NOT BOOT_ON_FLASH_UPDATE, this routine does 
nothing.
+  If the current boot mode is BOOT_ON_FLASH_UPDATE, 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.
+
+  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.
+
+  @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_BOOT_MODE                 BootMode;
+  EFI_STATUS                    Status;
+  EFI_STATUS                    StatusRet;
+
+  BootMode = GetBootModeHob();
+  if (BootMode != BOOT_ON_FLASH_UPDATE) {
+    return EFI_SUCCESS;
+  }
+
+  if (!mDxeCapsuleLibEndOfDxe) {
+    Status = ProcessSystemCapsules();
+    StatusRet = ProcessNonSystemCapsules(TRUE);
+    if (EFI_ERROR(StatusRet)) {
+      StatusRet = Status;
+    }
+  } else {
+    StatusRet = ProcessNonSystemCapsules(FALSE);
+  }
+  return StatusRet;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c 
b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
new file mode 100644
index 0000000..2f8f141
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
@@ -0,0 +1,447 @@
+/** @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>
+
+/**
+  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 recorded.
+
+  @param CapsuleHeader  The capsule image header
+  @param PayloadIndex   FMP payload index
+  @param ImageHeader    FMP image header
+
+  @retval TRUE  This FMP capsule is recorded.
+  @retval FALSE This FMP capsule is not recorded.
+**/
+BOOLEAN
+IsFmpCapsuleVariableRecorded(
+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,
+  IN UINTN                                        PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader
+  )
+{
+  EFI_STATUS                          Status;
+  UINT16                              Index;
+  INTN                                CurrentIndex;
+  CHAR16                              CapsuleVarName[20];
+  CHAR16                              *TempVarName;
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResult;
+  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultFmp;
+
+  CurrentIndex = GetCurrentCapsuleLastIndex();
+  if (CurrentIndex == -1) {
+    return FALSE;
+  }
+
+  StrCpyS(CapsuleVarName, sizeof(CapsuleVarName) / sizeof(CapsuleVarName[0]), 
L"Capsule");
+  TempVarName = CapsuleVarName + StrLen(CapsuleVarName);
+  for (Index = 0; Index < (UINT16)CurrentIndex; Index++) {
+    UnicodeSPrint(TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
+    Status = GetVariable2 (
+               CapsuleVarName,
+               &gEfiCapsuleReportGuid,
+               (VOID **) &CapsuleResult,
+               NULL
+               );
+    if (Status == EFI_NOT_FOUND) {
+      break;
+    } else if (EFI_ERROR(Status)) {
+      continue;
+    }
+    //
+    // Check
+    //
+    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;
+}
+
+/**
+  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 CapsuleResult      The capsule status variable
+  @param 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((EFI_D_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((EFI_D_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.
+
+  @param CapsuleHeader  The capsule image header
+  @param 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;
+
+  if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);
+  CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+  ZeroMem(&CapsuleResultVariable.CapsuleProcessed, 
sizeof(CapsuleResultVariable.CapsuleProcessed));
+  gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);
+  CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
+
+  return WriteNewCapsuleResultVariable(&CapsuleResultVariable, 
sizeof(CapsuleResultVariable));
+}
+
+/**
+  Record FMP capsule status variable.
+
+  @param CapsuleHeader  The capsule image header
+  @param CapsuleStatus  The capsule process stauts
+  @param PayloadIndex   FMP payload index
+  @param 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;
+
+  if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) == 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  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);
+
+  return WriteNewCapsuleResultVariable(&CapsuleResultVariable, 
sizeof(CapsuleResultVariable));
+}
+
+/**
+  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/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..2eed206
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
@@ -0,0 +1,85 @@
+## @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
+  DxeCapsuleProcessLib.c
+  DxeCapsuleReportLib.c
+  DxeCapsuleRuntime.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  DxeServicesTableLib
+  UefiBootServicesTableLib
+  DevicePathLib
+  ReportStatusCodeLib
+  PrintLib
+  HobLib
+  EdkiiSystemCapsuleLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiSystemFmpCapsuleImageTypeIdGuid  ## 
CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem
+
+[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."
+
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to