]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
MdeModulePkg/CapsuleApp: Fix potential NULL pointer dereference issue
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleDump.c
index 2bb5f1f02cf427888055b285afe84c38709f67b5..7bef5a1378d4851f935c092670b3d54beacd4f93 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Dump Capsule image information.\r
 \r
-  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2016 - 2019, 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
 #include <Library/UefiRuntimeServicesTableLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/PrintLib.h>\r
+#include <Library/FileHandleLib.h>\r
+#include <Library/SortLib.h>\r
+#include <Library/UefiBootManagerLib.h>\r
+#include <Library/DevicePathLib.h>\r
 #include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/Shell.h>\r
 #include <Guid/ImageAuthentication.h>\r
 #include <Guid/CapsuleReport.h>\r
 #include <Guid/SystemResourceTable.h>\r
 #include <Guid/FmpCapsule.h>\r
+#include <Guid/CapsuleVendor.h>\r
 #include <IndustryStandard/WindowsUxCapsule.h>\r
 \r
+//\r
+// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)\r
+//\r
+#define MAX_FILE_NAME_SIZE   522\r
+#define MAX_FILE_NAME_LEN    (MAX_FILE_NAME_SIZE / sizeof(CHAR16))\r
+\r
 /**\r
   Read a file.\r
 \r
@@ -61,6 +74,55 @@ WriteFileFromBuffer (
   IN  VOID                                 *Buffer\r
   );\r
 \r
+/**\r
+  Get shell protocol.\r
+\r
+  @return Pointer to shell protocol.\r
+\r
+**/\r
+EFI_SHELL_PROTOCOL *\r
+GetShellProtocol (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Get SimpleFileSystem from boot option file path.\r
+\r
+  @param[in]  DevicePath     The file path of boot option\r
+  @param[out] FullPath       The full device path of boot device\r
+  @param[out] Fs             The file system within EfiSysPartition\r
+\r
+  @retval EFI_SUCCESS    Get file system successfully\r
+  @retval EFI_NOT_FOUND  No valid file system found\r
+  @retval others         Get file system failed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetEfiSysPartitionFromBootOptionFilePath (\r
+  IN  EFI_DEVICE_PATH_PROTOCOL         *DevicePath,\r
+  OUT EFI_DEVICE_PATH_PROTOCOL         **FullPath,\r
+  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs\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
 /**\r
   Dump UX capsule information.\r
 \r
@@ -88,37 +150,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 +167,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
@@ -214,7 +245,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
@@ -242,11 +273,17 @@ DumpCapsule (
   EFI_CAPSULE_HEADER                            *CapsuleHeader;\r
   EFI_STATUS                                    Status;\r
 \r
+  Buffer = NULL;\r
   Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer);\r
   if (EFI_ERROR(Status)) {\r
     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
@@ -269,7 +306,9 @@ DumpCapsule (
   }\r
 \r
 Done:\r
-  FreePool(Buffer);\r
+  if (Buffer != NULL) {\r
+    FreePool(Buffer);\r
+  }\r
   return Status;\r
 }\r
 \r
@@ -280,7 +319,7 @@ Done:
   @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
 **/\r
 EFI_STATUS\r
-DmpCapsuleStatusVariable (\r
+DumpCapsuleStatusVariable (\r
   VOID\r
   )\r
 {\r
@@ -451,9 +490,6 @@ DumpEsrtEntry (
   Print(L"  FwVersion                - 0x%x\n", EsrtEntry->FwVersion);\r
   Print(L"  LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupportedFwVersion);\r
   Print(L"  CapsuleFlags             - 0x%x\n", EsrtEntry->CapsuleFlags);\r
-  Print(L"    PERSIST_ACROSS_RESET   - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET);\r
-  Print(L"    POPULATE_SYSTEM_TABLE  - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE);\r
-  Print(L"    INITIATE_RESET         - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_INITIATE_RESET);\r
   Print(L"  LastAttemptVersion       - 0x%x\n", EsrtEntry->LastAttemptVersion);\r
   Print(L"  LastAttemptStatus        - 0x%x (%a)\n", EsrtEntry->LastAttemptStatus, LastAttemptStatusToString(EsrtEntry->LastAttemptStatus));\r
 }\r
@@ -512,6 +548,501 @@ 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
+EFIAPI\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
+    return EFI_NOT_FOUND;\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
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Get file count first\r
+  //\r
+  for ( Status = FileHandleFindFirstFile (DirHandle, &FileInfo)\r
+      ; !EFI_ERROR(Status) && !NoFile\r
+      ; Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile)\r
+     ){\r
+    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) == 0) {\r
+      continue;\r
+    }\r
+    FileCount++;\r
+  }\r
+\r
+  if (FileCount == 0) {\r
+    Print (L"Error: No capsule file found!\n");\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  FileInfoBuffer = AllocatePool (sizeof(FileInfo) * FileCount);\r
+  NoFile = FALSE;\r
+\r
+  //\r
+  // Get all file info\r
+  //\r
+  for ( Status = FileHandleFindFirstFile (DirHandle, &FileInfo)\r
+      ; !EFI_ERROR (Status) && !NoFile\r
+      ; Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile)\r
+     ){\r
+    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) == 0) {\r
+      continue;\r
+    }\r
+    FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);\r
+  }\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
+    return EFI_SUCCESS;\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
+      break;\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
+      return Status;\r
+    }\r
+\r
+    FileBuffer = AllocatePool (FileSize);\r
+    if (FileBuffer == NULL) {\r
+      return RETURN_OUT_OF_RESOURCES;\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
+      FreePool (FileBuffer);\r
+      FileHandleClose (FileHandle);\r
+      return Status;\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
+  return EFI_SUCCESS;\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
+  ShellProtocol = GetShellProtocol ();\r
+\r
+  Index             = 0;\r
+  CapsuleDataPtr64  = NULL;\r
+  BootNext          = NULL;\r
+  ShellProtocol     = NULL;\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)) {\r
+      if (Index == 0) {\r
+        Print (L"No data.\n");\r
+      }\r
+      break;\r
+    } else {\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
+  //\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)) {\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
@@ -950,5 +1481,7 @@ DumpFmpImage (
   Status = WriteFileFromBuffer(ImageName, ImageSize, Image);\r
   Print(L"CapsuleApp: Dump %g ImageIndex (0x%x) to %s %r\n", ImageTypeId, ImageIndex, ImageName, Status);\r
 \r
+  FreePool (Image);\r
+\r
   return ;\r
 }\r