]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/DxeCapsuleLibFmp: Add DxeCapsuleLibFmp instance.
authorJiewen Yao <jiewen.yao@intel.com>
Wed, 21 Sep 2016 01:49:12 +0000 (09:49 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Tue, 8 Nov 2016 14:37:00 +0000 (22:37 +0800)
This instance handles Microsoft UX capsule, UEFI defined FMP capsule.
This instance should not assume any capsule image format.

Cc: Feng Tian <feng.tian@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Chao Zhang <chao.b.zhang@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
Reviewed-by: Michael Kinney <michael.d.kinney@intel.com>
Tested-by: Michael Kinney <michael.d.kinney@intel.com>
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.uni [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLibNull.c [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLibNull.c [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleRuntime.c [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf [new file with mode: 0644]
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.uni [new file with mode: 0644]

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