]> git.proxmox.com Git - mirror_edk2.git/blobdiff - MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleDump.c
index 4c85e8c23dffff058bf118434617be8d4f0e603f..9fd4af4e5584c85eb8680205113f053214bcf572 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Dump Capsule image information.\r
 \r
-  Copyright (c) 2016 - 2018, 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
@@ -248,6 +279,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
@@ -283,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
@@ -512,6 +548,539 @@ 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
+    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
+  do {\r
+    Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\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
+  do {\r
+    Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\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