public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Jiewen Yao <jiewen.yao@intel.com>
To: edk2-devel@lists.01.org
Cc: Feng Tian <feng.tian@intel.com>, Star Zeng <star.zeng@intel.com>,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Liming Gao <liming.gao@intel.com>,
	Chao Zhang <chao.b.zhang@intel.com>
Subject: [PATCH V5 06/15] MdeModulePkg/DxeCapsuleLibFmp: Add DxeCapsuleLibFmp instance.
Date: Thu, 27 Oct 2016 21:36:13 +0800	[thread overview]
Message-ID: <1477575382-20992-7-git-send-email-jiewen.yao@intel.com> (raw)
In-Reply-To: <1477575382-20992-1-git-send-email-jiewen.yao@intel.com>

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

Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
---
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c            | 1363 ++++++++++++++++++++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf          |   80 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni          |   22 +
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c     |  475 +++++++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c |   57 +
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c      |  489 +++++++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c  |   91 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c        |  112 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf   |   83 ++
 MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni   |   22 +
 10 files changed, 2794 insertions(+)

diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
new file mode 100644
index 0000000..e5dbb74
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -0,0 +1,1363 @@
+/** @file
+  DXE capsule library.
+
+  Caution: This module requires additional review when modified.
+  This module will have external input - capsule image.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
+  ValidateFmpCapsule(), DisplayCapsuleImage(), ConvertBmpToGopBlt() will
+  receive untrusted input and do basic validation.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/Bmp.h>
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/DevicePath.h>
+
+BOOLEAN            mAreAllImagesProcessed;
+
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable              = NULL;
+BOOLEAN                   mIsVirtualAddrConverted  = FALSE;
+BOOLEAN                   mDxeCapsuleLibEndOfDxe   = FALSE;
+
+/**
+  Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+  VOID
+  );
+
+/**
+  Check if this FMP capsule is processed.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] PayloadIndex   FMP payload index
+  @param[in] ImageHeader    FMP image header
+
+  @retval TRUE  This FMP capsule is processed.
+  @retval FALSE This FMP capsule is not processed.
+**/
+BOOLEAN
+IsFmpCapsuleProcessed (
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
+  IN UINTN                                         PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader
+  );
+
+/**
+  Record capsule status variable.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] CapsuleStatus  The capsule process stauts
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,
+  IN EFI_STATUS                                   CapsuleStatus
+  );
+
+/**
+  Record FMP capsule status variable.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] CapsuleStatus  The capsule process stauts
+  @param[in] PayloadIndex   FMP payload index
+  @param[in] ImageHeader    FMP image header
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
+  IN EFI_STATUS                                    CapsuleStatus,
+  IN UINTN                                         PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader
+  );
+
+/**
+  Function indicate the current completion progress of the firmware
+  update. Platform may override with own specific progress function.
+
+  @param[in]  Completion    A value between 1 and 100 indicating the current completion progress of the firmware update
+
+  @retval EFI_SUCESS    Input capsule is a correct FMP capsule.
+**/
+EFI_STATUS
+EFIAPI
+Update_Image_Progress (
+  IN UINTN  Completion
+  )
+{
+  return EFI_SUCCESS;
+}
+
+/**
+  Return if this CapsuleGuid is a FMP capsule GUID or not.
+
+  @param[in] CapsuleGuid A pointer to EFI_GUID
+
+  @retval TRUE  It is a FMP capsule GUID.
+  @retval FALSE It is not a FMP capsule GUID.
+**/
+BOOLEAN
+IsFmpCapsuleGuid (
+  IN EFI_GUID  *CapsuleGuid
+  )
+{
+  if (CompareGuid(&gEfiFmpCapsuleGuid, CapsuleGuid)) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Validate if it is valid capsule header
+
+  Caution: This function may receive untrusted input.
+
+  This function assumes the caller provided correct CapsuleHeader pointer
+  and CapsuleSize.
+
+  This function validates the fields in EFI_CAPSULE_HEADER.
+
+  @param[in]  CapsuleHeader    Points to a capsule header.
+  @param[in]  CapsuleSize      Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  IN UINT64              CapsuleSize
+  )
+{
+  if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
+    return FALSE;
+  }
+  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Validate Fmp capsules layout.
+
+  Caution: This function may receive untrusted input.
+
+  This function assumes the caller validated the capsule by using
+  IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
+  The capsule buffer size is CapsuleHeader->CapsuleImageSize.
+
+  This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+  and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
+
+  This function need support nested FMP capsule.
+
+  @param[in]   CapsuleHeader        Points to a capsule header.
+  @param[out]  EmbeddedDriverCount  The EmbeddedDriverCount in the FMP capsule.
+
+  @retval EFI_SUCESS             Input capsule is a correct FMP capsule.
+  @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.
+**/
+EFI_STATUS
+ValidateFmpCapsule (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  OUT UINT16             *EmbeddedDriverCount OPTIONAL
+  )
+{
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
+  UINT8                                        *EndOfCapsule;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+  UINT8                                        *EndOfPayload;
+  UINT64                                       *ItemOffsetList;
+  UINT32                                       ItemNum;
+  UINTN                                        Index;
+  UINTN                                        FmpCapsuleSize;
+  UINTN                                        FmpCapsuleHeaderSize;
+  UINT64                                       FmpImageSize;
+  UINTN                                        FmpImageHeaderSize;
+
+  if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
+    return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
+  }
+
+  if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+    DEBUG((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;
+  }
+
+  if (EmbeddedDriverCount != NULL) {
+    *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
+  is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
+  buffer is passed in it will be used if it is big enough.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]       BmpImage      Pointer to BMP file
+  @param[in]       BmpImageSize  Number of bytes in BmpImage
+  @param[in, out]  GopBlt        Buffer containing GOP version of BmpImage.
+  @param[in, out]  GopBltSize    Size of GopBlt in bytes.
+  @param[out]      PixelHeight   Height of GopBlt/BmpImage in pixels
+  @param[out]      PixelWidth    Width of GopBlt/BmpImage in pixels
+
+  @retval EFI_SUCCESS           GopBlt and GopBltSize are returned.
+  @retval EFI_UNSUPPORTED       BmpImage is not a valid *.BMP image
+  @retval EFI_BUFFER_TOO_SMALL  The passed in GopBlt buffer is not big enough.
+                                GopBltSize will contain the required size.
+  @retval EFI_OUT_OF_RESOURCES  No enough buffer to allocate.
+
+**/
+STATIC
+EFI_STATUS
+ConvertBmpToGopBlt (
+  IN     VOID      *BmpImage,
+  IN     UINTN     BmpImageSize,
+  IN OUT VOID      **GopBlt,
+  IN OUT UINTN     *GopBltSize,
+     OUT UINTN     *PixelHeight,
+     OUT UINTN     *PixelWidth
+  )
+{
+  UINT8                         *Image;
+  UINT8                         *ImageHeader;
+  BMP_IMAGE_HEADER              *BmpHeader;
+  BMP_COLOR_MAP                 *BmpColorMap;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  UINT64                        BltBufferSize;
+  UINTN                         Index;
+  UINTN                         Height;
+  UINTN                         Width;
+  UINTN                         ImageIndex;
+  UINT32                        DataSizePerLine;
+  BOOLEAN                       IsAllocated;
+  UINT32                        ColorMapNum;
+
+  if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
+
+  if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Doesn't support compress.
+  //
+  if (BmpHeader->CompressionType != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Only support BITMAPINFOHEADER format.
+  // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
+  //
+  if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // The data size in each line must be 4 byte alignment.
+  //
+  DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
+  BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
+  if (BltBufferSize > (UINT32) ~0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if ((BmpHeader->Size != BmpImageSize) ||
+      (BmpHeader->Size < BmpHeader->ImageOffset) ||
+      (BmpHeader->Size - BmpHeader->ImageOffset !=  BmpHeader->PixelHeight * DataSizePerLine)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Calculate Color Map offset in the image.
+  //
+  Image       = BmpImage;
+  BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
+  if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
+    switch (BmpHeader->BitPerPixel) {
+      case 1:
+        ColorMapNum = 2;
+        break;
+      case 4:
+        ColorMapNum = 16;
+        break;
+      case 8:
+        ColorMapNum = 256;
+        break;
+      default:
+        ColorMapNum = 0;
+        break;
+      }
+    //
+    // BMP file may has padding data between the bmp header section and the bmp data section.
+    //
+    if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Calculate graphics image data address in the image
+  //
+  Image         = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
+  ImageHeader   = Image;
+
+  //
+  // Calculate the BltBuffer needed size.
+  //
+  BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
+  //
+  // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+  //
+  if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+    return EFI_UNSUPPORTED;
+  }
+  BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+  IsAllocated   = FALSE;
+  if (*GopBlt == NULL) {
+    //
+    // GopBlt is not allocated by caller.
+    //
+    *GopBltSize = (UINTN) BltBufferSize;
+    *GopBlt     = AllocatePool (*GopBltSize);
+    IsAllocated = TRUE;
+    if (*GopBlt == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    //
+    // GopBlt has been allocated by caller.
+    //
+    if (*GopBltSize < (UINTN) BltBufferSize) {
+      *GopBltSize = (UINTN) BltBufferSize;
+      return EFI_BUFFER_TOO_SMALL;
+    }
+  }
+
+  *PixelWidth   = BmpHeader->PixelWidth;
+  *PixelHeight  = BmpHeader->PixelHeight;
+
+  //
+  // Convert image from BMP to Blt buffer format
+  //
+  BltBuffer = *GopBlt;
+  for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
+    Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
+    for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
+      switch (BmpHeader->BitPerPixel) {
+      case 1:
+        //
+        // Convert 1-bit (2 colors) BMP to 24-bit color
+        //
+        for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
+          Blt->Red    = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
+          Blt->Green  = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
+          Blt->Blue   = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
+          Blt++;
+          Width++;
+        }
+
+        Blt--;
+        Width--;
+        break;
+
+      case 4:
+        //
+        // Convert 4-bit (16 colors) BMP Palette to 24-bit color
+        //
+        Index       = (*Image) >> 4;
+        Blt->Red    = BmpColorMap[Index].Red;
+        Blt->Green  = BmpColorMap[Index].Green;
+        Blt->Blue   = BmpColorMap[Index].Blue;
+        if (Width < (BmpHeader->PixelWidth - 1)) {
+          Blt++;
+          Width++;
+          Index       = (*Image) & 0x0f;
+          Blt->Red    = BmpColorMap[Index].Red;
+          Blt->Green  = BmpColorMap[Index].Green;
+          Blt->Blue   = BmpColorMap[Index].Blue;
+        }
+        break;
+
+      case 8:
+        //
+        // Convert 8-bit (256 colors) BMP Palette to 24-bit color
+        //
+        Blt->Red    = BmpColorMap[*Image].Red;
+        Blt->Green  = BmpColorMap[*Image].Green;
+        Blt->Blue   = BmpColorMap[*Image].Blue;
+        break;
+
+      case 24:
+        //
+        // It is 24-bit BMP.
+        //
+        Blt->Blue   = *Image++;
+        Blt->Green  = *Image++;
+        Blt->Red    = *Image;
+        break;
+
+      case 32:
+        //
+        // it is 32-bit BMP. Skip pixel's highest byte
+        //
+        Blt->Blue  = *Image++;
+        Blt->Green = *Image++;
+        Blt->Red   = *Image++;
+        break;
+
+      default:
+        //
+        // Other bit format BMP is not supported.
+        //
+        if (IsAllocated) {
+          FreePool (*GopBlt);
+          *GopBlt = NULL;
+        }
+        return EFI_UNSUPPORTED;
+      };
+
+    }
+
+    ImageIndex = (UINTN) (Image - ImageHeader);
+    if ((ImageIndex % 4) != 0) {
+      //
+      // Bmp Image starts each row on a 32-bit boundary!
+      //
+      Image = Image + (4 - (ImageIndex % 4));
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Those capsules supported by the firmwares.
+
+  Caution: This function may receive untrusted input.
+
+  @param[in]  CapsuleHeader    Points to a capsule header.
+
+  @retval EFI_SUCESS       Input capsule is supported by firmware.
+  @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
+**/
+EFI_STATUS
+DisplayCapsuleImage (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader
+  )
+{
+  DISPLAY_DISPLAY_PAYLOAD       *ImagePayload;
+  UINTN                         PayloadSize;
+  EFI_STATUS                    Status;
+  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+  UINTN                         BltSize;
+  UINTN                         Height;
+  UINTN                         Width;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL  *GraphicsOutput;
+
+  ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)(CapsuleHeader + 1);
+  PayloadSize = (UINTN)(CapsuleHeader->CapsuleImageSize - sizeof(EFI_CAPSULE_HEADER));
+
+  if (ImagePayload->Version != 1) {
+    return EFI_UNSUPPORTED;
+  }
+  if (CalculateCheckSum8((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
+    return EFI_UNSUPPORTED;
+  }
+  //
+  // Only Support Bitmap by now
+  //
+  if (ImagePayload->ImageType != 0) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Try to open GOP
+  //
+  Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
+  if (EFI_ERROR (Status)) {
+    Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
+    if (EFI_ERROR(Status)) {
+      return EFI_UNSUPPORTED;
+    }
+  }
+
+  if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
+    return EFI_UNSUPPORTED;
+  }
+
+  Blt = NULL;
+  Width = 0;
+  Height = 0;
+  Status = ConvertBmpToGopBlt (
+             ImagePayload + 1,
+             PayloadSize - sizeof(DISPLAY_DISPLAY_PAYLOAD),
+             (VOID **)&Blt,
+             &BltSize,
+             &Height,
+             &Width
+             );
+
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GraphicsOutput->Blt (
+                             GraphicsOutput,
+                             Blt,
+                             EfiBltBufferToVideo,
+                             0,
+                             0,
+                             (UINTN) ImagePayload->OffsetX,
+                             (UINTN) ImagePayload->OffsetY,
+                             Width,
+                             Height,
+                             Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+                             );
+
+  FreePool(Blt);
+
+  return Status;
+}
+
+/**
+  Dump FMP information.
+
+  @param[in] ImageInfoSize       The size of ImageInfo, in bytes.
+  @param[in] ImageInfo           A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[in] DescriptorVersion   The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[in] DescriptorCount     The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param[in] DescriptorSize      The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+  @param[in] PackageVersion      The version of package.
+  @param[in] PackageVersionName  The version name of package.
+**/
+VOID
+DumpFmpImageInfo (
+  IN UINTN                           ImageInfoSize,
+  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR   *ImageInfo,
+  IN UINT32                          DescriptorVersion,
+  IN UINT8                           DescriptorCount,
+  IN UINTN                           DescriptorSize,
+  IN UINT32                          PackageVersion,
+  IN CHAR16                          *PackageVersionName
+  )
+{
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *CurrentImageInfo;
+  UINTN                                         Index;
+
+  DEBUG((DEBUG_VERBOSE, "  DescriptorVersion  - 0x%x\n", DescriptorVersion));
+  DEBUG((DEBUG_VERBOSE, "  DescriptorCount    - 0x%x\n", DescriptorCount));
+  DEBUG((DEBUG_VERBOSE, "  DescriptorSize     - 0x%x\n", DescriptorSize));
+  DEBUG((DEBUG_VERBOSE, "  PackageVersion     - 0x%x\n", PackageVersion));
+  DEBUG((DEBUG_VERBOSE, "  PackageVersionName - %s\n\n", PackageVersionName));
+  CurrentImageInfo = ImageInfo;
+  for (Index = 0; Index < DescriptorCount; Index++) {
+    DEBUG((DEBUG_VERBOSE, "  ImageDescriptor (%d)\n", Index));
+    DEBUG((DEBUG_VERBOSE, "    ImageIndex                  - 0x%x\n", CurrentImageInfo->ImageIndex));
+    DEBUG((DEBUG_VERBOSE, "    ImageTypeId                 - %g\n", &CurrentImageInfo->ImageTypeId));
+    DEBUG((DEBUG_VERBOSE, "    ImageId                     - 0x%lx\n", CurrentImageInfo->ImageId));
+    DEBUG((DEBUG_VERBOSE, "    ImageIdName                 - %s\n", CurrentImageInfo->ImageIdName));
+    DEBUG((DEBUG_VERBOSE, "    Version                     - 0x%x\n", CurrentImageInfo->Version));
+    DEBUG((DEBUG_VERBOSE, "    VersionName                 - %s\n", CurrentImageInfo->VersionName));
+    DEBUG((DEBUG_VERBOSE, "    Size                        - 0x%x\n", CurrentImageInfo->Size));
+    DEBUG((DEBUG_VERBOSE, "    AttributesSupported         - 0x%lx\n", CurrentImageInfo->AttributesSupported));
+    DEBUG((DEBUG_VERBOSE, "    AttributesSetting           - 0x%lx\n", CurrentImageInfo->AttributesSetting));
+    DEBUG((DEBUG_VERBOSE, "    Compatibilities             - 0x%lx\n", CurrentImageInfo->Compatibilities));
+    if (DescriptorVersion > 1) {
+      DEBUG((DEBUG_VERBOSE, "    LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
+      if (DescriptorVersion > 2) {
+        DEBUG((DEBUG_VERBOSE, "    LastAttemptVersion          - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
+        DEBUG((DEBUG_VERBOSE, "    LastAttemptStatus           - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
+        DEBUG((DEBUG_VERBOSE, "    HardwareInstance            - 0x%lx\n", CurrentImageInfo->HardwareInstance));
+      }
+    }
+    //
+    // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
+    //
+    CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
+  }
+}
+
+/**
+  Dump a non-nested FMP capsule.
+
+  @param[in]  CapsuleHeader  A pointer to CapsuleHeader
+**/
+VOID
+DumpFmpCapsule (
+  IN EFI_CAPSULE_HEADER                *CapsuleHeader
+  )
+{
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
+  UINTN                                         Index;
+  UINT64                                        *ItemOffsetList;
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+
+  DEBUG((DEBUG_VERBOSE, "FmpCapsule:\n"));
+  DEBUG((DEBUG_VERBOSE, "  Version                - 0x%x\n", FmpCapsuleHeader->Version));
+  DEBUG((DEBUG_VERBOSE, "  EmbeddedDriverCount    - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
+  DEBUG((DEBUG_VERBOSE, "  PayloadItemCount       - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
+
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+  for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+    DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));
+  }
+  for (; Index < (UINTN)(FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount); Index++) {
+    DEBUG((DEBUG_VERBOSE, "  ItemOffsetList[%d]      - 0x%lx\n", Index, ItemOffsetList[Index]));
+    ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+    DEBUG((DEBUG_VERBOSE, "  ImageHeader:\n"));
+    DEBUG((DEBUG_VERBOSE, "    Version                - 0x%x\n", ImageHeader->Version));
+    DEBUG((DEBUG_VERBOSE, "    UpdateImageTypeId      - %g\n", &ImageHeader->UpdateImageTypeId));
+    DEBUG((DEBUG_VERBOSE, "    UpdateImageIndex       - 0x%x\n", ImageHeader->UpdateImageIndex));
+    DEBUG((DEBUG_VERBOSE, "    UpdateImageSize        - 0x%x\n", ImageHeader->UpdateImageSize));
+    DEBUG((DEBUG_VERBOSE, "    UpdateVendorCodeSize   - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
+    if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+      DEBUG((DEBUG_VERBOSE, "    UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
+    }
+  }
+}
+
+/**
+  Process Firmware management protocol data capsule.
+
+  This function assumes the caller validated the capsule by using
+  ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
+
+  This function need support nested FMP capsule.
+
+  @param[in]  CapsuleHeader         Points to a capsule header.
+  @param[in]  AreAllImagesProcessed If all the FMP images in the capsule are processed.
+
+  @retval EFI_SUCESS            Process Capsule Image successfully.
+  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
+  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.
+**/
+EFI_STATUS
+ProcessFmpCapsuleImage (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  OUT BOOLEAN            *AreAllImagesProcessed
+  )
+{
+  EFI_STATUS                                    Status;
+  EFI_STATUS                                    StatusEsrt;
+  EFI_STATUS                                    StatusRet;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
+  UINT8                                         *Image;
+  EFI_HANDLE                                    ImageHandle;
+  UINT64                                        *ItemOffsetList;
+  UINT32                                        ItemNum;
+  UINTN                                         Index;
+  UINTN                                         ExitDataSize;
+  EFI_HANDLE                                    *HandleBuffer;
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
+  UINTN                                         NumberOfHandles;
+  UINTN                                         DescriptorSize;
+  UINT8                                         FmpImageInfoCount;
+  UINT32                                        FmpImageInfoDescriptorVer;
+  UINTN                                         ImageInfoSize;
+  UINT32                                        PackageVersion;
+  CHAR16                                        *PackageVersionName;
+  CHAR16                                        *AbortReason;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;
+  UINTN                                         DriverLen;
+  UINTN                                         Index1;
+  UINTN                                         Index2;
+  MEMMAP_DEVICE_PATH                            MemMapNode;
+  EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;
+  ESRT_MANAGEMENT_PROTOCOL                      *EsrtProtocol;
+  EFI_SYSTEM_RESOURCE_ENTRY                     EsrtEntry;
+  VOID                                          *VendorCode;
+
+  if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
+    return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), AreAllImagesProcessed);
+  }
+
+  ASSERT(AreAllImagesProcessed != NULL);
+
+  Status           = EFI_SUCCESS;
+  StatusRet        = EFI_NOT_FOUND;
+  HandleBuffer     = NULL;
+  ExitDataSize     = 0;
+  DriverDevicePath = NULL;
+  EsrtProtocol     = NULL;
+  *AreAllImagesProcessed = FALSE;
+
+  DumpFmpCapsule(CapsuleHeader);
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+
+  if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+    return EFI_INVALID_PARAMETER;
+  }
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+  ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+  //
+  // capsule in which driver count and payload count are both zero is not processed.
+  //
+  if (ItemNum == 0) {
+    *AreAllImagesProcessed = TRUE;
+    return EFI_SUCCESS;
+  }
+
+  //
+  // Update corresponding ESRT entry LastAttemp Status
+  //
+  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+  if (EFI_ERROR (Status)) {
+    EsrtProtocol = NULL;
+  }
+
+  //
+  // 1. Try to load & start all the drivers within capsule
+  //
+  SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
+  MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;
+  MemMapNode.Header.SubType  = HW_MEMMAP_DP;
+  MemMapNode.MemoryType      = EfiBootServicesCode;
+  MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;
+  MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);
+
+  DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
+  if (DriverDevicePath == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+    if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {
+      //
+      // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
+      //
+      DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
+    } else {
+      DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
+    }
+
+    DEBUG((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;
+    }
+  }
+
+  //
+  // 2. 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 (IsFmpCapsuleProcessed(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);
+    }
+  }
+
+  //
+  // final check for AreAllImagesProcessed
+  //
+  *AreAllImagesProcessed = TRUE;
+  for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+    ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+    if (!IsFmpCapsuleProcessed(CapsuleHeader, Index - FmpCapsuleHeader->EmbeddedDriverCount, ImageHeader)) {
+      *AreAllImagesProcessed = FALSE;
+      break;
+    }
+  }
+
+EXIT:
+
+  if (HandleBuffer != NULL) {
+    FreePool(HandleBuffer);
+  }
+
+  if (DriverDevicePath != NULL) {
+    FreePool(DriverDevicePath);
+  }
+
+  return StatusRet;
+}
+
+/**
+  Return if there is a FMP header below capsule header.
+
+  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+  @retval TRUE  There is a FMP header below capsule header.
+  @retval FALSE There is not a FMP header below capsule header
+**/
+BOOLEAN
+IsNestedFmpCapsule (
+  IN EFI_CAPSULE_HEADER         *CapsuleHeader
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;
+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
+  UINTN                      Index;
+  BOOLEAN                    EsrtGuidFound;
+  EFI_CAPSULE_HEADER         *NestedCapsuleHeader;
+  UINTN                      NestedCapsuleSize;
+  ESRT_MANAGEMENT_PROTOCOL   *EsrtProtocol;
+  EFI_SYSTEM_RESOURCE_ENTRY  Entry;
+
+  EsrtGuidFound = FALSE;
+
+  //
+  // Check ESRT protocol
+  //
+  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+  if (!EFI_ERROR(Status)) {
+    Status = EsrtProtocol->GetEsrtEntry(&CapsuleHeader->CapsuleGuid, &Entry);
+    if (!EFI_ERROR(Status)) {
+      EsrtGuidFound = TRUE;
+    }
+  }
+
+  //
+  // Check ESRT configuration table
+  //
+  if (!EsrtGuidFound) {
+    Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
+    if (!EFI_ERROR(Status)) {
+      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[in]  CapsuleHeader    Points to a capsule header.
+
+  @retval EFI_SUCESS       Input capsule is supported by firmware.
+  @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
+  @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader
+  )
+{
+  //
+  // check Display Capsule Guid
+  //
+  if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+    return EFI_SUCCESS;
+  }
+
+  if (IsFmpCapsule(CapsuleHeader)) {
+    //
+    // Check layout of FMP capsule
+    //
+    return ValidateFmpCapsule(CapsuleHeader, NULL);
+  }
+  DEBUG((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[in]  CapsuleHeader         Points to a capsule header.
+
+  @retval EFI_SUCESS            Process Capsule Image successfully.
+  @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
+  @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
+  @retval EFI_OUT_OF_RESOURCES  Not enough memory.
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsuleImage (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader
+  )
+{
+  EFI_STATUS                   Status;
+  BOOLEAN                      AreAllImagesProcessed;
+
+  if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Display image in firmware update display capsule
+  //
+  if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+    DEBUG((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, 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, &AreAllImagesProcessed);
+    DEBUG((EFI_D_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
+
+    if (!AreAllImagesProcessed) {
+      mAreAllImagesProcessed = FALSE;
+    }
+
+    return Status;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Callback function executed when the EndOfDxe event group is signaled.
+
+  @param[in] Event      Event whose notification function is being invoked.
+  @param[in] Context    The pointer to the notification function's context, which
+                        is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibEndOfDxe (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  mDxeCapsuleLibEndOfDxe = TRUE;
+}
+
+/**
+  The constructor function.
+
+  @param[in]  ImageHandle   The firmware allocated handle for the EFI image.
+  @param[in]  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor successfully .
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibConstructor (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_EVENT     EndOfDxeEvent;
+  EFI_STATUS    Status;
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_CALLBACK,
+                  DxeCapsuleLibEndOfDxe,
+                  NULL,
+                  &gEfiEndOfDxeEventGroupGuid,
+                  &EndOfDxeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  InitCapsuleVariable();
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
new file mode 100644
index 0000000..5e437dc
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
@@ -0,0 +1,80 @@
+## @file
+#  Capsule library instance for DXE_DRIVER.
+#
+#  Capsule library instance for DXE_DRIVER module types.
+#
+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeCapsuleLib
+  MODULE_UNI_FILE                = DxeCapsuleLib.uni
+  FILE_GUID                      = 534E35DE-8EB3-47b3-A4E0-72A571E50733
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = CapsuleLib|DXE_DRIVER UEFI_APPLICATION
+  CONSTRUCTOR                    = DxeCapsuleLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  DxeCapsuleLib.c
+  DxeCapsuleProcessLib.c
+  DxeCapsuleReportLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  DxeServicesTableLib
+  UefiBootServicesTableLib
+  DevicePathLib
+  ReportStatusCodeLib
+  PrintLib
+  HobLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax                               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag      ## CONSUMES
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule                ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd      ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware        ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess   ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem         ## CONSUMES
+
+[Protocols]
+  gEsrtManagementProtocolGuid             ## CONSUMES
+  gEfiFirmwareManagementProtocolGuid      ## SOMETIMES_CONSUMES
+  gEdkiiVariableLockProtocolGuid          ## SOMETIMES_CONSUMES
+
+[Guids]
+  gEfiFmpCapsuleGuid                      ## SOMETIMES_CONSUMES ## GUID
+  gWindowsUxCapsuleGuid                   ## SOMETIMES_CONSUMES ## GUID
+  gEfiSystemResourceTableGuid             ## SOMETIMES_CONSUMES ## GUID
+  gEfiCapsuleReportGuid                   ## CONSUMES ## Variable
+  gEfiCapsuleVendorGuid                   ## CONSUMES ## Variable
+  gEfiEndOfDxeEventGroupGuid              ## CONSUMES ## Event
+
+[Depex]
+  gEfiVariableWriteArchProtocolGuid
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
new file mode 100644
index 0000000..05a80d0
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Capsule library instance for DXE_DRIVER.
+//
+// Capsule library instance for DXE_DRIVER module types.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution.  The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Capsule Support Library"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Capsule library instance for DXE_DRIVER module types."
+
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
new file mode 100644
index 0000000..0a4ece4
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
@@ -0,0 +1,475 @@
+/** @file
+  DXE capsule process.
+
+  Caution: This module requires additional review when modified.
+  This module will have external input - capsule image.
+  This external input must be validated carefully to avoid security issue like
+  buffer overflow, integer overflow.
+
+  ProcessCapsules(), ProcessTheseCapsules() will receive untrusted
+  input and do basic validation.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/EsrtManagement.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/CapsuleLib.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+/**
+  Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
+
+  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+  @retval TRUE  It is a system FMP.
+  @retval FALSE It is a device FMP.
+**/
+BOOLEAN
+IsFmpCapsule (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader
+  );
+
+/**
+  Validate Fmp capsules layout.
+
+  Caution: This function may receive untrusted input.
+
+  This function assumes the caller validated the capsule by using
+  IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
+  The capsule buffer size is CapsuleHeader->CapsuleImageSize.
+
+  This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+  and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
+
+  This function need support nested FMP capsule.
+
+  @param[in]   CapsuleHeader        Points to a capsule header.
+  @param[out]  EmbeddedDriverCount  The EmbeddedDriverCount in the FMP capsule.
+
+  @retval EFI_SUCESS             Input capsule is a correct FMP capsule.
+  @retval EFI_INVALID_PARAMETER  Input capsule is not a correct FMP capsule.
+**/
+EFI_STATUS
+ValidateFmpCapsule (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  OUT UINT16             *EmbeddedDriverCount OPTIONAL
+  );
+
+/**
+  Validate if it is valid capsule header
+
+  This function assumes the caller provided correct CapsuleHeader pointer
+  and CapsuleSize.
+
+  This function validates the fields in EFI_CAPSULE_HEADER.
+
+  @param[in]  CapsuleHeader    Points to a capsule header.
+  @param[in]  CapsuleSize      Size of the whole capsule image.
+
+**/
+BOOLEAN
+IsValidCapsuleHeader (
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  IN UINT64              CapsuleSize
+  );
+
+extern BOOLEAN                   mDxeCapsuleLibEndOfDxe;
+extern BOOLEAN                   mAreAllImagesProcessed;
+BOOLEAN                          mNeedReset;
+
+/**
+
+  This routine is called to process capsules.
+
+  Caution: This function may receive untrusted input.
+
+  Each individual capsule result is recorded in capsule record variable.
+
+  @param[in]  NeedBlockDriver         TRUE: Need skip the FMP capsules with non zero EmbeddedDriverCount.
+                                      FALSE: No need to skip any FMP capsules.
+
+  @retval EFI_SUCCESS             There is no error when processing capsules.
+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.
+
+**/
+EFI_STATUS
+ProcessTheseCapsules (
+  IN BOOLEAN  NeedBlockDriver
+  )
+{
+  EFI_STATUS                  Status;
+  EFI_PEI_HOB_POINTERS        HobPointer;
+  EFI_CAPSULE_HEADER          *CapsuleHeader;
+  UINT32                      Size;
+  UINT32                      CapsuleNumber;
+  UINT32                      CapsuleTotalNumber;
+  EFI_CAPSULE_TABLE           *CapsuleTable;
+  UINT32                      Index;
+  UINT32                      CacheIndex;
+  UINT32                      CacheNumber;
+  VOID                        **CapsulePtr;
+  VOID                        **CapsulePtrCache;
+  EFI_GUID                    *CapsuleGuidCache;
+  EFI_STATUS                  *CapsuleStatusArray;
+  BOOLEAN                     DisplayCapsuleExist;
+  ESRT_MANAGEMENT_PROTOCOL    *EsrtManagement;
+  UINT16                      EmbeddedDriverCount;
+
+  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));
+
+  CapsuleNumber       = 0;
+  CapsuleTotalNumber  = 0;
+  CacheIndex          = 0;
+  CacheNumber         = 0;
+  CapsulePtr          = NULL;
+  CapsulePtrCache     = NULL;
+  CapsuleGuidCache    = NULL;
+  DisplayCapsuleExist = FALSE;
+  EsrtManagement      = NULL;
+
+  Status = EFI_SUCCESS;
+  //
+  // Find all capsule images from hob
+  //
+  HobPointer.Raw = GetHobList ();
+  while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
+    if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {
+      HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid
+    } else {
+      CapsuleTotalNumber++;
+    }
+    HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+  }
+
+  if (CapsuleTotalNumber == 0) {
+    //
+    // We didn't find a hob, so had no errors.
+    //
+    DEBUG ((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);
+  }
+
+  //
+  // 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.
+      //
+      EmbeddedDriverCount = 0;
+      if (IsFmpCapsule(CapsuleHeader)) {
+        Status = ValidateFmpCapsule(CapsuleHeader, &EmbeddedDriverCount);
+        if (EFI_ERROR(Status)) {
+          DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));
+          continue;
+        }
+      }
+
+      if ((!NeedBlockDriver) || (EmbeddedDriverCount == 0)) {
+        DEBUG((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");
+        } else {
+          REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));
+        }
+
+        if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0 ||
+            IsFmpCapsule(CapsuleHeader)) {
+          mNeedReset = TRUE;
+        }
+      }
+    }
+  }
+
+  Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);
+  //
+  // Always sync ESRT Cache from FMP Instance
+  //
+  if (!EFI_ERROR(Status)) {
+    EsrtManagement->SyncEsrtFmp();
+  }
+  Status = EFI_SUCCESS;
+
+Done:
+  //
+  // Free the allocated temp memory space.
+  //
+  if (CapsuleGuidCache != NULL) {
+    FreePool(CapsuleGuidCache);
+  }
+  if (CapsulePtrCache != NULL) {
+    FreePool(CapsulePtrCache);
+  }
+  if (CapsulePtr != NULL) {
+    FreePool(CapsulePtr);
+  }
+
+  REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));
+
+  return Status;
+}
+
+/**
+  Do reset system.
+**/
+VOID
+DoResetSystem (
+  VOID
+  )
+{
+  UINTN                         Index;
+
+  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();
+}
+
+/**
+
+  This routine is called to process capsules.
+
+  Caution: This function may receive untrusted input.
+
+  The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
+  If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
+
+  This routine should be called twice in BDS.
+  1) The first call must be before EndOfDxe. The system capsules is processed.
+     If device capsule FMP protocols are exposted at this time and device FMP
+     capsule has zero EmbeddedDriverCount, the device capsules are processed.
+     Each individual capsule result is recorded in capsule record variable.
+     System may reset in this function, if reset is required by capsule and
+     all capsules are processed.
+     If not all capsules are processed, reset will be defered to second call.
+
+  2) The second call must be after EndOfDxe and after ConnectAll, so that all
+     device capsule FMP protocols are exposed.
+     The system capsules are skipped. If the device capsules are NOT processed
+     in first call, they are processed here.
+     Each individual capsule result is recorded in capsule record variable.
+     System may reset in this function, if reset is required by capsule
+     processed in first call and second call.
+
+  @retval EFI_SUCCESS             There is no error when processing capsules.
+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsules (
+  VOID
+  )
+{
+  EFI_STATUS                    Status;
+
+  if (!mDxeCapsuleLibEndOfDxe) {
+    //
+    // Initialize mAreAllImagesProcessed to be TRUE.
+    //
+    // It will be updated to FALSE in ProcessTheseCapsules()->ProcessCapsuleImage(),
+    // if there is any FMP image in any FMP capsule not processed.
+    //
+    mAreAllImagesProcessed = TRUE;
+
+    Status = ProcessTheseCapsules(TRUE);
+    //
+    // Reboot System if and only if all capsule processed.
+    // If not, defer reset to 2nd process.
+    //
+    if (mNeedReset && mAreAllImagesProcessed) {
+      DoResetSystem();
+    }
+  } else {
+    Status = ProcessTheseCapsules(FALSE);
+    //
+    // Reboot System if required after all capsule processed
+    //
+    if (mNeedReset) {
+      DoResetSystem();
+    }
+  }
+  return Status;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
new file mode 100644
index 0000000..07e9e46
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c
@@ -0,0 +1,57 @@
+/** @file
+  DXE capsule process.
+  Dummy function for runtime module, because CapsuleDxeRuntime
+  does not need call ProcessCapsules().
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/CapsuleLib.h>
+
+/**
+
+  This routine is called to process capsules.
+
+  Caution: This function may receive untrusted input.
+
+  The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
+  If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
+
+  This routine should be called twice in BDS.
+  1) The first call must be before EndOfDxe. The system capsules is processed.
+     If device capsule FMP protocols are exposted at this time and device FMP
+     capsule has zero EmbeddedDriverCount, the device capsules are processed.
+     Each individual capsule result is recorded in capsule record variable.
+     System may reset in this function, if reset is required by capsule and
+     all capsules are processed.
+     If not all capsules are processed, reset will be defered to second call.
+
+  2) The second call must be after EndOfDxe and after ConnectAll, so that all
+     device capsule FMP protocols are exposed.
+     The system capsules are skipped. If the device capsules are NOT processed
+     in first call, they are processed here.
+     Each individual capsule result is recorded in capsule record variable.
+     System may reset in this function, if reset is required by capsule
+     processed in first call and second call.
+
+  @retval EFI_SUCCESS             There is no error when processing capsules.
+  @retval EFI_OUT_OF_RESOURCES    No enough resource to process capsules.
+
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsules (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
new file mode 100644
index 0000000..b6ba404
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
@@ -0,0 +1,489 @@
+/** @file
+  DXE capsule report related function.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/VariableLock.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/FmpCapsule.h>
+#include <Guid/CapsuleVendor.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/CapsuleLib.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+typedef struct {
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  CapsuleResultHeader;
+  EFI_CAPSULE_RESULT_VARIABLE_FMP     CapsuleResultFmp;
+} CAPSULE_RESULT_VARIABLE_CACHE;
+
+#define CAPSULE_RESULT_VARIABLE_CACHE_COUNT   0x10
+
+CAPSULE_RESULT_VARIABLE_CACHE *mCapsuleResultVariableCache;
+UINTN                         mCapsuleResultVariableCacheMaxCount;
+UINTN                         mCapsuleResultVariableCacheCount;
+
+/**
+  Get current capsule last variable index.
+
+  @return Current capsule last variable index.
+  @retval -1  No current capsule last variable.
+**/
+INTN
+GetCurrentCapsuleLastIndex (
+  VOID
+  )
+{
+  UINTN                            Size;
+  CHAR16                           CapsuleLastStr[sizeof("Capsule####")];
+  EFI_STATUS                       Status;
+  UINT16                           CurrentIndex;
+
+  Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+  Status = gRT->GetVariable(
+                  L"CapsuleLast",
+                  &gEfiCapsuleReportGuid,
+                  NULL,
+                  &Size,
+                  CapsuleLastStr
+                  );
+  if (EFI_ERROR(Status)) {
+    return -1;
+  }
+  CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);
+  return CurrentIndex;
+}
+
+/**
+  Check if this FMP capsule is processed.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] PayloadIndex   FMP payload index
+  @param[in] ImageHeader    FMP image header
+
+  @retval TRUE  This FMP capsule is processed.
+  @retval FALSE This FMP capsule is not processed.
+**/
+BOOLEAN
+IsFmpCapsuleProcessed (
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
+  IN UINTN                                         PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader
+  )
+{
+  UINTN                               Index;
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResult;
+  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultFmp;
+
+  for (Index = 0; Index < mCapsuleResultVariableCacheCount; Index++) {
+    //
+    // Check
+    //
+    CapsuleResult = &mCapsuleResultVariableCache[Index].CapsuleResultHeader;
+    if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {
+      if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+        if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {
+          CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);
+          if (CompareGuid(&CapsuleResultFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId) &&
+              (CapsuleResultFmp->UpdateImageIndex == ImageHeader->UpdateImageIndex) &&
+              (CapsuleResultFmp->PayloadIndex == PayloadIndex) ) {
+            return TRUE;
+          }
+        }
+      }
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+  Write a new capsule status variable cache.
+
+  @param[in] CapsuleResult      The capsule status variable
+  @param[in] CapsuleResultSize  The size of the capsule stauts variable in bytes
+
+  @retval EFI_SUCCESS          The capsule status variable is cached.
+  @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.
+**/
+EFI_STATUS
+WriteNewCapsuleResultVariableCache (
+  IN VOID    *CapsuleResult,
+  IN UINTN   CapsuleResultSize
+  )
+{
+  if (CapsuleResultSize > sizeof(CAPSULE_RESULT_VARIABLE_CACHE)) {
+    CapsuleResultSize = sizeof(CAPSULE_RESULT_VARIABLE_CACHE);
+  }
+
+  if (mCapsuleResultVariableCacheCount == mCapsuleResultVariableCacheMaxCount) {
+    mCapsuleResultVariableCache = ReallocatePool(
+                                    mCapsuleResultVariableCacheMaxCount * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),
+                                    (mCapsuleResultVariableCacheMaxCount + CAPSULE_RESULT_VARIABLE_CACHE_COUNT) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE),
+                                    mCapsuleResultVariableCache
+                                    );
+    if (mCapsuleResultVariableCache == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+    mCapsuleResultVariableCacheMaxCount += CAPSULE_RESULT_VARIABLE_CACHE_COUNT;
+  }
+
+  ASSERT(mCapsuleResultVariableCacheCount < mCapsuleResultVariableCacheMaxCount);
+  ASSERT(mCapsuleResultVariableCache != NULL);
+  CopyMem(
+    &mCapsuleResultVariableCache[mCapsuleResultVariableCacheCount],
+    CapsuleResult,
+    CapsuleResultSize
+    );
+  mCapsuleResultVariableCacheCount++;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get a new capsule status variable index.
+
+  @return A new capsule status variable index.
+  @retval -1  No new capsule status variable index.
+**/
+INTN
+GetNewCapsuleResultIndex (
+  VOID
+  )
+{
+  INTN                             CurrentIndex;
+
+  CurrentIndex = GetCurrentCapsuleLastIndex();
+  if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {
+    return -1;
+  }
+
+  return CurrentIndex + 1;
+}
+
+/**
+  Write a new capsule status variable.
+
+  @param[in] CapsuleResult      The capsule status variable
+  @param[in] CapsuleResultSize  The size of the capsule stauts variable in bytes
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+WriteNewCapsuleResultVariable (
+  IN VOID    *CapsuleResult,
+  IN UINTN   CapsuleResultSize
+  )
+{
+  INTN                                CapsuleResultIndex;
+  CHAR16                              CapsuleResultStr[sizeof("Capsule####")];
+  UINTN                               Size;
+  EFI_STATUS                          Status;
+
+  CapsuleResultIndex = GetNewCapsuleResultIndex();
+  DEBUG((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 and to local cache.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] CapsuleStatus  The capsule process stauts
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,
+  IN EFI_STATUS                                   CapsuleStatus
+  )
+{
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  CapsuleResultVariable;
+  EFI_STATUS                          Status;
+
+  CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);
+  CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+  ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));
+  gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);
+  CapsuleResultVariable.CapsuleStatus = CapsuleStatus;
+
+  //
+  // Save Local Cache
+  //
+  Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
+
+  if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+    Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
+  }
+  return Status;
+}
+
+/**
+  Record FMP capsule status variable and to local cache.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] CapsuleStatus  The capsule process stauts
+  @param[in] PayloadIndex   FMP payload index
+  @param[in] ImageHeader    FMP image header
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
+  IN EFI_STATUS                                    CapsuleStatus,
+  IN UINTN                                         PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader
+  )
+{
+  UINT8                               CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)];
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResultVariableHeader;
+  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultVariableFmp;
+  EFI_STATUS                          Status;
+
+  CapsuleResultVariableHeader = (VOID *)&CapsuleResultVariable[0];
+  CapsuleResultVariableHeader->VariableTotalSize = sizeof(CapsuleResultVariable);
+  CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);
+  ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));
+  gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);
+  CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;
+
+  CapsuleResultVariableFmp = (VOID *)&CapsuleResultVariable[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)];
+  CapsuleResultVariableFmp->Version = 0x1;
+  CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
+  CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;
+  CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);
+
+  //
+  // Save Local Cache
+  //
+  Status = WriteNewCapsuleResultVariableCache(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
+
+  if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+    Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));
+  }
+  return Status;
+}
+
+/**
+  Initialize CapsuleMax variables.
+**/
+VOID
+InitCapsuleMaxVariable (
+  VOID
+  )
+{
+  EFI_STATUS                       Status;
+  UINTN                            Size;
+  CHAR16                           CapsuleMaxStr[sizeof("Capsule####")];
+  EDKII_VARIABLE_LOCK_PROTOCOL     *VariableLock;
+
+  UnicodeSPrint(
+    CapsuleMaxStr,
+    sizeof(CapsuleMaxStr),
+    L"Capsule%04x",
+    PcdGet16(PcdCapsuleMax)
+    );
+
+  Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+  Status = gRT->SetVariable(
+                  L"CapsuleMax",
+                  &gEfiCapsuleReportGuid,
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                  Size,
+                  CapsuleMaxStr
+                  );
+  if (!EFI_ERROR(Status)) {
+    // Lock it per UEFI spec.
+    Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
+    if (!EFI_ERROR(Status)) {
+      Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);
+      ASSERT_EFI_ERROR(Status);
+    }
+  }
+}
+
+/**
+  Initialize CapsuleLast variables.
+**/
+VOID
+InitCapsuleLastVariable (
+  VOID
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_BOOT_MODE                    BootMode;
+  EDKII_VARIABLE_LOCK_PROTOCOL     *VariableLock;
+  VOID                             *CapsuleResult;
+  UINTN                            Size;
+  CHAR16                           CapsuleLastStr[sizeof("Capsule####")];
+
+  BootMode = GetBootModeHob();
+  if (BootMode == BOOT_ON_FLASH_UPDATE) {
+    Status = gRT->SetVariable(
+                    L"CapsuleLast",
+                    &gEfiCapsuleReportGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                    0,
+                    NULL
+                    );
+    // Do not lock it because it will be updated later.
+  } else {
+    //
+    // Check if OS/APP cleared L"Capsule####"
+    //
+    ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));
+    Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator
+    Status = gRT->GetVariable(
+                    L"CapsuleLast",
+                    &gEfiCapsuleReportGuid,
+                    NULL,
+                    &Size,
+                    CapsuleLastStr
+                    );
+    if (!EFI_ERROR(Status)) {
+      //
+      // L"CapsuleLast" is got, check if data is there.
+      //
+      Status = GetVariable2 (
+                 CapsuleLastStr,
+                 &gEfiCapsuleReportGuid,
+                 (VOID **) &CapsuleResult,
+                 NULL
+                 );
+      if (EFI_ERROR(Status)) {
+        //
+        // If no data, delete L"CapsuleLast"
+        //
+        Status = gRT->SetVariable(
+                        L"CapsuleLast",
+                        &gEfiCapsuleReportGuid,
+                        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+                        0,
+                        NULL
+                        );
+      }
+    }
+
+    // Lock it in normal boot path per UEFI spec.
+    Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);
+    if (!EFI_ERROR(Status)) {
+      Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);
+      ASSERT_EFI_ERROR(Status);
+    }
+  }
+}
+
+/**
+  Initialize capsule update variables.
+**/
+VOID
+InitCapsuleUpdateVariable (
+  VOID
+  )
+{
+  EFI_STATUS                     Status;
+  UINTN                          Index;
+  CHAR16                         CapsuleVarName[30];
+  CHAR16                         *TempVarName;
+
+  //
+  // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
+  // as early as possible which will avoid the next time boot after the capsule update
+  // will still into the capsule loop
+  //
+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);
+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+  Index = 0;
+  while (TRUE) {
+    if (Index > 0) {
+      UnicodeValueToString (TempVarName, 0, Index, 0);
+    }
+    Status = gRT->SetVariable (
+                    CapsuleVarName,
+                    &gEfiCapsuleVendorGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    0,
+                    (VOID *)NULL
+                    );
+    if (EFI_ERROR (Status)) {
+      //
+      // There is no capsule variables, quit
+      //
+      break;
+    }
+    Index++;
+  }
+}
+
+/**
+  Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+  VOID
+  )
+{
+  InitCapsuleUpdateVariable();
+  InitCapsuleMaxVariable();
+  InitCapsuleLastVariable();
+  //
+  // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
+  // to check status and delete them.
+  //
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
new file mode 100644
index 0000000..bf550e5
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c
@@ -0,0 +1,91 @@
+/** @file
+  DXE capsule report related function.
+  Dummy function for runtime module, because CapsuleDxeRuntime
+  does not need record capsule status variable.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/FmpCapsule.h>
+#include <Library/CapsuleLib.h>
+
+/**
+  Check if this FMP capsule is processed.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] PayloadIndex   FMP payload index
+  @param[in] ImageHeader    FMP image header
+
+  @retval TRUE  This FMP capsule is processed.
+  @retval FALSE This FMP capsule is not processed.
+**/
+BOOLEAN
+IsFmpCapsuleProcessed (
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
+  IN UINTN                                         PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader
+  )
+{
+  return FALSE;
+}
+
+/**
+  Record capsule status variable and to local cache.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] CapsuleStatus  The capsule process stauts
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+  IN EFI_CAPSULE_HEADER                           *CapsuleHeader,
+  IN EFI_STATUS                                   CapsuleStatus
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Record FMP capsule status variable and to local cache.
+
+  @param[in] CapsuleHeader  The capsule image header
+  @param[in] CapsuleStatus  The capsule process stauts
+  @param[in] PayloadIndex   FMP payload index
+  @param[in] ImageHeader    FMP image header
+
+  @retval EFI_SUCCESS          The capsule status variable is recorded.
+  @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader,
+  IN EFI_STATUS                                    CapsuleStatus,
+  IN UINTN                                         PayloadIndex,
+  IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+  VOID
+  )
+{
+  return;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
new file mode 100644
index 0000000..8801439
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c
@@ -0,0 +1,112 @@
+/** @file
+  Capsule library runtime support.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD License
+  which accompanies this distribution.  The full text of the license may be found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+extern EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable;
+extern BOOLEAN                   mIsVirtualAddrConverted;
+
+/**
+  Convert EsrtTable physical address to virtual address.
+
+  @param[in] Event      Event whose notification function is being invoked.
+  @param[in] Context    The pointer to the notification function's context, which
+                        is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibVirtualAddressChangeEvent (
+  IN  EFI_EVENT   Event,
+  IN  VOID        *Context
+  )
+{
+  UINTN                    Index;
+  EFI_CONFIGURATION_TABLE  *ConfigEntry;
+
+  //
+  // Get Esrt table first
+  //
+  ConfigEntry = gST->ConfigurationTable;
+  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+    if (CompareGuid(&gEfiSystemResourceTableGuid, &ConfigEntry->VendorGuid)) {
+      break;
+    }
+    ConfigEntry++;
+  }
+
+  //
+  // If no Esrt table installed in Configure Table
+  //
+  if (Index < gST->NumberOfTableEntries) {
+    //
+    // Search Esrt to check given capsule is qualified
+    //
+    mEsrtTable = (EFI_SYSTEM_RESOURCE_TABLE *) ConfigEntry->VendorTable;
+
+    //
+    // Update protocol pointer to Esrt Table.
+    //
+    gRT->ConvertPointer (0x00, (VOID**) &(mEsrtTable));
+  }
+
+  mIsVirtualAddrConverted = TRUE;
+
+}
+
+/**
+  The constructor function hook VirtualAddressChange event to use ESRT table as capsule routing table.
+
+  @param  ImageHandle   The firmware allocated handle for the EFI image.
+  @param  SystemTable   A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS   The constructor successfully .
+**/
+EFI_STATUS
+EFIAPI
+DxeRuntimeCapsuleLibConstructor (
+  IN EFI_HANDLE         ImageHandle,
+  IN EFI_SYSTEM_TABLE   *SystemTable
+  )
+{
+  EFI_STATUS     Status;
+  EFI_EVENT      Event;
+
+  //
+  // Make sure we can handle virtual address changes.
+  //
+  Event = NULL;
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  DxeCapsuleLibVirtualAddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &Event
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
new file mode 100644
index 0000000..88a3c61
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
@@ -0,0 +1,83 @@
+## @file
+#  Capsule library instance for DXE_RUNTIME_DRIVER.
+#
+#  Capsule library instance for DXE_RUNTIME_DRIVER module types.
+#
+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD License
+#  which accompanies this distribution.  The full text of the license may be found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = DxeRuntimeCapsuleLib
+  MODULE_UNI_FILE                = DxeRuntimeCapsuleLib.uni
+  FILE_GUID                      = 19BE1E4B-1A9A-44c1-8F12-32DD0470516A
+  MODULE_TYPE                    = DXE_DRIVER
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = CapsuleLib|DXE_RUNTIME_DRIVER
+  CONSTRUCTOR                    = DxeCapsuleLibConstructor
+  CONSTRUCTOR                    = DxeRuntimeCapsuleLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
+#
+
+[Sources]
+  DxeCapsuleLib.c
+  DxeCapsuleProcessLibNull.c
+  DxeCapsuleReportLibNull.c
+  DxeCapsuleRuntime.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+  DxeServicesTableLib
+  UefiBootServicesTableLib
+  DevicePathLib
+  ReportStatusCodeLib
+  PrintLib
+  HobLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax                               ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcessFlag      ## CONSUMES
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeSubClassCapsule                ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesBegin    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsulesEnd      ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmware        ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareSuccess   ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwareFailed    ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSystem         ## CONSUMES
+
+[Protocols]
+  gEsrtManagementProtocolGuid             ## CONSUMES
+  gEfiFirmwareManagementProtocolGuid      ## SOMETIMES_CONSUMES
+  gEdkiiVariableLockProtocolGuid          ## SOMETIMES_CONSUMES
+
+[Guids]
+  gEfiFmpCapsuleGuid                      ## SOMETIMES_CONSUMES ## GUID
+  gWindowsUxCapsuleGuid                   ## SOMETIMES_CONSUMES ## GUID
+  gEfiSystemResourceTableGuid             ## SOMETIMES_CONSUMES ## GUID
+  gEfiCapsuleReportGuid                   ## CONSUMES ## Variable
+  gEfiCapsuleVendorGuid                   ## CONSUMES ## Variable
+  gEfiEndOfDxeEventGroupGuid              ## CONSUMES ## Event
+  gEfiEventVirtualAddressChangeGuid       ## CONSUMES ## Event
+
+[Depex]
+  gEfiVariableWriteArchProtocolGuid
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
new file mode 100644
index 0000000..cd89b13
--- /dev/null
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni
@@ -0,0 +1,22 @@
+// /** @file
+// Capsule library instance for DXE_RUNTIME_DRIVER.
+//
+// Capsule library instance for DXE_RUNTIME_DRIVER module types.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution.  The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "Capsule Support Library"
+
+#string STR_MODULE_DESCRIPTION          #language en-US "Capsule library instance for DXE_RUNTIME_DRIVER module types."
+
-- 
2.7.4.windows.1



  parent reply	other threads:[~2016-10-27 13:36 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-27 13:36 [PATCH V5 00/15] Add capsule update and recovery sample Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 01/15] MdeModulePkg/Include: Add FmpAuthenticationLib header Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 02/15] MdeModulePkg/CapsuleLib: Add ProcessCapsules() API Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 03/15] MdeModulePkg/MdeModulePkg.dec: Add capsule related definition Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 04/15] MdeModulePkg/FmpAuthenticationLibNull: Add NULL instance FMP Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 05/15] MdeModulePkg/DxeCapsuleLibNull: Add ProcessCapsules() interface Jiewen Yao
2016-10-27 13:36 ` Jiewen Yao [this message]
2016-10-27 13:36 ` [PATCH V5 07/15] MdeModulePkg/Esrt: Add ESRT_FW_TYPE_SYSTEMFIRMWARE check Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 09/15] MdeModulePkg/UiApp: Show test key warning info in FrontPage Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 10/15] MdeModulePkg/MdeModulePkg.dsc: Add FMP related component Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 11/15] IntelFrameworkModulePkg/DxeCapsuleLib: Add ProcessCapsules() interface Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 12/15] SecurityPkg/SecurityPkg.dec: Add PcdPkcs7CertBuffer PCD Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 13/15] SecurityPkg/FmpAuthenticationLibPkcs7: Add PKCS7 instance for FMP Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 14/15] SecurityPkg/FmpAuthenticationLibRsa2048Sha256: Add RSA2048 instance Jiewen Yao
2016-10-27 13:36 ` [PATCH V5 15/15] SecurityPkg/SecurityPkg.dsc: Add FmpAuthenticationLib* Jiewen Yao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1477575382-20992-7-git-send-email-jiewen.yao@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox