]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
MdeModulePkg: Add FMP Capsule Image Header extension
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleDump.c
index 97f1893ef433b19b65528e78de4eb9cbe787966d..5725e2f6dd5b454f999c69305e556d974963c14c 100644 (file)
@@ -1,64 +1,29 @@
 /** @file\r
   Dump Capsule image information.\r
 \r
-  Copyright (c) 2016 - 2018, 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
+  Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
-#include <PiDxe.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/PrintLib.h>\r
-#include <Protocol/FirmwareManagement.h>\r
-#include <Guid/ImageAuthentication.h>\r
-#include <Guid/CapsuleReport.h>\r
-#include <Guid/SystemResourceTable.h>\r
-#include <Guid/FmpCapsule.h>\r
-#include <IndustryStandard/WindowsUxCapsule.h>\r
+#include "CapsuleApp.h"\r
 \r
 /**\r
-  Read a file.\r
-\r
-  @param[in]  FileName        The file to be read.\r
-  @param[out] BufferSize      The file buffer size\r
-  @param[out] Buffer          The file buffer\r
+  Validate if it is valid capsule header\r
 \r
-  @retval EFI_SUCCESS    Read file successfully\r
-  @retval EFI_NOT_FOUND  File not found\r
-**/\r
-EFI_STATUS\r
-ReadFileToBuffer (\r
-  IN  CHAR16                               *FileName,\r
-  OUT UINTN                                *BufferSize,\r
-  OUT VOID                                 **Buffer\r
-  );\r
+  This function assumes the caller provided correct CapsuleHeader pointer\r
+  and CapsuleSize.\r
 \r
-/**\r
-  Write a file.\r
+  This function validates the fields in EFI_CAPSULE_HEADER.\r
 \r
-  @param[in] FileName        The file to be written.\r
-  @param[in] BufferSize      The file buffer size\r
-  @param[in] Buffer          The file buffer\r
+  @param[in] CapsuleHeader  Points to a capsule header.\r
+  @param[in] CapsuleSize    Size of the whole capsule image.\r
 \r
-  @retval EFI_SUCCESS    Write file successfully\r
 **/\r
