]> git.proxmox.com Git - mirror_edk2.git/commitdiff
MdeModulePkg/CapsuleApp: Add CapsuleApp application.
authorJiewen Yao <jiewen.yao@intel.com>
Wed, 21 Sep 2016 02:43:03 +0000 (10:43 +0800)
committerJiewen Yao <jiewen.yao@intel.com>
Tue, 8 Nov 2016 14:37:05 +0000 (22:37 +0800)
This CapsuleApp can help perform capsule update in UEFI shell environment.
It can also dump capsule information, capsule status variable,
ESRT and FMP.

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/Application/CapsuleApp/AppSupport.c [new file with mode: 0644]
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c [new file with mode: 0644]
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf [new file with mode: 0644]
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni [new file with mode: 0644]
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni [new file with mode: 0644]
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c [new file with mode: 0644]

diff --git a/MdeModulePkg/Application/CapsuleApp/AppSupport.c b/MdeModulePkg/Application/CapsuleApp/AppSupport.c
new file mode 100644 (file)
index 0000000..0a1224d
--- /dev/null
@@ -0,0 +1,448 @@
+/** @file\r
+  A shell application that triggers capsule update process.\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 <Uefi.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/LoadedImage.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/ShellParameters.h>\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/Gpt.h>\r
+\r
+#define MAX_ARG_NUM     11\r
+\r
+UINTN  Argc;\r
+CHAR16 **Argv;\r
+\r
+/**\r
+\r
+  This function parse application ARG.\r
+\r
+  @return Status\r
+**/\r
+EFI_STATUS\r
+GetArg (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  gImageHandle,\r
+                  &gEfiShellParametersProtocolGuid,\r
+                  (VOID**)&ShellParameters\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Argc = ShellParameters->Argc;\r
+  Argv = ShellParameters->Argv;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Return File System Volume containing this shell application.\r
+\r
+  @return File System Volume containing this shell application.\r
+**/\r
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *\r
+GetMyVol (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  gImageHandle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **)&LoadedImage\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  LoadedImage->DeviceHandle,\r
+                  &gEfiSimpleFileSystemProtocolGuid,\r
+                  (VOID **)&Vol\r
+                  );\r
+  if (!EFI_ERROR (Status)) {\r
+    return Vol;\r
+  }\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Read a file from this volume.\r
+\r
+  @param[in]  Vol             File System Volume\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
+\r
+  @retval EFI_SUCCESS    Read file successfully\r
+  @retval EFI_NOT_FOUND  File not found\r
+**/\r
+EFI_STATUS\r
+ReadFileFromVol (\r
+  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol,\r
+  IN  CHAR16                            *FileName,\r
+  OUT UINTN                             *BufferSize,\r
+  OUT VOID                              **Buffer\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_FILE_HANDLE                   RootDir;\r
+  EFI_FILE_HANDLE                   Handle;\r
+  UINTN                             FileInfoSize;\r
+  EFI_FILE_INFO                     *FileInfo;\r
+  UINTN                             TempBufferSize;\r
+  VOID                              *TempBuffer;\r
+\r
+  //\r
+  // Open the root directory\r
+  //\r
+  Status = Vol->OpenVolume (Vol, &RootDir);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the file\r
+  //\r
+  Status = RootDir->Open (\r
+                      RootDir,\r
+                      &Handle,\r
+                      FileName,\r
+                      EFI_FILE_MODE_READ,\r
+                      0\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    RootDir->Close (RootDir);\r
+    return Status;\r
+  }\r
+\r
+  RootDir->Close (RootDir);\r
+\r
+  //\r
+  // Get the file information\r
+  //\r
+  FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;\r
+\r
+  FileInfo = AllocateZeroPool (FileInfoSize);\r
+  if (FileInfo == NULL) {\r
+    Handle->Close (Handle);\r
+    return Status;\r
+  }\r
+\r
+  Status = Handle->GetInfo (\r
+                     Handle,\r
+                     &gEfiFileInfoGuid,\r
+                     &FileInfoSize,\r
+                     FileInfo\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    Handle->Close (Handle);\r
+    gBS->FreePool (FileInfo);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Allocate buffer for the file data. The last CHAR16 is for L'\0'\r
+  //\r
+  TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);\r
+  TempBuffer = AllocateZeroPool (TempBufferSize);\r
+  if (TempBuffer == NULL) {\r
+    Handle->Close (Handle);\r
+    gBS->FreePool (FileInfo);\r
+    return Status;\r
+  }\r
+\r
+  gBS->FreePool (FileInfo);\r
+\r
+  //\r
+  // Read the file data to the buffer\r
+  //\r
+  Status = Handle->Read (\r
+                     Handle,\r
+                     &TempBufferSize,\r
+                     TempBuffer\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    Handle->Close (Handle);\r
+    gBS->FreePool (TempBuffer);\r
+    return Status;\r
+  }\r
+\r
+  Handle->Close (Handle);\r
+\r
+  *BufferSize = TempBufferSize;\r
+  *Buffer     = TempBuffer;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Read a file.\r
+  If ScanFs is FLASE, it will use this Vol as default Fs.\r
+  If ScanFs is TRUE, it will scan all FS and check the file.\r
+    If there is only one file match the name, it will be read.\r
+    If there is more than one file match the name, it will return Error.\r
+\r
+  @param[in]  ThisVol         File System Volume\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
+  @param[in]  ScanFs          Need Scan all FS\r
+\r
+  @retval EFI_SUCCESS    Read file successfully\r
+  @retval EFI_NOT_FOUND  File not found\r
+  @retval EFI_NO_MAPPING There is duplicated files found\r
+**/\r
+EFI_STATUS\r
+ReadFileToBufferEx (\r
+  IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   **ThisVol,\r
+  IN  CHAR16                               *FileName,\r
+  OUT UINTN                                *BufferSize,\r
+  OUT VOID                                 **Buffer,\r
+  IN  BOOLEAN                              ScanFs\r
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;\r
+  UINTN                             TempBufferSize;\r
+  VOID                              *TempBuffer;\r
+  UINTN                             NoHandles;\r
+  EFI_HANDLE                        *HandleBuffer;\r
+  UINTN                             Index;\r
+\r
+  //\r
+  // Check parameters\r
+  //\r
+  if ((FileName == NULL) || (Buffer == NULL) || (ThisVol == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // not scan fs\r
+  //\r
+  if (!ScanFs) {\r
+    if (*ThisVol == NULL) {\r
+      *ThisVol = GetMyVol ();\r
+      if (*ThisVol == NULL) {\r
+        return EFI_INVALID_PARAMETER;\r
+      }\r
+    }\r
+    //\r
+    // Read file directly from Vol\r
+    //\r
+    return ReadFileFromVol (*ThisVol, FileName, BufferSize, Buffer);\r
+  }\r
+\r
+  //\r
+  // need scan fs\r
+  //\r
+\r
+  //\r
+  // Get all Vol handle\r
+  //\r
+  Status = gBS->LocateHandleBuffer (\r
+                   ByProtocol,\r
+                   &gEfiSimpleFileSystemProtocolGuid,\r
+                   NULL,\r
+                   &NoHandles,\r
+                   &HandleBuffer\r
+                   );\r
+  if (EFI_ERROR (Status) && (NoHandles == 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Walk through each Vol\r
+  //\r
+  *ThisVol = NULL;\r
+  *BufferSize = 0;\r
+  *Buffer     = NULL;\r
+  for (Index = 0; Index < NoHandles; Index++) {\r
+    Status = gBS->HandleProtocol (\r
+                    HandleBuffer[Index],\r
+                    &gEfiSimpleFileSystemProtocolGuid,\r
+                    (VOID **)&Vol\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
+\r
+    Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);\r
+    if (!EFI_ERROR (Status)) {\r
+      //\r
+      // Read file OK, check duplication\r
+      //\r
+      if (*ThisVol != NULL) {\r
+        //\r
+        // Find the duplicated file\r
+        //\r
+        gBS->FreePool (TempBuffer);\r
+        gBS->FreePool (*Buffer);\r
+        Print (L"Duplicated FileName found!\n");\r
+        return EFI_NO_MAPPING;\r
+      } else {\r
+        //\r
+        // Record value\r
+        //\r
+        *ThisVol = Vol;\r
+        *BufferSize = TempBufferSize;\r
+        *Buffer     = TempBuffer;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Scan Fs done\r
+  //\r
+  if (*ThisVol == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Done\r
+  //\r
+  return EFI_SUCCESS;\r
+}\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
+\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
+{\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;\r
+  Vol = NULL;\r
+  return ReadFileToBufferEx(&Vol, FileName, BufferSize, Buffer, FALSE);\r
+}\r
+\r
+/**\r
+  Write a file.\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
+\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
+  )\r
+{\r
+  EFI_STATUS                        Status;\r
+  EFI_FILE_HANDLE                   RootDir;\r
+  EFI_FILE_HANDLE                   Handle;\r
+  UINTN                             TempBufferSize;\r
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;\r
+\r
+  Vol = GetMyVol();\r
+  if (Vol == NULL) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  //\r
+  // Open the root directory\r
+  //\r
+  Status = Vol->OpenVolume (Vol, &RootDir);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the file\r
+  //\r
+  Status = RootDir->Open (\r
+                      RootDir,\r
+                      &Handle,\r
+                      FileName,\r
+                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,\r
+                      0\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    RootDir->Close (RootDir);\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Delete file\r
+  //\r
+  Status = Handle->Delete(Handle);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Open the file again\r
+  //\r
+  Status = RootDir->Open (\r
+                      RootDir,\r
+                      &Handle,\r
+                      FileName,\r
+                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE,\r
+                      0\r
+                      );\r
+  if (EFI_ERROR (Status)) {\r
+    RootDir->Close (RootDir);\r
+    return Status;\r
+  }\r
+\r
+  RootDir->Close (RootDir);\r
+\r
+  //\r
+  // Write the file data from the buffer\r
+  //\r
+  TempBufferSize = BufferSize;\r
+  Status = Handle->Write (\r
+                     Handle,\r
+                     &TempBufferSize,\r
+                     Buffer\r
+                     );\r
+  if (EFI_ERROR (Status)) {\r
+    Handle->Close (Handle);\r
+    return Status;\r
+  }\r
+\r
+  Handle->Close (Handle);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
new file mode 100644 (file)
index 0000000..81a98ae
--- /dev/null
@@ -0,0 +1,850 @@
+/** @file\r
+  A shell application that triggers capsule update process.\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 <Uefi.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/LoadedImage.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/GraphicsOutput.h>\r
+#include <Guid/FileInfo.h>\r
+#include <Guid/Gpt.h>\r
+#include <Guid/GlobalVariable.h>\r
+#include <Guid/CapsuleReport.h>\r
+#include <Guid/SystemResourceTable.h>\r
+#include <Guid/FmpCapsule.h>\r
+#include <IndustryStandard/WindowsUxCapsule.h>\r
+\r
+#define CAPSULE_HEADER_SIZE  0x20\r
+\r
+#define NESTED_CAPSULE_HEADER_SIZE  SIZE_4KB\r
+#define SYSTEM_FIRMWARE_FLAG 0x50000\r
+#define DEVICE_FIRMWARE_FLAG 0x78010\r
+\r
+#define EFI_CAPSULE_FROM_FILE_DIR                           L"\\EFI\\UpdateCapsule\\"\r
+#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED  0x0000000000000004\r
+\r
+#define MAJOR_VERSION   1\r
+#define MINOR_VERSION   0\r
+\r
+#define MAX_CAPSULE_NUM 10\r
+\r
+extern UINTN  Argc;\r
+extern CHAR16 **Argv;\r
+\r
+//\r
+// Define how many block descriptors we want to test with.\r
+//\r
+UINTN  NumberOfDescriptors = 1;\r
+UINTN  CapsuleFirstIndex;\r
+UINTN  CapsuleLastIndex;\r
+\r
+/**\r
+  Dump capsule information\r
+\r
+  @param[in] CapsuleName  The name of the capsule image.\r
+\r
+  @retval EFI_SUCCESS            The capsule information is dumped.\r
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DumpCapsule (\r
+  IN CHAR16                                        *CapsuleName\r
+  );\r
+\r
+/**\r
+  Dump capsule status variable.\r
+\r
+  @retval EFI_SUCCESS            The capsule status variable is dumped.\r
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DmpCapsuleStatusVariable (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Dump FMP protocol info.\r
+**/\r
+VOID\r
+DumpFmpData (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Dump ESRT info.\r
+**/\r
+VOID\r
+DumpEsrtData (\r
+  VOID\r
+  );\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
+\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
+\r
+/**\r
+  Write a file.\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
+\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
+  );\r
+\r
+/**\r
+\r
+  This function parse application ARG.\r
+\r
+  @return Status\r
+**/\r
+EFI_STATUS\r
+GetArg (\r
+  VOID\r
+  );\r
+\r
+/**\r
+  Create UX capsule.\r
+\r
+  @retval EFI_SUCCESS            The capsule header is appended.\r
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to create UX capsule.\r
+**/\r
+EFI_STATUS\r
+CreateBmpFmp (\r
+  VOID\r
+  )\r
+{\r
+  CHAR16                                        *OutputCapsuleName;\r
+  VOID                                          *BmpBuffer;\r
+  UINTN                                         FileSize;\r
+  CHAR16                                        *BmpName;\r
+  UINT8                                         *FullCapsuleBuffer;\r
+  UINTN                                         FullCapsuleBufferSize;\r
+  EFI_DISPLAY_CAPSULE                           *DisplayCapsule;\r
+  EFI_STATUS                                    Status;\r
+  EFI_GRAPHICS_OUTPUT_PROTOCOL                  *Gop;\r
+\r
+  Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"CapsuleApp: NO GOP is found.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
+  Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);\r
+  Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);\r
+  // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
+  // VerticalResolution   >= BMP_IMAGE_HEADER.PixelHeight\r
+\r
+  if (Argc != 5) {\r
+    Print(L"CapsuleApp: Invalid Parameter.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (StrCmp(Argv[3], L"-O") != 0) {\r
+    Print(L"CapsuleApp: NO output capsule name.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  OutputCapsuleName = Argv[4];\r
+\r
+  BmpBuffer = NULL;\r
+  FileSize = 0;\r
+  FullCapsuleBuffer = NULL;\r
+\r
+  BmpName = Argv[2];\r
+  Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);\r
+    goto Done;\r
+  }\r
+\r
+  FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;\r
+  FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
+  if (FullCapsuleBuffer == NULL) {\r
+    Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;\r
+  CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);\r
+  DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);\r
+  DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
+  DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
+\r
+  DisplayCapsule->ImagePayload.Version = 1;\r
+  DisplayCapsule->ImagePayload.Checksum = 0;\r
+  DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
+  DisplayCapsule->ImagePayload.Reserved = 0;\r
+  DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
+  DisplayCapsule->ImagePayload.OffsetX = 0;\r
+  DisplayCapsule->ImagePayload.OffsetY = 0;\r
+\r
+  CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);\r
+\r
+  DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);\r
+\r
+  Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
+  Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
+\r
+Done:\r
+  if (BmpBuffer != NULL) {\r
+    FreePool(BmpBuffer);\r
+  }\r
+\r
+  if (FullCapsuleBuffer != NULL) {\r
+    FreePool(FullCapsuleBuffer);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Get ImageTypeId in the FMP capsule header.\r
+\r
+  @param[in] CapsuleHeader  The FMP capsule image header.\r
+\r
+  @return ImageTypeId\r
+**/\r
+EFI_GUID *\r
+GetCapsuleImageTypeId (\r
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader\r
+  )\r
+{\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;\r
+  UINT64                                       *ItemOffsetList;\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
+\r
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+  if (FmpCapsuleHeader->PayloadItemCount == 0) {\r
+    return NULL;\r
+  }\r
+  ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);\r
+  return &ImageHeader->UpdateImageTypeId;\r
+}\r
+\r
+/**\r
+  Get ESRT FwType according to ImageTypeId\r
+\r
+  @param[in]  ImageTypeId   ImageTypeId of an FMP capsule.\r
+\r
+  @return ESRT FwType\r
+**/\r
+UINT32\r
+GetEsrtFwType (\r
+  IN  EFI_GUID                                      *ImageTypeId\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;\r
+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;\r
+  UINTN                      Index;\r
+\r
+  //\r
+  // Check ESRT\r
+  //\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, ImageTypeId)) {\r
+        return EsrtEntry->FwType;\r
+      }\r
+    }\r
+  }\r
+\r
+  return ESRT_FW_TYPE_UNKNOWN;\r
+}\r
+\r
+/**\r
+  Append a capsule header on top of current image.\r
+  This function follows Windows UEFI Firmware Update Platform document.\r
+\r
+  @retval EFI_SUCCESS            The capsule header is appended.\r
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to append capsule header.\r
+**/\r
+EFI_STATUS\r
+CreateNestedFmp (\r
+  VOID\r
+  )\r
+{\r
+  CHAR16                                        *OutputCapsuleName;\r
+  VOID                                          *CapsuleBuffer;\r
+  UINTN                                         FileSize;\r
+  CHAR16                                        *CapsuleName;\r
+  UINT8                                         *FullCapsuleBuffer;\r
+  UINTN                                         FullCapsuleBufferSize;\r
+  EFI_CAPSULE_HEADER                            *NestedCapsuleHeader;\r
+  EFI_GUID                                      *ImageTypeId;\r
+  UINT32                                        FwType;\r
+  EFI_STATUS                                    Status;\r
+\r
+  if (Argc != 5) {\r
+    Print(L"CapsuleApp: Invalid Parameter.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (StrCmp(Argv[3], L"-O") != 0) {\r
+    Print(L"CapsuleApp: NO output capsule name.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  OutputCapsuleName = Argv[4];\r
+\r
+  CapsuleBuffer = NULL;\r
+  FileSize = 0;\r
+  FullCapsuleBuffer = NULL;\r
+\r
+  CapsuleName = Argv[2];\r
+  Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
+    goto Done;\r
+  }\r
+\r
+  ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);\r
+  if (ImageTypeId == NULL) {\r
+    Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
+    goto Done;\r
+  }\r
+  FwType = GetEsrtFwType(ImageTypeId);\r
+  if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
+    Print(L"CapsuleApp: Capsule FwType is invalid.\n");\r
+    goto Done;\r
+  }\r
+\r
+  FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;\r
+  FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);\r
+  if (FullCapsuleBuffer == NULL) {\r
+    Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
+    Status = EFI_OUT_OF_RESOURCES;\r
+    goto Done;\r
+  }\r
+\r
+  NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;\r
+  ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
+  CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
+  NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
+  NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
+  NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
+\r
+  CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
+\r
+  Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
+  Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
+\r
+Done:\r
+  if (CapsuleBuffer != NULL) {\r
+    FreePool(CapsuleBuffer);\r
+  }\r
+\r
+  if (FullCapsuleBuffer != NULL) {\r
+    FreePool(FullCapsuleBuffer);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Clear capsule status variable.\r
+\r
+  @retval EFI_SUCCESS            The capsule status variable is cleared.\r
+**/\r
+EFI_STATUS\r
+ClearCapsuleStatusVariable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINT32                              Index;\r
+  CHAR16                              CapsuleVarName[20];\r
+  CHAR16                              *TempVarName;\r
+\r
+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+  Index = 0;\r
+\r
+  while (TRUE) {\r
+    UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
+\r
+    Status = gRT->SetVariable (\r
+                    CapsuleVarName,\r
+                    &gEfiCapsuleReportGuid,\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
+\r
+    Index++;\r
+    if (Index > 0xFFFF) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Build Gather list for a list of capsule images.\r
+\r
+  @param[in]  CapsuleBuffer    An array of pointer to capsule images\r
+  @param[in]  FileSize         An array of UINTN to capsule images size\r
+  @param[in]  CapsuleNum       The count of capsule images\r
+  @param[out] BlockDescriptors The block descriptors for the capsule images\r
+\r
+  @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
+**/\r
+EFI_STATUS\r
+BuildGatherList (\r
+  IN VOID                          **CapsuleBuffer,\r
+  IN UINTN                         *FileSize,\r
+  IN UINTN                         CapsuleNum,\r
+  OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors1;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors2;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorPre;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorsHeader;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr;\r
+  UINT8                         *TempDataPtr;\r
+  UINTN                         SizeLeft;\r
+  UINTN                         Size;\r
+  INT32                         Count;\r
+  INT32                         Number;\r
+  UINTN                         Index;\r
+\r
+  TempBlockPtr           = NULL;\r
+  BlockDescriptors1      = NULL;\r
+  BlockDescriptors2      = NULL;\r
+  BlockDescriptorPre     = NULL;\r
+  BlockDescriptorsHeader = NULL;\r
+\r
+  for (Index = 0; Index < CapsuleNum; Index++) {\r
+    //\r
+    // Allocate memory for the descriptors.\r
+    //\r
+    if (NumberOfDescriptors == 1) {\r
+      Count = 2;\r
+    } else {\r
+      Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
+    }\r
+\r
+    Size               = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+    BlockDescriptors1  = AllocateRuntimeZeroPool (Size);\r
+    if (BlockDescriptors1 == NULL) {\r
+      Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      goto ERREXIT;\r
+    } else {\r
+      Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);\r
+      Print (L"CapsuleApp: capsule data starts          at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);\r
+    }\r
+\r
+    //\r
+    // Record descirptor header\r
+    //\r
+    if (Index == 0) {\r
+      BlockDescriptorsHeader = BlockDescriptors1;\r
+    }\r
+\r
+    if (BlockDescriptorPre != NULL) {\r
+      BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;\r
+      BlockDescriptorPre->Length = 0;\r
+    }\r
+\r
+    //\r
+    // Fill them in\r
+    //\r
+    TempBlockPtr  = BlockDescriptors1;\r
+    TempDataPtr   = CapsuleBuffer[Index];\r
+    SizeLeft      = FileSize[Index];\r
+    for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
+      //\r
+      // Divide remaining data in half\r
+      //\r
+      if (NumberOfDescriptors != 1) {\r
+        if (SizeLeft == 1) {\r
+          Size = 1;\r
+        } else {\r
+          Size = SizeLeft / 2;\r
+        }\r
+      } else {\r
+        Size = SizeLeft;\r
+      }\r
+      TempBlockPtr->Union.DataBlock    = (UINTN)TempDataPtr;\r
+      TempBlockPtr->Length  = Size;\r
+      Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
+      SizeLeft -= Size;\r
+      TempDataPtr += Size;\r
+      TempBlockPtr++;\r
+    }\r
+\r
+    //\r
+    // Allocate the second list, point the first block's last entry to point\r
+    // to this one, and fill this one in. Worst case is that the previous\r
+    // list only had one element that pointed here, so we need at least two\r
+    // elements -- one to point to all the data, another to terminate the list.\r
+    //\r
+    if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
+      Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
+      if (Count == 1) {\r
+        Count++;\r
+      }\r
+\r
+      Size              = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
+      BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
+      if (BlockDescriptors2 == NULL) {\r
+        Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        goto ERREXIT;\r
+      }\r
+\r
+      //\r
+      // Point the first list's last element to point to this second list.\r
+      //\r
+      TempBlockPtr->Union.ContinuationPointer   = (UINTN) BlockDescriptors2;\r
+\r
+      TempBlockPtr->Length  = 0;\r
+      TempBlockPtr = BlockDescriptors2;\r
+      for (Number = 0; Number < Count - 1; Number++) {\r
+        //\r
+        // If second-to-last one, then dump rest to this element\r
+        //\r
+        if (Number == (Count - 2)) {\r
+          Size = SizeLeft;\r
+        } else {\r
+          //\r
+          // Divide remaining data in half\r
+          //\r
+          if (SizeLeft == 1) {\r
+            Size = 1;\r
+          } else {\r
+            Size = SizeLeft / 2;\r
+          }\r
+        }\r
+\r
+        TempBlockPtr->Union.DataBlock    = (UINTN)TempDataPtr;\r
+        TempBlockPtr->Length  = Size;\r
+        Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", (UINTN) TempDataPtr, Size);\r
+        SizeLeft -= Size;\r
+        TempDataPtr += Size;\r
+        TempBlockPtr++;\r
+        if (SizeLeft == 0) {\r
+          break;\r
+        }\r
+      }\r
+    }\r
+\r
+    BlockDescriptorPre = TempBlockPtr;\r
+    BlockDescriptors1  = NULL;\r
+  }\r
+\r
+  //\r
+  // Null-terminate.\r
+  //\r
+  if (TempBlockPtr != NULL) {\r
+    TempBlockPtr->Union.ContinuationPointer    = (UINTN)NULL;\r
+    TempBlockPtr->Length  = 0;\r
+    *BlockDescriptors = BlockDescriptorsHeader;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+ERREXIT:\r
+  if (BlockDescriptors1 != NULL) {\r
+    FreePool(BlockDescriptors1);\r
+  }\r
+\r
+  if (BlockDescriptors2 != NULL) {\r
+    FreePool(BlockDescriptors2);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Clear the Gather list for a list of capsule images.\r
+\r
+  @param[in]  BlockDescriptors The block descriptors for the capsule images\r
+  @param[in]  CapsuleNum       The count of capsule images\r
+**/\r
+VOID\r
+CleanGatherList (\r
+  IN EFI_CAPSULE_BLOCK_DESCRIPTOR   *BlockDescriptors,\r
+  IN UINTN                          CapsuleNum\r
+  )\r
+{\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr1;\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr2;\r
+  UINTN                          Index;\r
+\r
+  if (BlockDescriptors != NULL) {\r
+    TempBlockPtr1 = BlockDescriptors;\r
+    while (1){\r
+      TempBlockPtr = TempBlockPtr1;\r
+      for (Index = 0; Index < CapsuleNum; Index++) {\r
+        if (TempBlockPtr[Index].Length == 0) {\r
+          break;\r
+        }\r
+      }\r
+\r
+      if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
+        break;\r
+      }\r
+\r
+      TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);\r
+      FreePool(TempBlockPtr1);\r
+      TempBlockPtr1 = TempBlockPtr2;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+  Print APP usage.\r
+**/\r
+VOID\r
+PrintUsage (\r
+  VOID\r
+  )\r
+{\r
+  Print(L"CapsuleApp:  usage\n");\r
+  Print(L"  CapsuleApp <Capsule...>\n");\r
+  Print(L"  CapsuleApp -S\n");\r
+  Print(L"  CapsuleApp -C\n");\r
+  Print(L"  CapsuleApp -P\n");\r
+  Print(L"  CapsuleApp -E\n");\r
+  Print(L"  CapsuleApp -G <BMP> -O <Capsule>\n");\r
+  Print(L"  CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
+  Print(L"  CapsuleApp -D <Capsule>\n");\r
+  Print(L"Parameter:\n");\r
+  Print(L"  -S:  Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
+  Print(L"       which is defined in UEFI specification.\n");\r
+  Print(L"  -C:  Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");\r
+  Print(L"       which is defined in UEFI specification.\n");\r
+  Print(L"  -P:  Dump UEFI FMP protocol info.\n");\r
+  Print(L"  -E:  Dump UEFI ESRT table info.\n");\r
+  Print(L"  -G:  Convert a BMP file to be a UX capsule,\n");\r
+  Print(L"       according to Windows Firmware Update document\n");\r
+  Print(L"  -N:  Append a Capsule Header to an existing capsule image,\n");\r
+  Print(L"       according to Windows Firmware Update document\n");\r
+  Print(L"  -O:  Output new Capsule file name\n");\r
+  Print(L"  -D:  Dump Capsule image header information and FMP header information,\n");\r
+  Print(L"       if it is an FMP capsule.\n");\r
+}\r
+\r
+/**\r
+  Update Capsule image.\r
+\r
+  @param[in]  ImageHandle     The image handle.\r
+  @param[in]  SystemTable     The system table.\r
+\r
+  @retval EFI_SUCCESS            Command completed successfully.\r
+  @retval EFI_INVALID_PARAMETER  Command usage error.\r
+  @retval EFI_NOT_FOUND          The input file can't be found.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+UefiMain (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  UINTN                         FileSize[MAX_CAPSULE_NUM];\r
+  VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];\r
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;\r
+  EFI_CAPSULE_HEADER             *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
+  UINT64                         MaxCapsuleSize;\r
+  EFI_RESET_TYPE                 ResetType;\r
+  BOOLEAN                        NeedReset;\r
+  CHAR16                         *CapsuleName;\r
+  UINTN                          CapsuleNum;\r
+  UINTN                          Index;\r
+\r
+  Status = GetArg();\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"Please use UEFI SHELL to run this application!\n", Status);\r
+    return Status;\r
+  }\r
+  if (Argc < 2) {\r
+    PrintUsage();\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  if (StrCmp(Argv[1], L"-D") == 0) {\r
+    Status = DumpCapsule(Argv[2]);\r
+    return Status;\r
+  }\r
+  if (StrCmp(Argv[1], L"-G") == 0) {\r
+    Status = CreateBmpFmp();\r
+    return Status;\r
+  }\r
+  if (StrCmp(Argv[1], L"-N") == 0) {\r
+    Status = CreateNestedFmp();\r
+    return Status;\r
+  }\r
+  if (StrCmp(Argv[1], L"-S") == 0) {\r
+    Status = DmpCapsuleStatusVariable();\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (StrCmp(Argv[1], L"-C") == 0) {\r
+    Status = ClearCapsuleStatusVariable();\r
+    return Status;\r
+  }\r
+  if (StrCmp(Argv[1], L"-P") == 0) {\r
+    DumpFmpData();\r
+    return EFI_SUCCESS;\r
+  }\r
+  if (StrCmp(Argv[1], L"-E") == 0) {\r
+    DumpEsrtData();\r
+    return EFI_SUCCESS;\r
+  }\r
+  CapsuleFirstIndex = 1;\r
+  CapsuleLastIndex = Argc - 1;\r
+  CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
+\r
+  if (CapsuleFirstIndex > CapsuleLastIndex) {\r
+    Print(L"CapsuleApp: NO capsule image.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  if (CapsuleNum > MAX_CAPSULE_NUM) {\r
+    Print(L"CapsuleApp: Too many capsule images.\n");\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));\r
+  ZeroMem(&FileSize, sizeof(FileSize));\r
+  BlockDescriptors = NULL;\r
+\r
+  for (Index = 0; Index < CapsuleNum; Index++) {\r
+    CapsuleName = Argv[CapsuleFirstIndex + Index];\r
+    Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);\r
+    if (EFI_ERROR(Status)) {\r
+      Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Every capsule use 2 descriptor 1 for data 1 for end\r
+  //\r
+  Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);\r
+  if (EFI_ERROR(Status)) {\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Call the runtime service capsule.\r
+  //\r
+  NeedReset = FALSE;\r
+  for (Index = 0; Index < CapsuleNum; Index++) {\r
+    CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];\r
+    if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
+      NeedReset = TRUE;\r
+    }\r
+  }\r
+  CapsuleHeaderArray[CapsuleNum] = NULL;\r
+\r
+  //\r
+  // Inquire platform capability of UpdateCapsule.\r
+  //\r
+  Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
+  if (EFI_ERROR(Status)) {\r
+    Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
+    goto Done;\r
+  }\r
+\r
+  for (Index = 0; Index < CapsuleNum; Index++) {\r
+    if (FileSize[Index] > MaxCapsuleSize) {\r
+      Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
+      Status = EFI_UNSUPPORTED;\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check whether the input capsule image has the flag of persist across system reset.\r
+  //\r
+  if (NeedReset) {\r
+    Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
+    if (Status != EFI_SUCCESS) {\r
+      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
+      goto Done;\r
+    }\r
+    //\r
+    // For capsule who has reset flag, after calling UpdateCapsule service,triger a\r
+    // system reset to process capsule persist across a system reset.\r
+    //\r
+    gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
+  } else {\r
+    //\r
+    // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
+    // system reset. The service will process the capsule immediately.\r
+    //\r
+    Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);\r
+    if (Status != EFI_SUCCESS) {\r
+      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
+    }\r
+  }\r
+\r
+  Status = EFI_SUCCESS;\r
+\r
+Done:\r
+  for (Index = 0; Index < CapsuleNum; Index++) {\r
+    if (CapsuleBuffer[Index] != NULL) {\r
+      FreePool (CapsuleBuffer[Index]);\r
+    }\r
+  }\r
+\r
+  CleanGatherList(BlockDescriptors, CapsuleNum);\r
+\r
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
new file mode 100644 (file)
index 0000000..2084e5f
--- /dev/null
@@ -0,0 +1,71 @@
+##  @file\r
+#  A shell application that triggers capsule update process.\r
+#\r
+# This application can trigger capsule update process. It can also\r
+# generate capsule image, or dump capsule variable information.\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                    = 0x00010006\r
+  BASE_NAME                      = CapsuleApp\r
+  MODULE_UNI_FILE                = CapsuleApp.uni\r
+  FILE_GUID                      = 4CEF31DA-8682-4274-9CC4-AEE7516A5E7B\r
+  MODULE_TYPE                    = UEFI_APPLICATION\r
+  VERSION_STRING                 = 1.0\r
+  ENTRY_POINT                    = UefiMain\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64\r
+#\r
+\r
+[Sources]\r
+  CapsuleApp.c\r
+  CapsuleDump.c\r
+  AppSupport.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+[Guids]\r
+  gEfiFileInfoGuid\r
+  gEfiPartTypeSystemPartGuid\r
+  gEfiGlobalVariableGuid\r
+  gEfiCapsuleReportGuid\r
+  gEfiFmpCapsuleGuid\r
+  gWindowsUxCapsuleGuid\r
+  gEfiCertTypeRsa2048Sha256Guid\r
+  gEfiCertPkcs7Guid\r
+  gEfiSystemResourceTableGuid\r
+\r
+[Protocols]\r
+  gEfiLoadedImageProtocolGuid\r
+  gEfiSimpleFileSystemProtocolGuid\r
+  gEfiGraphicsOutputProtocolGuid\r
+  gEfiFirmwareManagementProtocolGuid\r
+  gEfiShellParametersProtocolGuid\r
+\r
+[LibraryClasses]\r
+  BaseLib\r
+  UefiApplicationEntryPoint\r
+  DebugLib\r
+  MemoryAllocationLib\r
+  UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
+  UefiLib\r
+  PrintLib\r
+\r
+[UserExtensions.TianoCore."ExtraFiles"]\r
+  CapsuleAppExtra.uni\r
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
new file mode 100644 (file)
index 0000000..54d6e12
--- /dev/null
@@ -0,0 +1,22 @@
+// /** @file\r
+// A shell application that triggers capsule update process.\r
+//\r
+// This application can trigger capsule update process. It can also\r
+// generate capsule image, or dump capsule variable information.\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
+// 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 "A shell application that triggers capsule update process."\r
+\r
+#string STR_MODULE_DESCRIPTION          #language en-US "This application can trigger capsule update process. It can also generate capsule image, or dump capsule variable information."\r
+\r
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni b/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
new file mode 100644 (file)
index 0000000..b5a8840
--- /dev/null
@@ -0,0 +1,19 @@
+// /** @file\r
+// CapsuleApp Localized Strings and Content\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
+// 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
+#string STR_PROPERTIES_MODULE_NAME\r
+#language en-US\r
+"Capsule Application"\r
+\r
+\r
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
new file mode 100644 (file)
index 0000000..9291ba3
--- /dev/null
@@ -0,0 +1,738 @@
+/** @file\r
+  Dump Capsule image information.\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/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
+\r
+/**\r
+  Read a file.\r
+\r
+  @param[in] FileName        The file to be read.\r
+  @param[in] BufferSize      The file buffer size\r
+  @param[in] Buffer          The file buffer\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
+\r
+/**\r
+  Dump UX capsule information.\r
+\r
+  @param[in] CapsuleHeader      The UX capsule header\r
+**/\r
+VOID\r
+DumpUxCapsule (\r
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader\r
+  )\r
+{\r
+  EFI_DISPLAY_CAPSULE                           *DisplayCapsule;\r
+  DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader;\r
+  Print(L"[UxCapusule]\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
+  Print(L"  Flags            - 0x%x\n", DisplayCapsule->CapsuleHeader.Flags);\r
+  Print(L"  CapsuleImageSize - 0x%x\n", DisplayCapsule->CapsuleHeader.CapsuleImageSize);\r
+  Print(L"ImagePayload:\n");\r
+  Print(L"  Version          - 0x%x\n", DisplayCapsule->ImagePayload.Version);\r
+  Print(L"  Checksum         - 0x%x\n", DisplayCapsule->ImagePayload.Checksum);\r
+  Print(L"  ImageType        - 0x%x\n", DisplayCapsule->ImagePayload.ImageType);\r
+  Print(L"  Mode             - 0x%x\n", DisplayCapsule->ImagePayload.Mode);\r
+  Print(L"  OffsetX          - 0x%x\n", DisplayCapsule->ImagePayload.OffsetX);\r
+  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
+\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
+  UINT64                                        *ItemOffsetList;\r
+  UINTN                                         Index;\r
+  UINTN                                         Count;\r
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *FmpImageHeader;\r
+\r
+  Print(L"[FmpCapusule]\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
+\r
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
+  Print(L"FmpHeader:\n");\r
+  Print(L"  Version             - 0x%x\n", FmpCapsuleHeader->Version);\r
+  Print(L"  EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount);\r
+  Print(L"  PayloadItemCount    - 0x%x\n", FmpCapsuleHeader->PayloadItemCount);\r
+  Count = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r
+  for (Index = 0; Index < Count; Index++) {\r
+    Print(L"  Offset[%d]           - 0x%x\n", Index, ItemOffsetList[Index]);\r
+  }\r
+\r
+  for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) {\r
+    Print(L"FmpPayload[%d] ImageHeader:\n", Index);\r
+    FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r
+    Print(L"  Version                - 0x%x\n", FmpImageHeader->Version);\r
+    Print(L"  UpdateImageTypeId      - %g\n", &FmpImageHeader->UpdateImageTypeId);\r
+    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
+      Print(L"  UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance);\r
+    }\r
+  }\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
+\r
+  //\r
+  // Check ESRT\r
+  //\r
+  EsrtGuidFound = FALSE;\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->HeaderSize - (UINTN)NestedCapsuleHeader;\r
+  if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
+    return FALSE;\r
+  }\r
+  if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+    return FALSE;\r
+  }\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+  Dump capsule information\r
+\r
+  @param[in] CapsuleName  The name of the capsule image.\r
+\r
+  @retval EFI_SUCCESS            The capsule information is dumped.\r
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DumpCapsule (\r
+  IN CHAR16                                        *CapsuleName\r
+  )\r
+{\r
+  VOID                                          *Buffer;\r
+  UINTN                                         FileSize;\r
+  EFI_CAPSULE_HEADER                            *CapsuleHeader;\r
+  EFI_STATUS                                    Status;\r
+\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
+\r
+  CapsuleHeader = Buffer;\r
+  if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
+    DumpUxCapsule(CapsuleHeader);\r
+    Status = EFI_SUCCESS;\r
+    goto Done;\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
+Done:\r
+  FreePool(Buffer);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Dump capsule status variable.\r
+\r
+  @retval EFI_SUCCESS            The capsule status variable is dumped.\r
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.\r
+**/\r
+EFI_STATUS\r
+DmpCapsuleStatusVariable (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                          Status;\r
+  UINT32                              Index;\r
+  CHAR16                              CapsuleVarName[20];\r
+  CHAR16                              *TempVarName;\r
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResult;\r
+  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultFmp;\r
+  UINTN                               CapsuleFileNameSize;\r
+  CHAR16                              CapsuleIndexData[12];\r
+  CHAR16                              *CapsuleIndex;\r
+\r
+  Status = GetVariable2(\r
+             L"CapsuleMax",\r
+             &gEfiCapsuleReportGuid,\r
+             (VOID **)&CapsuleIndex,\r
+             NULL\r
+             );\r
+  if (!EFI_ERROR(Status)) {\r
+    CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));\r
+    CapsuleIndexData[11] = 0;\r
+    Print(L"CapsuleMax - %s\n", CapsuleIndexData);\r
+    FreePool(CapsuleIndex);\r
+  }\r
+  Status = GetVariable2(\r
+             L"CapsuleLast",\r
+             &gEfiCapsuleReportGuid,\r
+             (VOID **)&CapsuleIndex,\r
+             NULL\r
+             );\r
+  if (!EFI_ERROR(Status)) {\r
+    CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));\r
+    CapsuleIndexData[11] = 0;\r
+    Print(L"CapsuleLast - %s\n", CapsuleIndexData);\r
+    FreePool(CapsuleIndex);\r
+  }\r
+\r
+\r
+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");\r
+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+  Index = 0;\r
+\r
+  while (TRUE) {\r
+    UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);\r
+\r
+    Status = GetVariable2 (\r
+               CapsuleVarName,\r
+               &gEfiCapsuleReportGuid,\r
+               (VOID **) &CapsuleResult,\r
+               NULL\r
+               );\r
+    if (Status == EFI_NOT_FOUND) {\r
+      break;\r
+    } else if (EFI_ERROR(Status)) {\r
+      continue;\r
+    }\r
+    ASSERT (CapsuleResult != NULL);\r
+\r
+    //\r
+    // display capsule process status\r
+    //\r
+    if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {\r
+      Print (L"CapsuleName: %s\n", CapsuleVarName);\r
+      Print (L"  Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid);\r
+      Print (L"  Capsule ProcessedTime: %t\n", &CapsuleResult->CapsuleProcessed);\r
+      Print (L"  Capsule Status: %r\n", CapsuleResult->CapsuleStatus);\r
+    }\r
+\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
+        Print(L"  Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version);\r
+        Print(L"  Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->PayloadIndex);\r
+        Print(L"  Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFmp->UpdateImageIndex);\r
+        Print(L"  Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFmp->UpdateImageTypeId);\r
+        if (CapsuleResult->VariableTotalSize > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {\r
+          Print(L"  Capsule FMP CapsuleFileName: %s\n", (CapsuleResultFmp + 1));\r
+          CapsuleFileNameSize = StrSize((CHAR16 *)(CapsuleResultFmp + 1));\r
+          if (CapsuleResult->VariableTotalSize > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapsuleFileNameSize) {\r
+            Print(L"  Capsule FMP CapsuleTarget: %s\n", (UINT8 *)(CapsuleResultFmp + 1) + CapsuleFileNameSize);\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    FreePool(CapsuleResult);\r
+\r
+    Index++;\r
+    if (Index > 0xFFFF) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+CHAR8 *mFwTypeString[] = {\r
+  "Unknown",\r
+  "SystemFirmware",\r
+  "DeviceFirmware",\r
+  "UefiDriver",\r
+};\r
+\r
+CHAR8 *mLastAttemptStatusString[] = {\r
+  "Success",\r
+  "Error: Unsuccessful",\r
+  "Error: Insufficient Resources",\r
+  "Error: Incorrect Version",\r
+  "Error: Invalid Format",\r
+  "Error: Auth Error",\r
+  "Error: Power Event AC",\r
+  "Error: Power Event Battery",\r
+};\r
+\r
+/**\r
+  Convert FwType to a string.\r
+\r
+  @param[in] FwType  FwType in ESRT\r
+\r
+  @return a string for FwType.\r
+**/\r
+CHAR8 *\r
+FwTypeToString (\r
+  IN UINT32  FwType\r
+  )\r
+{\r
+  if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) {\r
+    return mFwTypeString[FwType];\r
+  } else {\r
+    return "Invalid";\r
+  }\r
+}\r
+\r
+/**\r
+  Convert LastAttemptStatus to a string.\r
+\r
+  @param[in] LastAttemptStatus  LastAttemptStatus in FMP or ESRT\r
+\r
+  @return a string for LastAttemptStatus.\r
+**/\r
+CHAR8 *\r
+LastAttemptStatusToString (\r
+  IN UINT32  LastAttemptStatus\r
+  )\r
+{\r
+  if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / sizeof(mLastAttemptStatusString[0])) {\r
+    return mLastAttemptStatusString[LastAttemptStatus];\r
+  } else {\r
+    return "Error: Unknown";\r
+  }\r
+}\r
+\r
+/**\r
+  Dump ESRT entry.\r
+\r
+  @param[in] EsrtEntry  ESRT entry\r
+**/\r
+VOID\r
+DumpEsrtEntry (\r
+  IN EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry\r
+  )\r
+{\r
+  Print(L"  FwClass                  - %g\n", &EsrtEntry->FwClass);\r
+  Print(L"  FwType                   - 0x%x (%a)\n", EsrtEntry->FwType, FwTypeToString(EsrtEntry->FwType));\r
+  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
+\r
+/**\r
+  Dump ESRT table.\r
+\r
+  @param[in] Esrt  ESRT table\r
+**/\r
+VOID\r
+DumpEsrt (\r
+  IN EFI_SYSTEM_RESOURCE_TABLE  *Esrt\r
+  )\r
+{\r
+  UINTN                      Index;\r
+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;\r
+\r
+  if (Esrt == NULL) {\r
+    return ;\r
+  }\r
+\r
+  Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n");\r
+  Print(L"FwResourceCount    - 0x%x\n", Esrt->FwResourceCount);\r
+  Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax);\r
+  Print(L"FwResourceVersion  - 0x%lx\n", Esrt->FwResourceVersion);\r
+\r
+  EsrtEntry = (VOID *)(Esrt + 1);\r
+  for (Index = 0; Index < Esrt->FwResourceCount; Index++) {\r
+    Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index);\r
+    DumpEsrtEntry(EsrtEntry);\r
+    EsrtEntry++;\r
+  }\r
+}\r
+\r
+/**\r
+  Dump ESRT info.\r
+**/\r
+VOID\r
+DumpEsrtData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                 Status;\r
+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;\r
+\r
+  Print(L"##############\n");\r
+  Print(L"# ESRT TABLE #\n");\r
+  Print(L"##############\n");\r
+\r
+  Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"ESRT - %r\n", Status);\r
+    return;\r
+  }\r
+  DumpEsrt(Esrt);\r
+  Print(L"\n");\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
+  Print(L"  DescriptorVersion  - 0x%x\n", DescriptorVersion);\r
+  Print(L"  DescriptorCount    - 0x%x\n", DescriptorCount);\r
+  Print(L"  DescriptorSize     - 0x%x\n", DescriptorSize);\r
+  Print(L"  PackageVersion     - 0x%x\n", PackageVersion);\r
+  Print(L"  PackageVersionName - \"%s\"\n", PackageVersionName);\r
+  CurrentImageInfo = ImageInfo;\r
+  for (Index = 0; Index < DescriptorCount; Index++) {\r
+    Print(L"  ImageDescriptor (%d)\n", Index);\r
+    Print(L"    ImageIndex                  - 0x%x\n", CurrentImageInfo->ImageIndex);\r
+    Print(L"    ImageTypeId                 - %g\n", &CurrentImageInfo->ImageTypeId);\r
+    Print(L"    ImageId                     - 0x%lx\n", CurrentImageInfo->ImageId);\r
+    Print(L"    ImageIdName                 - \"%s\"\n", CurrentImageInfo->ImageIdName);\r
+    Print(L"    Version                     - 0x%x\n", CurrentImageInfo->Version);\r
+    Print(L"    VersionName                 - \"%s\"\n", CurrentImageInfo->VersionName);\r
+    Print(L"    Size                        - 0x%x\n", CurrentImageInfo->Size);\r
+    Print(L"    AttributesSupported         - 0x%lx\n", CurrentImageInfo->AttributesSupported);\r
+    Print(L"      IMAGE_UPDATABLE           - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+    Print(L"      RESET_REQUIRED            - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+    Print(L"      AUTHENTICATION_REQUIRED   - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+    Print(L"      IN_USE                    - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE);\r
+    Print(L"      UEFI_IMAGE                - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE);\r
+    Print(L"    AttributesSetting           - 0x%lx\n", CurrentImageInfo->AttributesSetting);\r
+    Print(L"      IMAGE_UPDATABLE           - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+    Print(L"      RESET_REQUIRED            - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+    Print(L"      AUTHENTICATION_REQUIRED   - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+    Print(L"      IN_USE                    - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE);\r
+    Print(L"      UEFI_IMAGE                - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE);\r
+    Print(L"    Compatibilities             - 0x%lx\n", CurrentImageInfo->Compatibilities);\r
+    Print(L"      COMPATIB_CHECK_SUPPORTED  - 0x%lx\n", CurrentImageInfo->Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED);\r
+    if (DescriptorVersion > 1) {\r
+      Print(L"    LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion);\r
+      if (DescriptorVersion > 2) {\r
+        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
+      }\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 FMP package information.\r
+\r
+  @param[in] PackageVersion             The version of package.\r
+  @param[in] PackageVersionName         The version name of package.\r
+  @param[in] PackageVersionNameMaxLen   The maximum length of PackageVersionName.\r
+  @param[in] AttributesSupported        Package attributes that are supported by this device.\r
+  @param[in] AttributesSetting          Package attributes.\r
+**/\r
+VOID\r
+DumpFmpPackageInfo (\r
+  IN UINT32                           PackageVersion,\r
+  IN CHAR16                           *PackageVersionName,\r
+  IN UINT32                           PackageVersionNameMaxLen,\r
+  IN UINT64                           AttributesSupported,\r
+  IN UINT64                           AttributesSetting\r
+  )\r
+{\r
+  Print(L"  PackageVersion              - 0x%x\n", PackageVersion);\r
+  Print(L"  PackageVersionName          - \"%s\"\n", PackageVersionName);\r
+  Print(L"  PackageVersionNameMaxLen    - 0x%x\n", PackageVersionNameMaxLen);\r
+  Print(L"  AttributesSupported         - 0x%lx\n", AttributesSupported);\r
+  Print(L"    IMAGE_UPDATABLE           - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+  Print(L"    RESET_REQUIRED            - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+  Print(L"    AUTHENTICATION_REQUIRED   - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+  Print(L"  AttributesSetting           - 0x%lx\n", AttributesSetting);\r
+  Print(L"    IMAGE_UPDATABLE           - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);\r
+  Print(L"    RESET_REQUIRED            - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);\r
+  Print(L"    AUTHENTICATION_REQUIRED   - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);\r
+}\r
+\r
+/**\r
+  Dump FMP protocol info.\r
+**/\r
+VOID\r
+DumpFmpData (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;\r
+  EFI_HANDLE                                    *HandleBuffer;\r
+  UINTN                                         NumberOfHandles;\r
+  UINTN                                         Index;\r
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;\r
+  UINTN                                         ImageInfoSize;\r
+  UINT32                                        FmpImageInfoDescriptorVer;\r
+  UINT8                                         FmpImageInfoCount;\r
+  UINTN                                         DescriptorSize;\r
+  UINT32                                        PackageVersion;\r
+  CHAR16                                        *PackageVersionName;\r
+  UINT32                                        PackageVersionNameMaxLen;\r
+  UINT64                                        AttributesSupported;\r
+  UINT64                                        AttributesSetting;\r
+\r
+  Print(L"############\n");\r
+  Print(L"# FMP DATA #\n");\r
+  Print(L"############\n");\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  NULL,\r
+                  &NumberOfHandles,\r
+                  &HandleBuffer\r
+                  );\r
+  if (EFI_ERROR(Status)) {\r
+    Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);\r
+    return;\r
+  }\r
+\r
+  for (Index = 0; Index < NumberOfHandles; Index++) {\r
+    Status = gBS->HandleProtocol(\r
+                    HandleBuffer[Index],\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
+      Status = 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
+      Print(L"FMP (%d) ImageInfo - %r\n", Index, Status);\r
+      FreePool(FmpImageInfoBuf);\r
+      continue;\r
+    }\r
+\r
+    Print(L"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
+    FreePool(FmpImageInfoBuf);\r
+\r
+    //\r
+    // Get package info\r
+    //\r
+    PackageVersionName = NULL;\r
+    Status = Fmp->GetPackageInfo (\r
+                    Fmp,\r
+                    &PackageVersion,              // PackageVersion\r
+                    &PackageVersionName,          // PackageVersionName\r
+                    &PackageVersionNameMaxLen,    // PackageVersionNameMaxLen\r
+                    &AttributesSupported,         // AttributesSupported\r
+                    &AttributesSetting            // AttributesSetting\r
+                    );\r
+    if (EFI_ERROR(Status)) {\r
+      Print(L"FMP (%d) PackageInfo - %r\n", Index, Status);\r
+    } else {\r
+      Print(L"FMP (%d) ImageInfo:\n", Index);\r
+      DumpFmpPackageInfo(\r
+        PackageVersion,              // PackageVersion\r
+        PackageVersionName,          // PackageVersionName\r
+        PackageVersionNameMaxLen,    // PackageVersionNameMaxLen\r
+        AttributesSupported,         // AttributesSupported\r
+        AttributesSetting            // AttributesSetting\r
+        );\r
+\r
+      if (PackageVersionName != NULL) {\r
+        FreePool(PackageVersionName);\r
+      }\r
+    }\r
+  }\r
+  Print(L"\n");\r
+\r
+EXIT:\r
+  FreePool(HandleBuffer);\r
+}\r