-EFI_STATUS\r
-WriteFileFromBuffer (\r
-  IN  CHAR16                               *FileName,\r
-  IN  UINTN                                BufferSize,\r
-  IN  VOID                                 *Buffer\r
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+  IN EFI_CAPSULE_HEADER     *CapsuleHeader,\r
+  IN UINT64                 CapsuleSize\r
   );\r
 \r
 /**\r
@@ -73,7 +38,7 @@ DumpUxCapsule (
 {\r
   EFI_DISPLAY_CAPSULE                           *DisplayCapsule;\r
   DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader;\r
-  Print(L"[UxCapusule]\n");\r
+  Print(L"[UxCapsule]\n");\r
   Print(L"CapsuleHeader:\n");\r
   Print(L"  CapsuleGuid      - %g\n", &DisplayCapsule->CapsuleHeader.CapsuleGuid);\r
   Print(L"  HeaderSize       - 0x%x\n", DisplayCapsule->CapsuleHeader.HeaderSize);\r
@@ -88,37 +53,6 @@ DumpUxCapsule (
   Print(L"  OffsetY          - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY);\r
 }\r
 \r
-/**\r
-  Dump FMP image authentication information.\r
-\r
-  @param[in] Image      The FMP capsule image\r
-  @param[in] ImageSize  The size of the FMP capsule image in bytes.\r
-\r
-  @return the size of FMP authentication.\r
-**/\r
-UINTN\r
-DumpImageAuthentication (\r
-  IN VOID   *Image,\r
-  IN UINTN  ImageSize\r
-  )\r
-{\r
-  EFI_FIRMWARE_IMAGE_AUTHENTICATION             *ImageAuthentication;\r
-\r
-  ImageAuthentication = Image;\r
-  if (CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertPkcs7Guid) ||\r
-      CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
-    Print(L"[ImageAuthentication]\n");\r
-    Print(L"  MonotonicCount   - 0x%lx\n", ImageAuthentication->MonotonicCount);\r
-    Print(L"WIN_CERTIFICATE:\n");\r
-    Print(L"  dwLength         - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.dwLength);\r
-    Print(L"  wRevision        - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wRevision);\r
-    Print(L"  wCertificateType - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wCertificateType);\r
-    Print(L"  CertType         - %g\n", &ImageAuthentication->AuthInfo.CertType);\r
-    return sizeof(ImageAuthentication->MonotonicCount) + ImageAuthentication->AuthInfo.Hdr.dwLength;\r
-  } else {\r
-    return 0;\r
-  }\r
-}\r
 \r
 /**\r
   Dump a non-nested FMP capsule.\r
@@ -136,7 +70,7 @@ DumpFmpCapsule (
   UINTN                                         Count;\r
   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *FmpImageHeader;\r
 \r
-  Print(L"[FmpCapusule]\n");\r
+  Print(L"[FmpCapsule]\n");\r
   Print(L"CapsuleHeader:\n");\r
   Print(L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);\r
   Print(L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);\r
@@ -162,8 +96,11 @@ DumpFmpCapsule (
     Print(L"  UpdateImageIndex       - 0x%x\n", FmpImageHeader->UpdateImageIndex);\r
     Print(L"  UpdateImageSize        - 0x%x\n", FmpImageHeader->UpdateImageSize);\r
     Print(L"  UpdateVendorCodeSize   - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize);\r
-    if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+    if (FmpImageHeader->Version >= 2) {\r
       Print(L"  UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance);\r
+      if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+        Print(L"  ImageCapsuleSupport    - 0x%lx\n", FmpImageHeader->ImageCapsuleSupport);\r
+      }\r
     }\r
   }\r
 }\r
@@ -214,7 +151,7 @@ IsNestedFmpCapsule (
   // FMP GUID after ESRT one\r
   //\r
   NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
-  NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->HeaderSize - (UINTN)NestedCapsuleHeader;\r
+  NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize- (UINTN)NestedCapsuleHeader;\r
   if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
     return FALSE;\r
   }\r
@@ -248,6 +185,11 @@ DumpCapsule (
     Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName);\r
     goto Done;\r
   }\r
+  if (!IsValidCapsuleHeader (Buffer, FileSize)) {\r
+    Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
+    Status = EFI_INVALID_PARAMETER;\r
+    goto Done;\r
+  }\r
 \r
   CapsuleHeader = Buffer;\r
   if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
@@ -260,7 +202,7 @@ DumpCapsule (
     DumpFmpCapsule(CapsuleHeader);\r
   }\r
   if (IsNestedFmpCapsule(CapsuleHeader)) {\r
-    Print(L"[NestedCapusule]\n");\r
+    Print(L"[NestedCapsule]\n");\r
     Print(L"CapsuleHeader:\n");\r
     Print(L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);\r
     Print(L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);\r
@@ -283,7 +225,7 @@ Done:
   @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
 **/\r
 EFI_STATUS\r
-DmpCapsuleStatusVariable (\r
+DumpCapsuleStatusVariable (\r
   VOID\r
   )\r
 {\r
@@ -399,6 +341,7 @@ CHAR8 *mLastAttemptStatusString[] = {
   "Error: Auth Error",\r
   "Error: Power Event AC",\r
   "Error: Power Event Battery",\r
+  "Error: Unsatisfied Dependencies",\r
 };\r
 \r
 /**\r
@@ -512,6 +455,538 @@ DumpEsrtData (
   Print(L"\n");\r
 }\r
 \r
+\r
+/**\r
+  Dump capsule information from CapsuleHeader\r
+\r
+  @param[in] CapsuleHeader       The CapsuleHeader of the capsule image.\r
+\r
+  @retval EFI_SUCCESS            The capsule information is dumped.\r
+\r
+**/\r
+EFI_STATUS\r
+DumpCapsuleFromBuffer (\r
+  IN EFI_CAPSULE_HEADER                         *CapsuleHeader\r
+  )\r
+{\r
+  if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
+    DumpUxCapsule (CapsuleHeader);\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+    DumpFmpCapsule (CapsuleHeader);\r
+  }\r
+  if (IsNestedFmpCapsule (CapsuleHeader)) {\r
+    Print (L"[NestedCapusule]\n");\r
+    Print (L"CapsuleHeader:\n");\r
+    Print (L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);\r
+    Print (L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);\r
+    Print (L"  Flags            - 0x%x\n", CapsuleHeader->Flags);\r
+    Print (L"  CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);\r
+    DumpFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This routine is called to upper case given unicode string.\r
+\r
+  @param[in]   Str              String to upper case\r
+\r
+  @retval upper cased string after process\r
+\r
+**/\r
+STATIC\r
+CHAR16 *\r
+UpperCaseString (\r
+  IN CHAR16 *Str\r
+  )\r
+{\r
+  CHAR16  *Cptr;\r
+\r
+  for (Cptr = Str; *Cptr != L'\0'; Cptr++) {\r
+    if (L'a' <= *Cptr && *Cptr <= L'z') {\r
+      *Cptr = *Cptr - L'a' + L'A';\r
+    }\r
+  }\r
+\r
+  return Str;\r
+}\r
+\r
+/**\r
+  This routine is used to return substring before period '.' or '\0'\r
+  Caller should respsonsible of substr space allocation & free\r
+\r
+  @param[in]   Str              String to check\r
+  @param[out]  SubStr           First part of string before period or '\0'\r
+  @param[out]  SubStrLen        Length of first part of string\r
+\r
+**/\r
+STATIC\r
+VOID\r
+GetSubStringBeforePeriod (\r
+  IN  CHAR16 *Str,\r
+  OUT CHAR16 *SubStr,\r
+  OUT UINTN  *SubStrLen\r
+  )\r
+{\r
+  UINTN Index;\r
+  for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {\r
+    SubStr[Index] = Str[Index];\r
+  }\r
+\r
+  SubStr[Index] = L'\0';\r
+  *SubStrLen = Index;\r
+}\r
+\r
+/**\r
+  This routine pad the string in tail with input character.\r
+\r
+  @param[in]   StrBuf            Str buffer to be padded, should be enough room for\r
+  @param[in]   PadLen            Expected padding length\r
+  @param[in]   Character         Character used to pad\r
+\r
+**/\r
+STATIC\r
+VOID\r
+PadStrInTail (\r
+  IN CHAR16   *StrBuf,\r
+  IN UINTN    PadLen,\r
+  IN CHAR16   Character\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; StrBuf[Index] != L'\0'; Index++);\r
+\r
+  while(PadLen != 0) {\r
+    StrBuf[Index] = Character;\r
+    Index++;\r
+    PadLen--;\r
+  }\r
+\r
+  StrBuf[Index] = L'\0';\r
+}\r
+\r
+/**\r
+  This routine find the offset of the last period '.' of string. if No period exists\r
+  function FileNameExtension is set to L'\0'\r
+\r
+  @param[in]   FileName           File name to split between last period\r
+  @param[out]  FileNameFirst      First FileName before last period\r
+  @param[out]  FileNameExtension  FileName after last period\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SplitFileNameExtension (\r
+  IN  CHAR16  *FileName,\r
+  OUT CHAR16  *FileNameFirst,\r
+  OUT CHAR16  *FileNameExtension\r
+  )\r
+{\r
+  UINTN Index;\r
+  UINTN StringLen;\r
+\r
+  StringLen = StrLen(FileName);\r
+  for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);\r
+\r
+  //\r
+  // No period exists. No FileName Extension\r
+  //\r
+  if (Index == 0 && FileName[Index] != L'.') {\r
+    FileNameExtension[0] = L'\0';\r
+    Index = StringLen;\r
+  } else {\r
+    StrCpyS (FileNameExtension, MAX_FILE_NAME_LEN, &FileName[Index+1]);\r
+  }\r
+\r
+  //\r
+  // Copy First file name\r
+  //\r
+  StrnCpyS (FileNameFirst, MAX_FILE_NAME_LEN, FileName, Index);\r
+  FileNameFirst[Index] = L'\0';\r
+}\r
+\r
+/**\r
+  The function is called by PerformQuickSort to sort file name in alphabet.\r
+\r
+  @param[in] Left            The pointer to first buffer.\r
+  @param[in] Right           The pointer to second buffer.\r
+\r
+  @retval 0                  Buffer1 equal to Buffer2.\r
+  @return <0                 Buffer1 is less than Buffer2.\r
+  @return >0                 Buffer1 is greater than Buffer2.\r
+\r
+**/\r
+INTN\r
+CompareFileNameInAlphabet (\r
+  IN VOID                         *Left,\r
+  IN VOID                         *Right\r
+  )\r
+{\r
+  EFI_FILE_INFO  *FileInfo1;\r
+  EFI_FILE_INFO  *FileInfo2;\r
+  CHAR16         FileName1[MAX_FILE_NAME_SIZE];\r
+  CHAR16         FileExtension1[MAX_FILE_NAME_SIZE];\r
+  CHAR16         FileName2[MAX_FILE_NAME_SIZE];\r
+  CHAR16         FileExtension2[MAX_FILE_NAME_SIZE];\r
+  CHAR16         TempSubStr1[MAX_FILE_NAME_SIZE];\r
+  CHAR16         TempSubStr2[MAX_FILE_NAME_SIZE];\r
+  UINTN          SubStrLen1;\r
+  UINTN          SubStrLen2;\r
+  INTN           SubStrCmpResult;\r
+\r
+  FileInfo1 = (EFI_FILE_INFO *) (*(UINTN *)Left);\r
+  FileInfo2 = (EFI_FILE_INFO *) (*(UINTN *)Right);\r
+\r
+  SplitFileNameExtension (FileInfo1->FileName, FileName1, FileExtension1);\r
+  SplitFileNameExtension (FileInfo2->FileName, FileName2, FileExtension2);\r
+\r
+  UpperCaseString (FileName1);\r
+  UpperCaseString (FileName2);\r
+\r
+  GetSubStringBeforePeriod (FileName1, TempSubStr1, &SubStrLen1);\r
+  GetSubStringBeforePeriod (FileName2, TempSubStr2, &SubStrLen2);\r
+\r
+  if (SubStrLen1 > SubStrLen2) {\r
+    //\r
+    // Substr in NewFileName is longer.  Pad tail with SPACE\r
+    //\r
+    PadStrInTail (TempSubStr2, SubStrLen1 - SubStrLen2, L' ');\r
+  } else if (SubStrLen1 < SubStrLen2){\r
+    //\r
+    // Substr in ListedFileName is longer. Pad tail with SPACE\r
+    //\r
+    PadStrInTail (TempSubStr1, SubStrLen2 - SubStrLen1, L' ');\r
+  }\r
+\r
+  SubStrCmpResult = StrnCmp (TempSubStr1, TempSubStr2, MAX_FILE_NAME_LEN);\r
+  if (SubStrCmpResult != 0) {\r
+    return SubStrCmpResult;\r
+  }\r
+\r
+  UpperCaseString (FileExtension1);\r
+  UpperCaseString (FileExtension2);\r
+\r
+  return StrnCmp (FileExtension1, FileExtension2, MAX_FILE_NAME_LEN);\r
+}\r
+\r
+/**\r
+  Dump capsule information from disk.\r
+\r
+  @param[in] Fs                  The device path of disk.\r
+  @param[in] DumpCapsuleInfo     The flag to indicate whether to dump the capsule inforomation.\r
+\r
+  @retval EFI_SUCCESS            The capsule information is dumped.\r
+\r
+**/\r
+EFI_STATUS\r
+DumpCapsuleFromDisk (\r
+  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL            *Fs,\r
+  IN BOOLEAN                                    DumpCapsuleInfo\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FILE                                      *Root;\r
+  EFI_FILE                                      *DirHandle;\r
+  EFI_FILE                                      *FileHandle;\r
+  UINTN                                         Index;\r
+  UINTN                                         FileSize;\r
+  VOID                                          *FileBuffer;\r
+  EFI_FILE_INFO                                 **FileInfoBuffer;\r
+  EFI_FILE_INFO                                 *FileInfo;\r
+  UINTN                                         FileCount;\r
+  BOOLEAN                                       NoFile;\r
+\r
+  DirHandle       = NULL;\r
+  FileHandle      = NULL;\r
+  Index           = 0;\r
+  FileInfoBuffer  = NULL;\r
+  FileInfo        = NULL;\r
+  FileCount       = 0;\r
+  NoFile          = FALSE;\r
+\r
+  Status = Fs->OpenVolume (Fs, &Root);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"Cannot open volume. Status = %r\n", Status);\r
+    goto Done;\r
+  }\r
+\r
+  Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);\r
+  if (EFI_ERROR (Status)) {\r
+    Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status);\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Get file count first\r
+  //\r
+  Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\r
+  do {\r
+    if (EFI_ERROR (Status) || FileInfo == NULL) {\r
+      Print (L"Get File Info Fail. Status = %r\n", Status);\r
+      goto Done;\r
+    }\r
+\r
+    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {\r
+      FileCount++;\r
+    }\r
+\r
+    Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"Get Next File Fail. Status = %r\n", Status);\r
+      goto Done;\r
+    }\r
+  } while (!NoFile);\r
+\r
+  if (FileCount == 0) {\r
+    Print (L"Error: No capsule file found!\n");\r
+    Status = EFI_NOT_FOUND;\r
+    goto Done;\r
+  }\r
+\r
+  FileInfoBuffer = AllocateZeroPool (sizeof (FileInfo) * FileCount);\r
+  if (FileInfoBuffer == NULL) {\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+  NoFile = FALSE;\r
+\r
+  //\r
+  // Get all file info\r
+  //\r
+  Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\r
+  do {\r
+    if (EFI_ERROR (Status) || FileInfo == NULL) {\r
+      Print (L"Get File Info Fail. Status = %r\n", Status);\r
+      goto Done;\r
+    }\r
+\r
+    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {\r
+      FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);\r
+    }\r
+\r
+    Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"Get Next File Fail. Status = %r\n", Status);\r
+      goto Done;\r
+    }\r
+  } while (!NoFile);\r
+\r
+  //\r
+  // Sort FileInfoBuffer by alphabet order\r
+  //\r
+  PerformQuickSort (\r
+    FileInfoBuffer,\r
+    FileCount,\r
+    sizeof (FileInfo),\r
+    (SORT_COMPARE) CompareFileNameInAlphabet\r
+    );\r
+\r
+  Print (L"The capsules will be performed by following order:\n");\r
+\r
+  for (Index = 0; Index < FileCount; Index++) {\r
+    Print (L"  %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName);\r
+  }\r
+\r
+  if (!DumpCapsuleInfo) {\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  Print(L"The infomation of the capsules:\n");\r
+\r
+  for (Index = 0; Index < FileCount; Index++) {\r
+    FileHandle = NULL;\r
+    Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]->FileName, EFI_FILE_MODE_READ, 0);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Done;\r
+    }\r
+\r
+    Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);\r
+      FileHandleClose (FileHandle);\r
+      goto Done;\r
+    }\r
+\r
+    FileBuffer = AllocatePool (FileSize);\r
+    if (FileBuffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto Done;\r
+    }\r
+\r
+    Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);\r
+    if (EFI_ERROR (Status)) {\r
+      Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);\r
+      FileHandleClose (FileHandle);\r
+      FreePool (FileBuffer);\r
+      goto Done;\r
+    }\r
+\r
+    Print (L"**************************\n");\r
+    Print (L"  %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName);\r
+    Print (L"**************************\n");\r
+    DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer);\r
+    FileHandleClose (FileHandle);\r
+    FreePool (FileBuffer);\r
+  }\r
+\r
+Done:\r
+  if (FileInfoBuffer != NULL) {\r
+    for (Index = 0; Index < FileCount; Index++) {\r
+      if (FileInfoBuffer[Index] != NULL) {\r
+        FreePool (FileInfoBuffer[Index]);\r
+      }\r
+    }\r
+    FreePool (FileInfoBuffer);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Dump capsule inforomation form Gather list.\r
+\r
+  @param[in]  BlockDescriptors The block descriptors for the capsule images\r
+  @param[in]  DumpCapsuleInfo  The flag to indicate whether to dump the capsule inforomation.\r
+\r
+**/\r
+VOID\r
+DumpBlockDescriptors (\r
+  IN EFI_CAPSULE_BLOCK_DESCRIPTOR   *BlockDescriptors,\r
+  IN BOOLEAN                        DumpCapsuleInfo\r
+  )\r
+{\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR      *TempBlockPtr;\r
+\r
+  TempBlockPtr = BlockDescriptors;\r
+\r
+  while (TRUE) {\r
+    if (TempBlockPtr->Length != 0) {\r
+      if (DumpCapsuleInfo) {\r
+        Print(L"******************************************************\n");\r
+      }\r
+      Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlockPtr->Union.DataBlock, TempBlockPtr->Length);\r
+      if (DumpCapsuleInfo) {\r
+        Print(L"******************************************************\n");\r
+        DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN) TempBlockPtr->Union.DataBlock);\r
+      }\r
+      TempBlockPtr += 1;\r
+    } else {\r
+      if (TempBlockPtr->Union.ContinuationPointer == (UINTN)NULL) {\r
+        break;\r
+      } else {\r
+        TempBlockPtr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockPtr->Union.ContinuationPointer;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Dump Provisioned Capsule.\r
+\r
+  @param[in]  DumpCapsuleInfo  The flag to indicate whether to dump the capsule inforomation.\r
+\r
+**/\r
+VOID\r
+DumpProvisionedCapsule (\r
+  IN BOOLEAN                      DumpCapsuleInfo\r
+  )\r
+{\r
+  EFI_STATUS                      Status;\r
+  CHAR16                          CapsuleVarName[30];\r
+  CHAR16                          *TempVarName;\r
+  UINTN                           Index;\r
+  EFI_PHYSICAL_ADDRESS            *CapsuleDataPtr64;\r
+  UINT16                          *BootNext;\r
+  CHAR16                          BootOptionName[20];\r
+  EFI_BOOT_MANAGER_LOAD_OPTION    BootNextOptionEntry;\r
+  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
+  EFI_SHELL_PROTOCOL              *ShellProtocol;\r
+\r
+  Index             = 0;\r
+  CapsuleDataPtr64  = NULL;\r
+  BootNext          = NULL;\r
+\r
+  ShellProtocol = GetShellProtocol ();\r
+  if (ShellProtocol == NULL) {\r
+    Print (L"Get Shell Protocol Fail\n");\r
+    return ;\r
+  }\r
+\r
+  //\r
+  // Dump capsule provisioned on Memory\r
+  //\r
+  Print (L"#########################\n");\r
+  Print (L"### Capsule on Memory ###\n");\r
+  Print (L"#########################\n");\r
+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+  while (TRUE) {\r
+    if (Index > 0) {\r
+      UnicodeValueToStringS (\r
+        TempVarName,\r
+        sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
+        0,\r
+        Index,\r
+        0\r
+        );\r
+    }\r
+\r
+    Status = GetVariable2 (\r
+              CapsuleVarName,\r
+              &gEfiCapsuleVendorGuid,\r
+              (VOID **) &CapsuleDataPtr64,\r
+              NULL\r
+              );\r
+    if (EFI_ERROR (Status) || CapsuleDataPtr64 == NULL) {\r
+      if (Index == 0) {\r
+        Print (L"No data.\n");\r
+      }\r
+      break;\r
+    }\r
+\r
+    Index++;\r
+    Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64);\r
+    DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN) *CapsuleDataPtr64, DumpCapsuleInfo);\r
+  }\r
+\r
+  //\r
+  // Dump capsule provisioned on Disk\r
+  //\r
+  Print (L"#########################\n");\r
+  Print (L"### Capsule on Disk #####\n");\r
+  Print (L"#########################\n");\r
+  Status = GetVariable2 (\r
+             L"BootNext",\r
+             &gEfiGlobalVariableGuid,\r
+             (VOID **) &BootNext,\r
+             NULL\r
+            );\r
+  if (EFI_ERROR (Status) || BootNext == NULL) {\r
+    Print (L"Get BootNext Variable Fail. Status = %r\n", Status);\r
+  } else {\r
+    UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNext);\r
+    Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Display description and device path\r
+      //\r
+      GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath, &DevicePath, &Fs);\r
+      if(!EFI_ERROR (Status)) {\r
+        Print (L"Capsules are provisioned on BootOption: %s\n", BootNextOptionEntry.Description);\r
+        Print (L"    %s %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE));\r
+        DumpCapsuleFromDisk (Fs, DumpCapsuleInfo);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
 /**\r
   Dump FMP information.\r
 \r
@@ -536,6 +1011,7 @@ DumpFmpImageInfo (
 {\r
   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *CurrentImageInfo;\r
   UINTN                                         Index;\r
+  UINTN                                         Index2;\r
 \r
   Print(L"  DescriptorVersion  - 0x%x\n", DescriptorVersion);\r
   Print(L"  DescriptorCount    - 0x%x\n", DescriptorCount);\r
@@ -572,6 +1048,18 @@ DumpFmpImageInfo (
         Print(L"    LastAttemptVersion          - 0x%x\n", CurrentImageInfo->LastAttemptVersion);\r
         Print(L"    LastAttemptStatus           - 0x%x (%a)\n", CurrentImageInfo->LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus));\r
         Print(L"    HardwareInstance            - 0x%lx\n", CurrentImageInfo->HardwareInstance);\r
+        if (DescriptorVersion > 3) {\r
+          Print(L"    Dependencies                - ");\r
+          if (CurrentImageInfo->Dependencies == NULL) {\r
+            Print(L"NULL\n");\r
+          } else {\r
+            Index2 = 0;\r
+            do {\r
+              Print(L"%02x ", CurrentImageInfo->Dependencies->Dependencies[Index2]);\r
+            } while (CurrentImageInfo->Dependencies->Dependencies[Index2 ++] != EFI_FMP_DEP_END);\r
+            Print(L"\n");\r
+          }\r
+        }\r
       }\r
     }\r
     //\r