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.t...@intel.com>
Cc: Star Zeng <star.z...@intel.com>
Cc: Michael D Kinney <michael.d.kin...@intel.com>
Cc: Liming Gao <liming....@intel.com>
Cc: Chao Zhang <chao.b.zh...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen....@intel.com>
---
 MdeModulePkg/Application/CapsuleApp/AppSupport.c        |  480 +++++++++
 MdeModulePkg/Application/CapsuleApp/CapsuleApp.c        | 1047 
++++++++++++++++++++
 MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf      |   71 ++
 MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni      |   22 +
 MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni |   19 +
 MdeModulePkg/Application/CapsuleApp/CapsuleDump.c       |  840 ++++++++++++++++
 6 files changed, 2479 insertions(+)

diff --git a/MdeModulePkg/Application/CapsuleApp/AppSupport.c 
b/MdeModulePkg/Application/CapsuleApp/AppSupport.c
new file mode 100644
index 0000000..365067d
--- /dev/null
+++ b/MdeModulePkg/Application/CapsuleApp/AppSupport.c
@@ -0,0 +1,480 @@
+/** @file
+  A shell application that triggers capsule update process.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Guid/FileInfo.h>
+#include <Guid/Gpt.h>
+
+#define MAX_ARG_NUM     11
+
+UINTN  Argc = 0;
+CHAR16 *Argv[MAX_ARG_NUM];
+CHAR16 *ArgBuffer;
+
+/**
+
+  This function parse application ARG.
+
+  @return Status
+**/
+EFI_STATUS
+GetArg (
+  VOID
+  )
+{
+  UINT8                         *Data;
+  UINTN                         DataSize;
+  CHAR16                        *Index;
+  CHAR16                        *End;
+  CHAR16                        *DIndex;
+  EFI_STATUS                    Status;
+  EFI_LOADED_IMAGE_PROTOCOL     *LoadedImage;
+
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID**)&LoadedImage
+                  );
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  Data = LoadedImage->LoadOptions;
+  DataSize = LoadedImage->LoadOptionsSize;
+
+  End = (CHAR16*)(UINTN)(Data + DataSize);
+  Status = gBS->AllocatePool (EfiBootServicesData, DataSize, (VOID 
**)&ArgBuffer);
+  ASSERT_EFI_ERROR (Status);
+  DIndex = ArgBuffer;
+  Argv[Argc++] = ArgBuffer;
+  for (Index = (CHAR16*)Data; Index < End; ) {
+    if (*Index == L' ') {
+      *DIndex = L'\0';
+      if (Argc >= MAX_ARG_NUM) {
+        return EFI_UNSUPPORTED;
+      }
+      Argv[Argc++] = (++ DIndex);
+      while(*Index == L' ') {
+        Index ++;
+      }
+    }
+    (*(DIndex ++)) = (*(Index ++));
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  Clear APP ARG.
+**/
+VOID
+CleanArg (
+  VOID
+  )
+{
+  FreePool (Argv[0]);
+}
+
+/**
+  Return File System Volume containing this shell application.
+
+  @return File System Volume containing this shell application.
+**/
+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *
+GetMyVol (
+  VOID
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
+
+  Status = gBS->HandleProtocol (
+                  gImageHandle,
+                  &gEfiLoadedImageProtocolGuid,
+                  (VOID **)&LoadedImage
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->HandleProtocol (
+                  LoadedImage->DeviceHandle,
+                  &gEfiSimpleFileSystemProtocolGuid,
+                  (VOID **)&Vol
+                  );
+  if (!EFI_ERROR (Status)) {
+    return Vol;
+  }
+
+  return NULL;
+}
+
+/**
+  Read a file from this volume.
+
+  @param Vol             File System Volume
+  @param FileName        The file to be read.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+
+  @retval EFI_SUCCESS    Read file successfully
+  @retval EFI_NOT_FOUND  File not found
+**/
+EFI_STATUS
+ReadFileFromVol (
+  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol,
+  IN  CHAR16                            *FileName,
+  OUT UINTN                             *BufferSize,
+  OUT VOID                              **Buffer
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_FILE_HANDLE                   RootDir;
+  EFI_FILE_HANDLE                   Handle;
+  UINTN                             FileInfoSize;
+  EFI_FILE_INFO                     *FileInfo;
+  UINTN                             TempBufferSize;
+  VOID                              *TempBuffer;
+
+  //
+  // Open the root directory
+  //
+  Status = Vol->OpenVolume (Vol, &RootDir);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Open the file
+  //
+  Status = RootDir->Open (
+                      RootDir,
+                      &Handle,
+                      FileName,
+                      EFI_FILE_MODE_READ,
+                      0
+                      );
+  if (EFI_ERROR (Status)) {
+    RootDir->Close (RootDir);
+    return Status;
+  }
+
+  RootDir->Close (RootDir);
+
+  //
+  // Get the file information
+  //
+  FileInfoSize = sizeof(EFI_FILE_INFO) + 1024;
+
+  FileInfo = AllocateZeroPool (FileInfoSize);
+  if (FileInfo == NULL) {
+    Handle->Close (Handle);
+    return Status;
+  }
+
+  Status = Handle->GetInfo (
+                     Handle,
+                     &gEfiFileInfoGuid,
+                     &FileInfoSize,
+                     FileInfo
+                     );
+  if (EFI_ERROR (Status)) {
+    Handle->Close (Handle);
+    gBS->FreePool (FileInfo);
+    return Status;
+  }
+
+  //
+  // Allocate buffer for the file data. The last CHAR16 is for L'\0'
+  //
+  TempBufferSize = (UINTN) FileInfo->FileSize + sizeof(CHAR16);
+  TempBuffer = AllocateZeroPool (TempBufferSize);
+  if (TempBuffer == NULL) {
+    Handle->Close (Handle);
+    gBS->FreePool (FileInfo);
+    return Status;
+  }
+
+  gBS->FreePool (FileInfo);
+
+  //
+  // Read the file data to the buffer
+  //
+  Status = Handle->Read (
+                     Handle,
+                     &TempBufferSize,
+                     TempBuffer
+                     );
+  if (EFI_ERROR (Status)) {
+    Handle->Close (Handle);
+    gBS->FreePool (TempBuffer);
+    return Status;
+  }
+
+  Handle->Close (Handle);
+
+  *BufferSize = TempBufferSize;
+  *Buffer     = TempBuffer;
+  return EFI_SUCCESS;
+}
+
+/**
+  Read a file.
+  If ScanFs is FLASE, it will use this Vol as default Fs.
+  If ScanFs is TRUE, it will scan all FS and check the file.
+    If there is only one file match the name, it will be read.
+    If there is more than one file match the name, it will return Error.
+
+  @param ThisVol         File System Volume
+  @param FileName        The file to be read.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+  @param ScanFs          Need Scan all FS
+
+  @retval EFI_SUCCESS    Read file successfully
+  @retval EFI_NOT_FOUND  File not found
+  @retval EFI_NO_MAPPING There is duplicated files found
+**/
+EFI_STATUS
+ReadFileToBufferEx (
+  IN OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   **ThisVol,
+  IN  CHAR16                               *FileName,
+  OUT UINTN                                *BufferSize,
+  OUT VOID                                 **Buffer,
+  IN  BOOLEAN                              ScanFs
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
+  UINTN                             TempBufferSize;
+  VOID                              *TempBuffer;
+  UINTN                             NoHandles;
+  EFI_HANDLE                        *HandleBuffer;
+  UINTN                             Index;
+
+  //
+  // Check parameters
+  //
+  if ((FileName == NULL) || (Buffer == NULL) || (ThisVol == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // not scan fs
+  //
+  if (!ScanFs) {
+    if (*ThisVol == NULL) {
+      *ThisVol = GetMyVol ();
+      if (*ThisVol == NULL) {
+        return EFI_INVALID_PARAMETER;
+      }
+    }
+    //
+    // Read file directly from Vol
+    //
+    return ReadFileFromVol (*ThisVol, FileName, BufferSize, Buffer);
+  }
+
+  //
+  // need scan fs
+  //
+
+  //
+  // Get all Vol handle
+  //
+  Status = gBS->LocateHandleBuffer (
+                   ByProtocol,
+                   &gEfiSimpleFileSystemProtocolGuid,
+                   NULL,
+                   &NoHandles,
+                   &HandleBuffer
+                   );
+  if (EFI_ERROR (Status) && (NoHandles == 0)) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Walk through each Vol
+  //
+  *ThisVol = NULL;
+  *BufferSize = 0;
+  *Buffer     = NULL;
+  for (Index = 0; Index < NoHandles; Index++) {
+    Status = gBS->HandleProtocol (
+                    HandleBuffer[Index],
+                    &gEfiSimpleFileSystemProtocolGuid,
+                    (VOID **)&Vol
+                    );
+    if (EFI_ERROR(Status)) {
+      continue;
+    }
+
+    Status = ReadFileFromVol (Vol, FileName, &TempBufferSize, &TempBuffer);
+    if (!EFI_ERROR (Status)) {
+      //
+      // Read file OK, check duplication
+      //
+      if (*ThisVol != NULL) {
+        //
+        // Find the duplicated file
+        //
+        gBS->FreePool (TempBuffer);
+        gBS->FreePool (*Buffer);
+        Print (L"Duplicated FileName found!\n");
+        return EFI_NO_MAPPING;
+      } else {
+        //
+        // Record value
+        //
+        *ThisVol = Vol;
+        *BufferSize = TempBufferSize;
+        *Buffer     = TempBuffer;
+      }
+    }
+  }
+
+  //
+  // Scan Fs done
+  //
+  if (*ThisVol == NULL) {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Done
+  //
+  return EFI_SUCCESS;
+}
+
+/**
+  Read a file.
+
+  @param FileName        The file to be read.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+
+  @retval EFI_SUCCESS    Read file successfully
+  @retval EFI_NOT_FOUND  File not found
+**/
+EFI_STATUS
+ReadFileToBuffer (
+  IN  CHAR16                               *FileName,
+  OUT UINTN                                *BufferSize,
+  OUT VOID                                 **Buffer
+  )
+{
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
+  Vol = NULL;
+  return ReadFileToBufferEx(&Vol, FileName, BufferSize, Buffer, FALSE);
+}
+
+/**
+  Write a file.
+
+  @param FileName        The file to be written.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+
+  @retval EFI_SUCCESS    Write file successfully
+**/
+EFI_STATUS
+WriteFileFromBuffer(
+  IN  CHAR16                               *FileName,
+  IN  UINTN                                BufferSize,
+  IN  VOID                                 *Buffer
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_FILE_HANDLE                   RootDir;
+  EFI_FILE_HANDLE                   Handle;
+  UINTN                             TempBufferSize;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL   *Vol;
+
+  Vol = GetMyVol();
+
+  //
+  // Open the root directory
+  //
+  Status = Vol->OpenVolume (Vol, &RootDir);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Open the file
+  //
+  Status = RootDir->Open (
+                      RootDir,
+                      &Handle,
+                      FileName,
+                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| 
EFI_FILE_MODE_CREATE,
+                      0
+                      );
+  if (EFI_ERROR (Status)) {
+    RootDir->Close (RootDir);
+    return Status;
+  }
+
+  //
+  // Delete file
+  //
+  Status = Handle->Delete(Handle);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // Open the file again
+  //
+  Status = RootDir->Open (
+                      RootDir,
+                      &Handle,
+                      FileName,
+                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| 
EFI_FILE_MODE_CREATE,
+                      0
+                      );
+  if (EFI_ERROR (Status)) {
+    RootDir->Close (RootDir);
+    return Status;
+  }
+
+  RootDir->Close (RootDir);
+
+  //
+  // Write the file data from the buffer
+  //
+  TempBufferSize = BufferSize;
+  Status = Handle->Write (
+                     Handle,
+                     &TempBufferSize,
+                     Buffer
+                     );
+  if (EFI_ERROR (Status)) {
+    Handle->Close (Handle);
+    return Status;
+  }
+
+  Handle->Close (Handle);
+
+  return EFI_SUCCESS;
+}
+
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c 
b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
new file mode 100644
index 0000000..0a28557
--- /dev/null
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
@@ -0,0 +1,1047 @@
+/** @file
+  A shell application that triggers capsule update process.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Guid/FileInfo.h>
+#include <Guid/Gpt.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/FmpCapsule.h>
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+#define CAPSULE_HEADER_SIZE  0x20
+
+#define NESTED_CAPSULE_HEADER_SIZE  SIZE_4KB
+#define SYSTEM_FIRMWARE_FLAG 0x50000
+#define DEVICE_FIRMWARE_FLAG 0x78010
+
+#define EFI_CAPSULE_FROM_FILE_DIR                           
L"\\EFI\\UpdateCapsule\\"
+#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED  0x0000000000000004
+
+#define MAJOR_VERSION   1
+#define MINOR_VERSION   0
+
+#define MAX_ARG_NUM     11
+#define MAX_CAPSULE_NUM (MAX_ARG_NUM - 1)
+
+extern UINTN  Argc;
+extern CHAR16 *Argv[];
+
+//
+// Define how many block descriptors we want to test with.
+//
+UINTN  NumberOfDescriptors = 1;
+UINTN  CapsuleFirstIndex;
+UINTN  CapsuleLastIndex;
+
+/**
+  Dump capsule information
+
+  @retval EFI_SUCCESS            The capsule information is dumped.
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.
+**/
+EFI_STATUS
+DumpCapsule(
+  VOID
+  );
+
+/**
+  Dump capsule status variable.
+
+  @retval EFI_SUCCESS            The capsule status variable is dumped.
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.
+**/
+EFI_STATUS
+DmpCapsuleStatusVariable(
+  VOID
+  );
+
+/**
+  Dump FMP protocol info.
+**/
+VOID
+DumpFmpData(
+  VOID
+  );
+
+/**
+  Dump ESRT info.
+**/
+VOID
+DumpEsrtData(
+  VOID
+  );
+
+/**
+  Read a file.
+
+  @param FileName        The file to be read.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+
+  @retval EFI_SUCCESS    Read file successfully
+  @retval EFI_NOT_FOUND  File not found
+**/
+EFI_STATUS
+ReadFileToBuffer(
+  IN  CHAR16                               *FileName,
+  OUT UINTN                                *BufferSize,
+  OUT VOID                                 **Buffer
+  );
+
+/**
+  Write a file.
+
+  @param FileName        The file to be written.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+
+  @retval EFI_SUCCESS    Write file successfully
+**/
+EFI_STATUS
+WriteFileFromBuffer(
+  IN  CHAR16                               *FileName,
+  IN  UINTN                                BufferSize,
+  IN  VOID                                 *Buffer
+  );
+
+/**
+
+  This function parse application ARG.
+
+  @return Status
+**/
+EFI_STATUS
+GetArg (
+  VOID
+  );
+
+/**
+  Clear APP ARG.
+**/
+VOID
+CleanArg (
+  VOID
+  );
+
+/**
+  Create UX capsule.
+
+  @retval EFI_SUCCESS            The capsule header is appended.
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to create UX capsule.
+**/
+EFI_STATUS
+CreateBmpFmp(
+  VOID
+  )
+{
+  CHAR16                                        *OutputCapsuleName;
+  VOID                                          *BmpBuffer;
+  UINTN                                         FileSize;
+  CHAR16                                        *BmpName;
+  UINT8                                         *FullCapsuleBuffer;
+  UINTN                                         FullCapsuleBufferSize;
+  EFI_DISPLAY_CAPSULE                           *DisplayCapsule;
+  EFI_STATUS                                    Status;
+  EFI_GRAPHICS_OUTPUT_PROTOCOL                  *Gop;
+
+  Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID 
**)&Gop);
+  if (EFI_ERROR(Status)) {
+    Print(L"CapsuleApp: NO GOP is found.\n");
+    return EFI_UNSUPPORTED;
+  }
+  Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);
+  Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);
+  Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);
+  // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
+  // VerticalResolution   >= BMP_IMAGE_HEADER.PixelHeight
+
+  if (Argc != 5) {
+    Print(L"CapsuleApp: Invalid Parameter.\n");
+    return EFI_UNSUPPORTED;
+  }
+
+  if (StrCmp(Argv[3], L"-O") != 0) {
+    Print(L"CapsuleApp: NO output capsule name.\n");
+    return EFI_UNSUPPORTED;
+  }
+  OutputCapsuleName = Argv[4];
+
+  BmpBuffer = NULL;
+  FileSize = 0;
+  FullCapsuleBuffer = NULL;
+
+  BmpName = Argv[2];
+  Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);
+  if (EFI_ERROR(Status)) {
+    Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
+    goto Done;
+  }
+
+  FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;
+  FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
+  if (FullCapsuleBuffer == NULL) {
+    Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", 
FullCapsuleBufferSize);
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;
+  CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);
+  DisplayCapsule->CapsuleHeader.HeaderSize = 
sizeof(DisplayCapsule->CapsuleHeader);
+  DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
+  DisplayCapsule->CapsuleHeader.CapsuleImageSize = 
(UINT32)FullCapsuleBufferSize;
+
+  DisplayCapsule->ImagePayload.Version = 1;
+  DisplayCapsule->ImagePayload.Checksum = 0;
+  DisplayCapsule->ImagePayload.ImageType = 0; // BMP
+  DisplayCapsule->ImagePayload.Reserved = 0;
+  DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;
+  DisplayCapsule->ImagePayload.OffsetX = 0;
+  DisplayCapsule->ImagePayload.OffsetY = 0;
+
+  CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);
+
+  DisplayCapsule->ImagePayload.Checksum = 
CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);
+
+  Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, 
FullCapsuleBuffer);
+  Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
+
+Done:
+  if (BmpBuffer != NULL) {
+    FreePool(BmpBuffer);
+  }
+
+  if (FullCapsuleBuffer != NULL) {
+    FreePool(FullCapsuleBuffer);
+  }
+
+  return Status;
+}
+
+/**
+  Get ImageTypeId in the FMP capsule header.
+
+  @param CapsuleHeader  The FMP capsule image header.
+
+  @return ImageTypeId
+**/
+EFI_GUID *
+GetCapsuleImageTypeId(
+  IN EFI_CAPSULE_HEADER                            *CapsuleHeader
+  )
+{
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER       *FmpCapsuleHeader;
+  UINT64                                       *ItemOffsetList;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 
*)CapsuleHeader + CapsuleHeader->HeaderSize);
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+  if (FmpCapsuleHeader->PayloadItemCount == 0) {
+    return NULL;
+  }
+  ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 
*)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);
+  return &ImageHeader->UpdateImageTypeId;
+}
+
+/**
+  Get ESRT FwType according to ImageTypeId
+
+  @param  ImageTypeId   ImageTypeId of an FMP capsule.
+
+  @return ESRT FwType
+**/
+UINT32
+GetEsrtFwType(
+  IN  EFI_GUID                                      *ImageTypeId
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;
+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
+  UINTN                      Index;
+
+  //
+  // Check ESRT
+  //
+  Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID 
**)&Esrt);
+  if (!EFI_ERROR(Status)) {
+    EsrtEntry = (VOID *)(Esrt + 1);
+    for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
+      if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {
+        return EsrtEntry->FwType;
+      }
+    }
+  }
+
+  return ESRT_FW_TYPE_UNKNOWN;
+}
+
+/**
+  Append a capsule header on top of current image.
+  This function follows Windows UEFI Firmware Update Platform document.
+
+  @retval EFI_SUCCESS            The capsule header is appended.
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.
+  @retval EFI_OUT_OF_RESOURCES   No enough resource to append capsule header.
+**/
+EFI_STATUS
+CreateNestedFmp(
+  VOID
+  )
+{
+  CHAR16                                        *OutputCapsuleName;
+  VOID                                          *CapsuleBuffer;
+  UINTN                                         FileSize;
+  CHAR16                                        *CapsuleName;
+  UINT8                                         *FullCapsuleBuffer;
+  UINTN                                         FullCapsuleBufferSize;
+  EFI_CAPSULE_HEADER                            *NestedCapsuleHeader;
+  EFI_GUID                                      *ImageTypeId;
+  UINT32                                        FwType;
+  EFI_STATUS                                    Status;
+
+  if (Argc != 5) {
+    Print(L"CapsuleApp: Invalid Parameter.\n");
+    return EFI_UNSUPPORTED;
+  }
+
+  if (StrCmp(Argv[3], L"-O") != 0) {
+    Print(L"CapsuleApp: NO output capsule name.\n");
+    return EFI_UNSUPPORTED;
+  }
+  OutputCapsuleName = Argv[4];
+
+  CapsuleBuffer = NULL;
+  FileSize = 0;
+  FullCapsuleBuffer = NULL;
+
+  CapsuleName = Argv[2];
+  Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);
+  if (EFI_ERROR(Status)) {
+    Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);
+    goto Done;
+  }
+
+  ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);
+  if (ImageTypeId == NULL) {
+    Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");
+    goto Done;
+  }
+  FwType = GetEsrtFwType(ImageTypeId);
+  if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != 
ESRT_FW_TYPE_DEVICEFIRMWARE)) {
+    Print(L"CapsuleApp: Capsule FwType is invalid.\n");
+    goto Done;
+  }
+
+  FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;
+  FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
+  if (FullCapsuleBuffer == NULL) {
+    Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", 
FullCapsuleBufferSize);
+    Status = EFI_OUT_OF_RESOURCES;
+    goto Done;
+  }
+
+  NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;
+  ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);
+  CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);
+  NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;
+  NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? 
SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;
+  NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
+
+  CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, 
CapsuleBuffer, FileSize);
+
+  Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, 
FullCapsuleBuffer);
+  Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
+
+Done:
+  if (CapsuleBuffer != NULL) {
+    FreePool(CapsuleBuffer);
+  }
+
+  if (FullCapsuleBuffer != NULL) {
+    FreePool(FullCapsuleBuffer);
+  }
+
+  return Status;
+}
+
+
+/**
+  Clear capsule status variable.
+
+  @retval EFI_SUCCESS            The capsule status variable is cleared.
+**/
+EFI_STATUS
+ClearCapsuleStatusVariable(
+  VOID
+  )
+{
+  EFI_STATUS                          Status;
+  UINT32                              Index;
+  CHAR16                              CapsuleVarName[20];
+  CHAR16                              *TempVarName;
+
+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), 
L"Capsule");
+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+  Index = 0;
+
+  while (TRUE) {
+    UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
+
+    Status = gRT->SetVariable (
+                    CapsuleVarName,
+                    &gEfiCapsuleReportGuid,
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | 
EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                    0,
+                    (VOID *)NULL
+                    );
+    if (EFI_ERROR(Status)) {
+      //
+      // There is no capsule variables, quit
+      //
+      break;
+    }
+
+    Index++;
+    if (Index > 0xFFFF) {
+      break;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Get the active UEFI system partition from bootoption list.
+
+  @param[out] Fs    Simple File System protocol on the active UEFI system 
partition
+
+  @retval EFI_SUCCESS   active UEFI system partition found
+**/
+EFI_STATUS
+GetEfiSysPartition(
+  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *FsTemp;
+  UINTN                            NoHandles;
+  EFI_HANDLE                       *Handles;
+  UINTN                            Index;
+
+  Handles = NULL;
+
+  //
+  // search for EFI system partition protocol on Boot option device path
+  //
+  Status = gBS->LocateHandleBuffer(ByProtocol, &gEfiPartTypeSystemPartGuid, 
NULL, &NoHandles, &Handles);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  //
+  // Skip BootOptions within FV
+  //
+  for (Index = 0; Index < NoHandles; Index++) {
+    Status = gBS->HandleProtocol (Handles[Index], 
&gEfiSimpleFileSystemProtocolGuid, (VOID **)&FsTemp);
+    if (!EFI_ERROR (Status)){
+      *Fs = FsTemp;
+      break;
+    }
+  }
+  return Status;
+}
+
+/**
+  Copy a list of capsule images to the active UEFI system partition from 
bootoption list.
+
+  @param[in] CapsuleBuffer    An array of pointer to capsule images
+  @param[in] FileSize         An array of UINTN to capsule images size
+  @param[in] CapsuleNum       The count of capsule images
+
+  @retval EFI_SUCCESS   Capsule images are copied to the active UEFI system 
partition
+**/
+EFI_STATUS
+CopyCapsuleToActiveEfiPartition(
+  IN VOID                          **CapsuleBuffer,
+  IN UINTN                         *FileSize,
+  IN UINTN                         CapsuleNum
+  )
+{
+  EFI_STATUS                       Status;
+  CHAR16                           *CapsuleName;
+  UINTN                            Index;
+  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
+  EFI_FILE_HANDLE                  RootDir;
+  EFI_FILE_HANDLE                  CapsuleDir;
+  EFI_FILE_HANDLE                  DestHandle;
+  UINTN                            DataSize;
+  UINT64                           OsIndication;
+
+  RootDir      = NULL;
+  CapsuleDir   = NULL;
+
+  Status = GetEfiSysPartition(&Fs);
+  if (EFI_ERROR(Status)) {
+    Print (L"Can not find active UEFI System Partition\n");
+    return Status;
+  }
+
+  Status = Fs->OpenVolume(Fs, &RootDir);
+  if (EFI_ERROR(Status)) {
+    goto EXIT;
+  }
+
+  Status = RootDir->Open(
+                      RootDir,
+                      &CapsuleDir,
+                      EFI_CAPSULE_FROM_FILE_DIR,
+                      EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | 
EFI_FILE_MODE_CREATE,
+                      EFI_FILE_DIRECTORY
+                      );
+  if (EFI_ERROR(Status)) {
+    goto EXIT;
+  }
+
+  //
+  // Read the input files.
+  //
+  for (Index = 0; Index < CapsuleNum; Index++) {
+    CapsuleName = Argv[CapsuleFirstIndex + Index];
+    Status = CapsuleDir->Open(
+                           CapsuleDir,
+                           &DestHandle,
+                           CapsuleName,
+                           EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | 
EFI_FILE_MODE_CREATE,
+                           EFI_FILE_ARCHIVE
+                           );
+    if (EFI_ERROR(Status)) {
+      Print(L"CapsuleApp: %s open error - %r\n", CapsuleName, Status);
+      continue;
+    }
+
+    DataSize = FileSize[Index];
+    Status = DestHandle->Write(
+                           DestHandle,
+                           &DataSize,
+                           CapsuleBuffer[Index]
+                           );
+    DestHandle->Close(DestHandle);
+    if (EFI_ERROR(Status)) {
+      Print(L"CapsuleApp: %s write error - %r, FileSize - 0x%x\n", 
CapsuleName, Status, FileSize[Index]);
+    }
+  }
+
+  Status = gRT->GetVariable (
+                  L"OsIndications",
+                  &gEfiGlobalVariableGuid,
+                  NULL,
+                  &DataSize,
+                  (VOID *) &OsIndication
+                  );
+
+  if (EFI_ERROR(Status) || DataSize != sizeof(OsIndication)) {
+    OsIndication = 0;
+  }
+
+  //
+  // Set OsIndications Variable 
EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED bit
+  //
+  OsIndication |= EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
+  Status = gRT->SetVariable (
+                  L"OsIndications",
+                  &gEfiGlobalVariableGuid,
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS |
+                  EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                  sizeof(OsIndication),
+                  (VOID *)&OsIndication
+                  );
+
+
+EXIT:
+  if (RootDir != NULL) {
+    RootDir->Close(RootDir);
+  }
+
+  if (CapsuleDir != NULL) {
+    CapsuleDir->Close(CapsuleDir);
+  }
+
+  return Status;
+}
+
+/**
+  Build Gather list for a list of capsule images.
+
+  @param[in]  CapsuleBuffer    An array of pointer to capsule images
+  @param[in]  FileSize         An array of UINTN to capsule images size
+  @param[in]  CapsuleNum       The count of capsule images
+  @param[out] BlockDescriptors The block descriptors for the capsule images
+
+  @retval EFI_SUCCESS The block descriptors for the capsule images are 
constructed.
+**/
+EFI_STATUS
+BuildGatherList(
+  IN VOID                          **CapsuleBuffer,
+  IN UINTN                         *FileSize,
+  IN UINTN                         CapsuleNum,
+  OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors1;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors2;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorPre;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptorsHeader;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *TempBlockPtr;
+  UINT8                         *TempDataPtr;
+  UINTN                         SizeLeft;
+  UINTN                         Size;
+  INT32                         Count;
+  INT32                         Number;
+  UINTN                         Index;
+
+  TempBlockPtr           = NULL;
+  BlockDescriptors1      = NULL;
+  BlockDescriptors2      = NULL;
+  BlockDescriptorPre     = NULL;
+  BlockDescriptorsHeader = NULL;
+
+  for (Index = 0; Index < CapsuleNum; Index++) {
+    //
+    // Allocate memory for the descriptors.
+    //
+    if (NumberOfDescriptors == 1) {
+      Count = 2;
+    } else {
+      Count = (INT32)(NumberOfDescriptors + 2) / 2;
+    }
+
+    Size               = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+    BlockDescriptors1  = AllocateRuntimeZeroPool (Size);
+    if (BlockDescriptors1 == NULL) {
+      Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
+      Status = EFI_OUT_OF_RESOURCES;
+      goto ERREXIT;
+    } else {
+      Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) 
BlockDescriptors1);
+      Print (L"CapsuleApp: capsule data starts          at 0x%X with size 
0x%X\n", (UINTN) CapsuleBuffer, FileSize);
+    }
+
+    //
+    // Record descirptor header
+    //
+    if (Index == 0) {
+      BlockDescriptorsHeader = BlockDescriptors1;
+    }
+
+    if (BlockDescriptorPre != NULL) {
+      BlockDescriptorPre->Union.ContinuationPointer = (UINTN) 
BlockDescriptors1;
+      BlockDescriptorPre->Length = 0;
+    }
+
+    //
+    // Fill them in
+    //
+    TempBlockPtr  = BlockDescriptors1;
+    TempDataPtr   = CapsuleBuffer[Index];
+    SizeLeft      = FileSize[Index];
+    for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
+      //
+      // Divide remaining data in half
+      //
+      if (NumberOfDescriptors != 1) {
+        if (SizeLeft == 1) {
+          Size = 1;
+        } else {
+          Size = SizeLeft / 2;
+        }
+      } else {
+        Size = SizeLeft;
+      }
+      TempBlockPtr->Union.DataBlock    = (UINTN)TempDataPtr;
+      TempBlockPtr->Length  = Size;
+      Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", 
(UINTN) TempDataPtr, Size);
+      SizeLeft -= Size;
+      TempDataPtr += Size;
+      TempBlockPtr++;
+    }
+
+    //
+    // Allocate the second list, point the first block's last entry to point
+    // to this one, and fill this one in. Worst case is that the previous
+    // list only had one element that pointed here, so we need at least two
+    // elements -- one to point to all the data, another to terminate the list.
+    //
+    if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
+      Count = (INT32)(NumberOfDescriptors + 2) - Count;
+      if (Count == 1) {
+        Count++;
+      }
+
+      Size              = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
+      BlockDescriptors2 = AllocateRuntimeZeroPool (Size);
+      if (BlockDescriptors2 == NULL) {
+        Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
+        Status = EFI_OUT_OF_RESOURCES;
+        goto ERREXIT;
+      }
+
+      //
+      // Point the first list's last element to point to this second list.
+      //
+      TempBlockPtr->Union.ContinuationPointer   = (UINTN) BlockDescriptors2;
+
+      TempBlockPtr->Length  = 0;
+      TempBlockPtr = BlockDescriptors2;
+      for (Number = 0; Number < Count - 1; Number++) {
+        //
+        // If second-to-last one, then dump rest to this element
+        //
+        if (Number == (Count - 2)) {
+          Size = SizeLeft;
+        } else {
+          //
+          // Divide remaining data in half
+          //
+          if (SizeLeft == 1) {
+            Size = 1;
+          } else {
+            Size = SizeLeft / 2;
+          }
+        }
+
+        TempBlockPtr->Union.DataBlock    = (UINTN)TempDataPtr;
+        TempBlockPtr->Length  = Size;
+        Print (L"CapsuleApp: capsule block/size              0x%X/0x%X\n", 
(UINTN) TempDataPtr, Size);
+        SizeLeft -= Size;
+        TempDataPtr += Size;
+        TempBlockPtr++;
+        if (SizeLeft == 0) {
+          break;
+        }
+      }
+    }
+
+    BlockDescriptorPre = TempBlockPtr;
+    BlockDescriptors1  = NULL;
+  }
+
+  //
+  // Null-terminate.
+  //
+  if (TempBlockPtr != NULL) {
+    TempBlockPtr->Union.ContinuationPointer    = (UINTN)NULL;
+    TempBlockPtr->Length  = 0;
+    *BlockDescriptors = BlockDescriptorsHeader;
+  }
+
+  return EFI_SUCCESS;
+
+ERREXIT:
+  if (BlockDescriptors1 != NULL) {
+    FreePool(BlockDescriptors1);
+  }
+
+  if (BlockDescriptors2 != NULL) {
+    FreePool(BlockDescriptors2);
+  }
+
+  return Status;
+}
+
+/**
+  Clear the Gather list for a list of capsule images.
+
+  @param[in]  BlockDescriptors The block descriptors for the capsule images
+  @param[in]  CapsuleNum       The count of capsule images
+**/
+VOID
+CleanGatherList(
+  IN EFI_CAPSULE_BLOCK_DESCRIPTOR   *BlockDescriptors,
+  IN UINTN                          CapsuleNum
+  )
+{
+  EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr1;
+  EFI_CAPSULE_BLOCK_DESCRIPTOR   *TempBlockPtr2;
+  UINTN                          Index;
+
+  if (BlockDescriptors != NULL) {
+    TempBlockPtr1 = BlockDescriptors;
+    while (1){
+      TempBlockPtr = TempBlockPtr1;
+      for (Index = 0; Index < CapsuleNum; Index++) {
+        if (TempBlockPtr[Index].Length == 0) {
+          break;
+        }
+      }
+
+      if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
+        break;
+      }
+
+      TempBlockPtr2 = (VOID *) ((UINTN) 
TempBlockPtr->Union.ContinuationPointer);
+      FreePool(TempBlockPtr1);
+      TempBlockPtr1 = TempBlockPtr2;
+    }
+  }
+}
+
+/**
+  Print APP usage.
+**/
+VOID
+PrintUsage (
+  VOID
+  )
+{
+  Print(L"CapsuleApp:  usage\n");
+  Print(L"  CapsuleApp [-F] <Capsule...> [-NR]\n");
+  Print(L"  CapsuleApp -S\n");
+  Print(L"  CapsuleApp -C\n");
+  Print(L"  CapsuleApp -P\n");
+  Print(L"  CapsuleApp -E\n");
+  Print(L"  CapsuleApp -G <BMP> -O <Capsule>\n");
+  Print(L"  CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
+  Print(L"  CapsuleApp -D|-DS <Capsule>\n");
+  Print(L"Parameter:\n");
+  Print(L"  -F:  Put capsule file to disk.\n");
+  Print(L"       No -F means to put capsule file in memory.\n");
+  Print(L"  -NR: No Reset.\n");
+  Print(L"  -S:  Dump capsule status.\n");
+  Print(L"  -C:  Clear capsule status.\n");
+  Print(L"  -P:  Dump FMP protocol info.\n");
+  Print(L"  -E:  Dump ESRT table info.\n");
+  Print(L"  -G:  Input BMP file name\n");
+  Print(L"  -N:  Append Capsule Header accroding to Windows Firmware 
Update\n");
+  Print(L"  -O:  Output Capsule file name\n");
+  Print(L"  -D:  Dump Capsule\n");
+  Print(L"  -DS: Dump Capsule with System FMP format\n");
+}
+
+/**
+  Update Capsule image.
+
+  @param[in]  ImageHandle     The image handle.
+  @param[in]  SystemTable     The system table.
+
+  @retval EFI_SUCCESS            Command completed successfully.
+  @retval EFI_INVALID_PARAMETER  Command usage error.
+  @retval EFI_NOT_FOUND          The input file can't be found.
+**/
+EFI_STATUS
+EFIAPI
+UefiMain (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                    Status;
+  UINTN                         FileSize[MAX_CAPSULE_NUM];
+  VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];
+  EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;
+  EFI_CAPSULE_HEADER             *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
+  UINT64                         MaxCapsuleSize;
+  EFI_RESET_TYPE                 ResetType;
+  BOOLEAN                        NeedReset;
+  BOOLEAN                        NoReset;
+  BOOLEAN                        NeedCopyOnDisk;
+  CHAR16                         *CapsuleName;
+  UINTN                          CapsuleNum;
+  UINTN                          Index;
+
+  Status = GetArg();
+  if (EFI_ERROR(Status)) {
+    PrintUsage();
+    return Status;
+  }
+  if (Argc < 2) {
+    PrintUsage();
+    CleanArg();
+    return EFI_INVALID_PARAMETER;
+  }
+  if ((StrCmp(Argv[1], L"-D") == 0) ||
+      (StrCmp(Argv[1], L"-DS") == 0)) {
+    Status = DumpCapsule();
+    CleanArg();
+    return Status;
+  }
+  if (StrCmp(Argv[1], L"-G") == 0) {
+    Status = CreateBmpFmp();
+    CleanArg();
+    return Status;
+  }
+  if (StrCmp(Argv[1], L"-N") == 0) {
+    Status = CreateNestedFmp();
+    CleanArg();
+    return Status;
+  }
+  if (StrCmp(Argv[1], L"-S") == 0) {
+    Status = DmpCapsuleStatusVariable();
+    CleanArg();
+    return EFI_SUCCESS;
+  }
+  if (StrCmp(Argv[1], L"-C") == 0) {
+    Status = ClearCapsuleStatusVariable();
+    CleanArg();
+    return Status;
+  }
+  if (StrCmp(Argv[1], L"-P") == 0) {
+    DumpFmpData();
+    CleanArg();
+    return EFI_SUCCESS;
+  }
+  if (StrCmp(Argv[1], L"-E") == 0) {
+    DumpEsrtData();
+    CleanArg();
+    return EFI_SUCCESS;
+  }
+  if (StrCmp(Argv[1], L"-F") == 0) {
+    NeedCopyOnDisk = TRUE;
+    CapsuleFirstIndex = 2;
+  } else {
+    NeedCopyOnDisk = FALSE;
+    CapsuleFirstIndex = 1;
+  }
+  if (StrCmp(Argv[Argc - 1], L"-NR") == 0) {
+    NoReset = TRUE;
+    CapsuleLastIndex = Argc - 2;
+  } else {
+    NoReset = FALSE;
+    CapsuleLastIndex = Argc - 1;
+  }
+  CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
+
+  if (CapsuleFirstIndex > CapsuleLastIndex) {
+    Print(L"CapsuleApp: NO capsule image.\n");
+    CleanArg();
+    return EFI_UNSUPPORTED;
+  }
+  if (CapsuleNum > MAX_CAPSULE_NUM) {
+    Print(L"CapsuleApp: Too many capsule images.\n");
+    CleanArg();
+    return EFI_UNSUPPORTED;
+  }
+
+  ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
+  ZeroMem(&FileSize, sizeof(FileSize));
+  BlockDescriptors = NULL;
+
+  for (Index = 0; Index < CapsuleNum; Index++) {
+    CapsuleName = Argv[CapsuleFirstIndex + Index];
+    Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], 
&CapsuleBuffer[Index]);
+    if (EFI_ERROR(Status)) {
+      Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
+      goto Done;
+    }
+  }
+
+  if (NeedCopyOnDisk) {
+    Status = CopyCapsuleToActiveEfiPartition(CapsuleBuffer, FileSize, 
CapsuleNum);
+  } else {
+    //
+    // Every capsule use 2 descriptor 1 for data 1 for end
+    //
+    Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, 
&BlockDescriptors);
+  }
+  if (EFI_ERROR(Status)) {
+    goto Done;
+  }
+
+  //
+  // Call the runtime service capsule.
+  //
+  NeedReset = FALSE;
+  for (Index = 0; Index < CapsuleNum; Index++) {
+    CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
+    if ((CapsuleHeaderArray[Index]->Flags & 
CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
+      NeedReset = TRUE;
+    }
+  }
+  CapsuleHeaderArray[CapsuleNum] = NULL;
+  if (NoReset) {
+    NeedReset = FALSE;
+  }
+
+  //
+  // Inquire platform capability of UpdateCapsule.
+  //
+  Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, 
&MaxCapsuleSize, &ResetType);
+  if (EFI_ERROR(Status)) {
+    Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
+    goto Done;
+  }
+
+  for (Index = 0; Index < CapsuleNum; Index++) {
+    if (FileSize[Index] > MaxCapsuleSize) {
+      Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", 
MaxCapsuleSize);
+      Status = EFI_UNSUPPORTED;
+      goto Done;
+    }
+  }
+
+  //
+  // Check whether the input capsule image has the flag of persist across 
system reset.
+  //
+  if (NeedReset) {
+    Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) 
BlockDescriptors);
+    if (Status != EFI_SUCCESS) {
+      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
+      goto Done;
+    }
+    //
+    // For capsule who has reset flag, after calling UpdateCapsule 
service,triger a
+    // system reset to process capsule persist across a system reset.
+    //
+    gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
+  } else {
+    //
+    // For capsule who has no reset flag, only call UpdateCapsule Service 
without a
+    // system reset. The service will process the capsule immediately.
+    //
+    Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) 
BlockDescriptors);
+    if (Status != EFI_SUCCESS) {
+      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
+    }
+  }
+
+  Status = EFI_SUCCESS;
+
+Done:
+  for (Index = 0; Index < CapsuleNum; Index++) {
+    if (CapsuleBuffer[Index] != NULL) {
+      FreePool (CapsuleBuffer[Index]);
+    }
+  }
+
+  CleanGatherList(BlockDescriptors, CapsuleNum);
+  CleanArg();
+
+  return Status;
+}
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf 
b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
new file mode 100644
index 0000000..7ee44fc
--- /dev/null
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
@@ -0,0 +1,71 @@
+##  @file
+#  A shell application that triggers capsule update process.
+#
+# This application can trigger capsule update process. It can also
+# generate capsule image, or dump capsule variable information.
+#
+#  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+#  This program and the accompanying materials
+#  are licensed and made available under the terms and conditions of the BSD 
License
+#  which accompanies this distribution.  The full text of the license may be 
found at
+#  http://opensource.org/licenses/bsd-license.php
+#
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
IMPLIED.
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010006
+  BASE_NAME                      = CapsuleApp
+  MODULE_UNI_FILE                = CapsuleApp.uni
+  FILE_GUID                      = 4CEF31DA-8682-4274-9CC4-AEE7516A5E7B
+  MODULE_TYPE                    = UEFI_APPLICATION
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = UefiMain
+
+#
+# The following information is for reference only and not required by the 
build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64
+#
+
+[Sources]
+  CapsuleApp.c
+  CapsuleDump.c
+  AppSupport.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+
+[Guids]
+  gEfiFileInfoGuid
+  gEfiPartTypeSystemPartGuid
+  gEfiGlobalVariableGuid
+  gEfiCapsuleReportGuid
+  gEfiFmpCapsuleGuid
+  gWindowsUxCapsuleGuid
+  gEfiCertTypeRsa2048Sha256Guid
+  gEfiCertPkcs7Guid
+  gEfiSystemResourceTableGuid
+
+[Protocols]
+  gEfiLoadedImageProtocolGuid
+  gEfiSimpleFileSystemProtocolGuid
+  gEfiGraphicsOutputProtocolGuid
+  gEfiFirmwareManagementProtocolGuid
+
+[LibraryClasses]
+  BaseLib
+  UefiApplicationEntryPoint
+  DebugLib
+  MemoryAllocationLib
+  UefiBootServicesTableLib
+  UefiRuntimeServicesTableLib
+  UefiLib
+  PrintLib
+  EdkiiSystemCapsuleLib
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  CapsuleAppExtra.uni
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni 
b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
new file mode 100644
index 0000000..54d6e12
--- /dev/null
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
@@ -0,0 +1,22 @@
+// /** @file
+// A shell application that triggers capsule update process.
+//
+// This application can trigger capsule update process. It can also
+// generate capsule image, or dump capsule variable information.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD 
License
+// which accompanies this distribution. The full text of the license may be 
found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT             #language en-US "A shell application 
that triggers capsule update process."
+
+#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."
+
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni 
b/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
new file mode 100644
index 0000000..b5a8840
--- /dev/null
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
@@ -0,0 +1,19 @@
+// /** @file
+// CapsuleApp Localized Strings and Content
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD 
License
+// which accompanies this distribution. The full text of the license may be 
found at
+// http://opensource.org/licenses/bsd-license.php
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR 
IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Capsule Application"
+
+
diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c 
b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
new file mode 100644
index 0000000..c56f41f
--- /dev/null
+++ b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
@@ -0,0 +1,840 @@
+/** @file
+  Dump Capsule image information.
+
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+  This program and the accompanying materials
+  are licensed and made available under the terms and conditions of the BSD 
License
+  which accompanies this distribution.  The full text of the license may be 
found at
+  http://opensource.org/licenses/bsd-license.php
+
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/EdkiiSystemCapsuleLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Guid/ImageAuthentication.h>
+#include <Guid/EdkiiSystemFmpCapsule.h>
+#include <Guid/CapsuleReport.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/FmpCapsule.h>
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+/**
+  Read a file.
+
+  @param FileName        The file to be read.
+  @param BufferSize      The file buffer size
+  @param Buffer          The file buffer
+
+  @retval EFI_SUCCESS    Read file successfully
+  @retval EFI_NOT_FOUND  File not found
+**/
+EFI_STATUS
+ReadFileToBuffer(
+  IN  CHAR16                               *FileName,
+  OUT UINTN                                *BufferSize,
+  OUT VOID                                 **Buffer
+  );
+
+extern UINTN  Argc;
+extern CHAR16 *Argv[];
+
+/**
+  Dump UX capsule information.
+
+  @param CapsuleHeader      The UX capsule header
+**/
+VOID
+DumpUxCapsule(
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader
+  )
+{
+  EFI_DISPLAY_CAPSULE                           *DisplayCapsule;
+  DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader;
+  Print(L"[UxCapusule]\n");
+  Print(L"CapsuleHeader:\n");
+  Print(L"  CapsuleGuid      - %g\n", 
&DisplayCapsule->CapsuleHeader.CapsuleGuid);
+  Print(L"  HeaderSize       - 0x%x\n", 
DisplayCapsule->CapsuleHeader.HeaderSize);
+  Print(L"  Flags            - 0x%x\n", DisplayCapsule->CapsuleHeader.Flags);
+  Print(L"  CapsuleImageSize - 0x%x\n", 
DisplayCapsule->CapsuleHeader.CapsuleImageSize);
+  Print(L"ImagePayload:\n");
+  Print(L"  Version          - 0x%x\n", DisplayCapsule->ImagePayload.Version);
+  Print(L"  Checksum         - 0x%x\n", DisplayCapsule->ImagePayload.Checksum);
+  Print(L"  ImageType        - 0x%x\n", 
DisplayCapsule->ImagePayload.ImageType);
+  Print(L"  Mode             - 0x%x\n", DisplayCapsule->ImagePayload.Mode);
+  Print(L"  OffsetX          - 0x%x\n", DisplayCapsule->ImagePayload.OffsetX);
+  Print(L"  OffsetY          - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY);
+}
+
+/**
+  Dump FMP image authentication information.
+
+  @param Image      The FMP capsule image
+  @param ImageSize  The size of the FMP capsule image in bytes.
+
+  @return the size of FMP authentication.
+**/
+UINTN
+DumpImageAuthentication(
+  IN VOID   *Image,
+  IN UINTN  ImageSize
+  )
+{
+  EFI_FIRMWARE_IMAGE_AUTHENTICATION             *ImageAuthentication;
+
+  ImageAuthentication = Image;
+  if (CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertPkcs7Guid) 
||
+      CompareGuid(&ImageAuthentication->AuthInfo.CertType, 
&gEfiCertTypeRsa2048Sha256Guid)) {
+    Print(L"[ImageAuthentication]\n");
+    Print(L"  MonotonicCount   - 0x%lx\n", 
ImageAuthentication->MonotonicCount);
+    Print(L"WIN_CERTIFICATE:\n");
+    Print(L"  dwLength         - 0x%x\n", 
ImageAuthentication->AuthInfo.Hdr.dwLength);
+    Print(L"  wRevision        - 0x%x\n", 
ImageAuthentication->AuthInfo.Hdr.wRevision);
+    Print(L"  wCertificateType - 0x%x\n", 
ImageAuthentication->AuthInfo.Hdr.wCertificateType);
+    Print(L"  CertType         - %g\n", 
&ImageAuthentication->AuthInfo.CertType);
+    return sizeof(ImageAuthentication->MonotonicCount) + 
ImageAuthentication->AuthInfo.Hdr.dwLength;
+  } else {
+    return 0;
+  }
+}
+
+/**
+  Dump EDKII system FMP capsule.
+
+  @param Image      The EDKII system FMP capsule.
+  @param ImageSize  The size of the EDKII system FMP capsule in bytes.
+**/
+VOID
+DumpEdkiiSystemFmpCapsule(
+  IN VOID   *Image,
+  IN UINTN  ImageSize
+  )
+{
+  UINTN                                         ImageOffset;
+  VOID                                          *BiosImage;
+  UINTN                                         BiosImageSize;
+  BOOLEAN                                       Result;
+  EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR        *TempImageFmpInfo;
+  EDKII_SYSTEM_FIRMWARE_IMAGE_DESCRIPTOR        *ImageFmpInfo;
+  UINTN                                         ImageFmpInfoSize;
+
+  //
+  // We do not know if there is EFI_FIRMWARE_IMAGE_AUTHENTICATION.
+  // so just *try* to parse it
+  //
+  ImageOffset = DumpImageAuthentication(Image, ImageSize);
+  Image = (UINT8 *)Image + ImageOffset;
+  ImageSize -= ImageOffset;
+  Print(L"[Image]\n");
+  Print(L"  ImageSize   - 0x%x\n", ImageSize);
+
+  Result = ExtractConfigImage(Image, ImageSize, &BiosImage, &BiosImageSize);
+  if (Result) {
+    Print(L"  ConfigFileSize  - 0x%x\n", BiosImageSize);
+  }
+  Result = ExtractDriverFvImage(Image, ImageSize, &BiosImage, &BiosImageSize);
+  if (Result) {
+    Print(L"  DriverFvSize    - 0x%x\n", BiosImageSize);
+  }
+  Result = ExtractSystemFirmwareImage(Image, ImageSize, &BiosImage, 
&BiosImageSize);
+  if (Result) {
+    Print(L"  BiosImageSize   - 0x%x\n", BiosImageSize);
+  }
+  Result = ExtractSystemFirmwareImageFmpInfo(BiosImage, BiosImageSize, 
&TempImageFmpInfo, &ImageFmpInfoSize);
+  if (Result) {
+    ImageFmpInfo = AllocateCopyPool(ImageFmpInfoSize, TempImageFmpInfo);
+    if (ImageFmpInfo != NULL) {
+      Print(L"[ImageFmpInfo]\n");
+      Print(L"  Signature                      - 0x%x\n", 
ImageFmpInfo->Signature);
+      Print(L"  HeaderLength                   - 0x%x\n", 
ImageFmpInfo->HeaderLength);
+      Print(L"  Length                         - 0x%x\n", 
ImageFmpInfo->Length);
+      Print(L"  PackageVersion                 - 0x%x\n", 
ImageFmpInfo->PackageVersion);
+      Print(L"  PackageVersionNameStringOffset - 0x%x\n", 
ImageFmpInfo->PackageVersionNameStringOffset);
+      if (ImageFmpInfo->PackageVersionNameStringOffset != 0) {
+        Print(L"                                 - %s\n", (UINT8 
*)ImageFmpInfo + ImageFmpInfo->PackageVersionNameStringOffset);
+      }
+      Print(L"  ImageIndex                     - 0x%x\n", 
ImageFmpInfo->ImageIndex);
+      Print(L"  ImageTypeId                    - %g\n", 
&ImageFmpInfo->ImageTypeId);
+      Print(L"  ImageId                        - 0x%lx\n", 
ImageFmpInfo->ImageId);
+      Print(L"  ImageIdNameStringOffset        - 0x%x\n", 
ImageFmpInfo->ImageIdNameStringOffset);
+      if (ImageFmpInfo->ImageIdNameStringOffset != 0) {
+        Print(L"                                 - %s\n", (UINT8 
*)ImageFmpInfo + ImageFmpInfo->ImageIdNameStringOffset);
+      }
+      Print(L"  Version                        - 0x%x\n", 
ImageFmpInfo->Version);
+      Print(L"  VersionNameStringOffset        - 0x%x\n", 
ImageFmpInfo->VersionNameStringOffset);
+      if (ImageFmpInfo->VersionNameStringOffset != 0) {
+        Print(L"                                 - %s\n", (UINT8 
*)ImageFmpInfo + ImageFmpInfo->VersionNameStringOffset);
+      }
+      Print(L"  Size                           - 0x%lx\n", ImageFmpInfo->Size);
+      Print(L"  AttributesSupported            - 0x%lx\n", 
ImageFmpInfo->AttributesSupported);
+      Print(L"  AttributesSetting              - 0x%lx\n", 
ImageFmpInfo->AttributesSetting);
+      Print(L"  Compatibilities                - 0x%lx\n", 
ImageFmpInfo->Compatibilities);
+      Print(L"  LowestSupportedImageVersion    - 0x%x\n", 
ImageFmpInfo->LowestSupportedImageVersion);
+      Print(L"  LastAttemptVersion             - 0x%x\n", 
ImageFmpInfo->LastAttemptVersion);
+      Print(L"  LastAttemptStatus              - 0x%x\n", 
ImageFmpInfo->LastAttemptStatus);
+      Print(L"  HardwareInstance               - 0x%lx\n", 
ImageFmpInfo->HardwareInstance);
+      Print(L"  Version                        - 0x%x\n", 
ImageFmpInfo->Version);
+      FreePool(ImageFmpInfo);
+    }
+  }
+}
+
+/**
+  Dump a non-nested FMP capsule.
+
+  @param  CapsuleHeader  A pointer to CapsuleHeader
+  @param  IsSystemFmp    If it is a system FMP
+**/
+VOID
+DumpFmpCapsule(
+  IN EFI_CAPSULE_HEADER  *CapsuleHeader,
+  IN BOOLEAN             IsSystemFmp
+  )
+{
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
+  UINT64                                        *ItemOffsetList;
+  UINTN                                         Index;
+  UINTN                                         Count;
+  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *FmpImageHeader;
+  VOID                                          *Image;
+
+  Print(L"[FmpCapusule]\n");
+  Print(L"CapsuleHeader:\n");
+  Print(L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);
+  Print(L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);
+  Print(L"  Flags            - 0x%x\n", CapsuleHeader->Flags);
+  Print(L"  CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
+
+  FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 
*)CapsuleHeader + CapsuleHeader->HeaderSize);
+  ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+  Print(L"FmpHeader:\n");
+  Print(L"  Version             - 0x%x\n", FmpCapsuleHeader->Version);
+  Print(L"  EmbeddedDriverCount - 0x%x\n", 
FmpCapsuleHeader->EmbeddedDriverCount);
+  Print(L"  PayloadItemCount    - 0x%x\n", FmpCapsuleHeader->PayloadItemCount);
+  Count = FmpCapsuleHeader->EmbeddedDriverCount + 
FmpCapsuleHeader->PayloadItemCount;
+  for (Index = 0; Index < Count; Index++) {
+    Print(L"  Offset[%d]           - 0x%x\n", Index, ItemOffsetList[Index]);
+  }
+
+  for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) {
+    Print(L"FmpPayload[%d] ImageHeader:\n", Index);
+    FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 
*)FmpCapsuleHeader + ItemOffsetList[Index]);
+    Print(L"  Version                - 0x%x\n", FmpImageHeader->Version);
+    Print(L"  UpdateImageTypeId      - %g\n", 
&FmpImageHeader->UpdateImageTypeId);
+    Print(L"  UpdateImageIndex       - 0x%x\n", 
FmpImageHeader->UpdateImageIndex);
+    Print(L"  UpdateImageSize        - 0x%x\n", 
FmpImageHeader->UpdateImageSize);
+    Print(L"  UpdateVendorCodeSize   - 0x%x\n", 
FmpImageHeader->UpdateVendorCodeSize);
+    if (FmpImageHeader->Version >= 
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+      Print(L"  UpdateHardwareInstance - 0x%lx\n", 
FmpImageHeader->UpdateHardwareInstance);
+    }
+    if (FmpImageHeader->Version >= 
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+      Image = (UINT8 *)(FmpImageHeader + 1);
+    }  else {
+      Image = (UINT8 *)FmpImageHeader + 
OFFSET_OF(EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+    }
+    if (IsSystemFmp) {
+      DumpEdkiiSystemFmpCapsule(Image, FmpImageHeader->UpdateImageSize);
+    }
+  }
+}
+
+/**
+  Return if there is a FMP header below capsule header.
+
+  @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+  @retval TRUE  There is a FMP header below capsule header.
+  @retval FALSE There is not a FMP header below capsule header
+**/
+BOOLEAN
+IsNestedFmpCapsule(
+  IN EFI_CAPSULE_HEADER         *CapsuleHeader
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;
+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
+  UINTN                      Index;
+  BOOLEAN                    EsrtGuidFound;
+  EFI_CAPSULE_HEADER         *NestedCapsuleHeader;
+  UINTN                      NestedCapsuleSize;
+
+  //
+  // Check ESRT
+  //
+  EsrtGuidFound = FALSE;
+  Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID 
**)&Esrt);
+  if (!EFI_ERROR(Status)) {
+    EsrtEntry = (VOID *)(Esrt + 1);
+    for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
+      if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
+        EsrtGuidFound = TRUE;
+        break;
+      }
+    }
+  }
+
+  if (!EsrtGuidFound) {
+    return FALSE;
+  }
+
+  //
+  // Check nested capsule header
+  // FMP GUID after ESRT one
+  //
+  NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + 
CapsuleHeader->HeaderSize);
+  NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->HeaderSize - 
(UINTN)NestedCapsuleHeader;
+  if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {
+    return FALSE;
+  }
+  if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+  Dump capsule information
+
+  @retval EFI_SUCCESS            The capsule information is dumped.
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.
+**/
+EFI_STATUS
+DumpCapsule(
+  VOID
+  )
+{
+  CHAR16                                        *CapsuleName;
+  VOID                                          *Buffer;
+  UINTN                                         FileSize;
+  BOOLEAN                                       IsSystemFmp;
+  EFI_CAPSULE_HEADER                            *CapsuleHeader;
+  EFI_STATUS                                    Status;
+
+  if (Argc != 3) {
+    Print(L"CapsuleApp: Invalid Parameter.\n");
+    return EFI_UNSUPPORTED;
+  }
+
+  IsSystemFmp = FALSE;
+  if (StrCmp(Argv[1], L"-DS") == 0) {
+    IsSystemFmp = TRUE;
+  }
+
+  CapsuleName = Argv[2];
+  Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer);
+  if (EFI_ERROR(Status)) {
+    Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName);
+    goto Done;
+  }
+
+  CapsuleHeader = Buffer;
+  if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
+    DumpUxCapsule(CapsuleHeader);
+    Status = EFI_SUCCESS;
+    goto Done;
+  }
+
+  if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+    DumpFmpCapsule(CapsuleHeader, IsSystemFmp);
+  }
+  if (IsNestedFmpCapsule(CapsuleHeader)) {
+    Print(L"[NestedCapusule]\n");
+    Print(L"CapsuleHeader:\n");
+    Print(L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);
+    Print(L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);
+    Print(L"  Flags            - 0x%x\n", CapsuleHeader->Flags);
+    Print(L"  CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
+    DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + 
CapsuleHeader->HeaderSize), IsSystemFmp);
+  }
+
+Done:
+  FreePool(Buffer);
+  return Status;
+}
+
+/**
+  Dump capsule status variable.
+
+  @retval EFI_SUCCESS            The capsule status variable is dumped.
+  @retval EFI_UNSUPPORTED        Input parameter is not valid.
+**/
+EFI_STATUS
+DmpCapsuleStatusVariable(
+  VOID
+  )
+{
+  EFI_STATUS                          Status;
+  UINT32                              Index;
+  CHAR16                              CapsuleVarName[20];
+  CHAR16                              *TempVarName;
+  EFI_CAPSULE_RESULT_VARIABLE_HEADER  *CapsuleResult;
+  EFI_CAPSULE_RESULT_VARIABLE_FMP     *CapsuleResultFmp;
+  UINTN                               CapsuleFileNameSize;
+  CHAR16                              CapsuleIndexData[12];
+  CHAR16                              *CapsuleIndex;
+
+  Status = GetVariable2(
+             L"CapsuleMax",
+             &gEfiCapsuleReportGuid,
+             (VOID **)&CapsuleIndex,
+             NULL
+             );
+  if (!EFI_ERROR(Status)) {
+    CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));
+    CapsuleIndexData[11] = 0;
+    Print(L"CapsuleMax - %s\n", CapsuleIndexData);
+    FreePool(CapsuleIndex);
+  }
+  Status = GetVariable2(
+             L"CapsuleLast",
+             &gEfiCapsuleReportGuid,
+             (VOID **)&CapsuleIndex,
+             NULL
+             );
+  if (!EFI_ERROR(Status)) {
+    CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));
+    CapsuleIndexData[11] = 0;
+    Print(L"CapsuleLast - %s\n", CapsuleIndexData);
+    FreePool(CapsuleIndex);
+  }
+
+
+  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), 
L"Capsule");
+  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
+  Index = 0;
+
+  while (TRUE) {
+    UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
+
+    Status = GetVariable2 (
+               CapsuleVarName,
+               &gEfiCapsuleReportGuid,
+               (VOID **) &CapsuleResult,
+               NULL
+               );
+    if (Status == EFI_NOT_FOUND) {
+      break;
+    } else if (EFI_ERROR(Status)) {
+      continue;
+    }
+
+    //
+    // display capsule process status
+    //
+    if (CapsuleResult->VariableTotalSize >= 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) {
+      Print (L"CapsuleName: %s\n", CapsuleVarName);
+      Print (L"  Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid);
+      Print (L"  Capsule ProcessedTime: %t\n", 
&CapsuleResult->CapsuleProcessed);
+      Print (L"  Capsule Status: %r\n", CapsuleResult->CapsuleStatus);
+    }
+
+    if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
+      if (CapsuleResult->VariableTotalSize >= 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {
+        CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 
1);
+        Print(L"  Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version);
+        Print(L"  Capsule FMP PayloadIndex: 0x%x\n", 
CapsuleResultFmp->PayloadIndex);
+        Print(L"  Capsule FMP UpdateImageIndex: 0x%x\n", 
CapsuleResultFmp->UpdateImageIndex);
+        Print(L"  Capsule FMP UpdateImageTypeId: %g\n", 
&CapsuleResultFmp->UpdateImageTypeId);
+        if (CapsuleResult->VariableTotalSize > 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {
+          Print(L"  Capsule FMP CapsuleFileName: %s\n", (CapsuleResultFmp + 
1));
+          CapsuleFileNameSize = StrSize((CHAR16 *)(CapsuleResultFmp + 1));
+          if (CapsuleResult->VariableTotalSize > 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + 
sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapsuleFileNameSize) {
+            Print(L"  Capsule FMP CapsuleTarget: %s\n", (UINT8 
*)(CapsuleResultFmp + 1) + CapsuleFileNameSize);
+          }
+        }
+      }
+    }
+
+    FreePool(CapsuleResult);
+
+    Index++;
+    if (Index > 0xFFFF) {
+      break;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+CHAR8 *mFwTypeString[] = {
+  "Unknown",
+  "SystemFirmware",
+  "DeviceFirmware",
+  "UefiDriver",
+};
+
+CHAR8 *mLastAttemptStatusString[] = {
+  "Success",
+  "Error: Unsuccessful",
+  "Error: Insufficient Resources",
+  "Error: Incorrect Version",
+  "Error: Invalid Format",
+  "Error: Auth Error",
+  "Error: Power Event AC",
+  "Error: Power Event Battery",
+};
+
+/**
+  Convert FwType to a string.
+
+  @param FwType  FwType in ESRT
+
+  @return a string for FwType.
+**/
+CHAR8 *
+FwTypeToString(
+  IN UINT32 FwType
+  )
+{
+  if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) {
+    return mFwTypeString[FwType];
+  } else {
+    return "Invalid";
+  }
+}
+
+/**
+  Convert LastAttemptStatus to a string.
+
+  @param LastAttemptStatus  LastAttemptStatus in FMP or ESRT
+
+  @return a string for LastAttemptStatus.
+**/
+CHAR8 *
+LastAttemptStatusToString(
+  IN UINT32 LastAttemptStatus
+  )
+{
+  if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / 
sizeof(mLastAttemptStatusString[0])) {
+    return mLastAttemptStatusString[LastAttemptStatus];
+  } else {
+    return "Error: Unknown";
+  }
+}
+
+/**
+  Dump ESRT entry.
+
+  @param EsrtEntry  ESRT entry
+**/
+VOID
+DumpEsrtEntry(
+  IN EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry
+  )
+{
+  Print(L"  FwClass                  - %g\n", &EsrtEntry->FwClass);
+  Print(L"  FwType                   - 0x%x (%a)\n", EsrtEntry->FwType, 
FwTypeToString(EsrtEntry->FwType));
+  Print(L"  FwVersion                - 0x%x\n", EsrtEntry->FwVersion);
+  Print(L"  LowestSupportedFwVersion - 0x%x\n", 
EsrtEntry->LowestSupportedFwVersion);
+  Print(L"  CapsuleFlags             - 0x%x\n", EsrtEntry->CapsuleFlags);
+  Print(L"    PERSIST_ACROSS_RESET   - 0x%x\n", EsrtEntry->CapsuleFlags & 
CAPSULE_FLAGS_PERSIST_ACROSS_RESET);
+  Print(L"    POPULATE_SYSTEM_TABLE  - 0x%x\n", EsrtEntry->CapsuleFlags & 
CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE);
+  Print(L"    INITIATE_RESET         - 0x%x\n", EsrtEntry->CapsuleFlags & 
CAPSULE_FLAGS_INITIATE_RESET);
+  Print(L"  LastAttemptVersion       - 0x%x\n", EsrtEntry->LastAttemptVersion);
+  Print(L"  LastAttemptStatus        - 0x%x (%a)\n", 
EsrtEntry->LastAttemptStatus, 
LastAttemptStatusToString(EsrtEntry->LastAttemptStatus));
+}
+
+/**
+  Dump ESRT table.
+
+  @param Esrt  ESRT table
+**/
+VOID
+DumpEsrt(
+  IN EFI_SYSTEM_RESOURCE_TABLE  *Esrt
+  )
+{
+  UINTN                      Index;
+  EFI_SYSTEM_RESOURCE_ENTRY  *EsrtEntry;
+
+  Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n");
+  Print(L"FwResourceCount    - 0x%x\n", Esrt->FwResourceCount);
+  Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax);
+  Print(L"FwResourceVersion  - 0x%lx\n", Esrt->FwResourceVersion);
+
+  EsrtEntry = (VOID *)(Esrt + 1);
+  for (Index = 0; Index < Esrt->FwResourceCount; Index++) {
+    Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index);
+    DumpEsrtEntry(EsrtEntry);
+    EsrtEntry++;
+  }
+}
+
+/**
+  Dump ESRT info.
+**/
+VOID
+DumpEsrtData (
+  VOID
+  )
+{
+  EFI_STATUS                 Status;
+  EFI_SYSTEM_RESOURCE_TABLE  *Esrt;
+
+  Print(L"##############\n");
+  Print(L"# ESRT TABLE #\n");
+  Print(L"##############\n");
+
+  Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID 
**)&Esrt);
+  if (EFI_ERROR(Status)) {
+    Print(L"ESRT - %r\n", Status);
+    return;
+  }
+  DumpEsrt(Esrt);
+  Print(L"\n");
+}
+
+/**
+  Dump FMP information.
+
+  @param ImageInfoSize       The size of ImageInfo, in bytes.
+  @param ImageInfo           A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param DescriptorVersion   The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param DescriptorCount     The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+  @param DescriptorSize      The size of an individual 
EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
+  @param PackageVersion      The version of package.
+  @param PackageVersionName  The version name of package.
+**/
+VOID
+DumpFmpImageInfo(
+  IN UINTN                           ImageInfoSize,
+  IN EFI_FIRMWARE_IMAGE_DESCRIPTOR   *ImageInfo,
+  IN UINT32                          DescriptorVersion,
+  IN UINT8                           DescriptorCount,
+  IN UINTN                           DescriptorSize,
+  IN UINT32                          PackageVersion,
+  IN CHAR16                          *PackageVersionName
+  )
+{
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *CurrentImageInfo;
+  UINTN                                         Index;
+
+  Print(L"  DescriptorVersion  - 0x%x\n", DescriptorVersion);
+  Print(L"  DescriptorCount    - 0x%x\n", DescriptorCount);
+  Print(L"  DescriptorSize     - 0x%x\n", DescriptorSize);
+  Print(L"  PackageVersion     - 0x%x\n", PackageVersion);
+  Print(L"  PackageVersionName - \"%s\"\n", PackageVersionName);
+  CurrentImageInfo = ImageInfo;
+  for (Index = 0; Index < DescriptorCount; Index++) {
+    Print(L"  ImageDescriptor (%d)\n", Index);
+    Print(L"    ImageIndex                  - 0x%x\n", 
CurrentImageInfo->ImageIndex);
+    Print(L"    ImageTypeId                 - %g\n", 
&CurrentImageInfo->ImageTypeId);
+    Print(L"    ImageId                     - 0x%lx\n", 
CurrentImageInfo->ImageId);
+    Print(L"    ImageIdName                 - \"%s\"\n", 
CurrentImageInfo->ImageIdName);
+    Print(L"    Version                     - 0x%x\n", 
CurrentImageInfo->Version);
+    Print(L"    VersionName                 - \"%s\"\n", 
CurrentImageInfo->VersionName);
+    Print(L"    Size                        - 0x%x\n", CurrentImageInfo->Size);
+    Print(L"    AttributesSupported         - 0x%lx\n", 
CurrentImageInfo->AttributesSupported);
+    Print(L"      IMAGE_UPDATABLE           - 0x%lx\n", 
CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+    Print(L"      RESET_REQUIRED            - 0x%lx\n", 
CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED);
+    Print(L"      AUTHENTICATION_REQUIRED   - 0x%lx\n", 
CurrentImageInfo->AttributesSupported & 
IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+    Print(L"      IN_USE                    - 0x%lx\n", 
CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE);
+    Print(L"      UEFI_IMAGE                - 0x%lx\n", 
CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE);
+    Print(L"    AttributesSetting           - 0x%lx\n", 
CurrentImageInfo->AttributesSetting);
+    Print(L"      IMAGE_UPDATABLE           - 0x%lx\n", 
CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+    Print(L"      RESET_REQUIRED            - 0x%lx\n", 
CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED);
+    Print(L"      AUTHENTICATION_REQUIRED   - 0x%lx\n", 
CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+    Print(L"      IN_USE                    - 0x%lx\n", 
CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE);
+    Print(L"      UEFI_IMAGE                - 0x%lx\n", 
CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE);
+    Print(L"    Compatibilities             - 0x%lx\n", 
CurrentImageInfo->Compatibilities);
+    Print(L"      COMPATIB_CHECK_SUPPORTED  - 0x%lx\n", 
CurrentImageInfo->Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED);
+    if (DescriptorVersion > 1) {
+      Print(L"    LowestSupportedImageVersion - 0x%x\n", 
CurrentImageInfo->LowestSupportedImageVersion);
+      if (DescriptorVersion > 2) {
+        Print(L"    LastAttemptVersion          - 0x%x\n", 
CurrentImageInfo->LastAttemptVersion);
+        Print(L"    LastAttemptStatus           - 0x%x (%a)\n", 
CurrentImageInfo->LastAttemptStatus, 
LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus));
+        Print(L"    HardwareInstance            - 0x%lx\n", 
CurrentImageInfo->HardwareInstance);
+      }
+    }
+    //
+    // Use DescriptorSize to move ImageInfo Pointer to stay compatible with 
different ImageInfo version
+    //
+    CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 
*)CurrentImageInfo + DescriptorSize);
+  }
+}
+
+/**
+  Dump FMP package information.
+
+  @param PackageVersion             The version of package.
+  @param PackageVersionName         The version name of package.
+  @param PackageVersionNameMaxLen   The maximum length of PackageVersionName.
+  @param AttributesSupported        Package attributes that are supported by 
this device.
+  @param AttributesSetting          Package attributes.
+**/
+VOID
+DumpFmpPackageInfo(
+  IN UINT32                           PackageVersion,
+  IN CHAR16                           *PackageVersionName,
+  IN UINT32                           PackageVersionNameMaxLen,
+  IN UINT64                           AttributesSupported,
+  IN UINT64                           AttributesSetting
+  )
+{
+  Print(L"  PackageVersion              - 0x%x\n", PackageVersion);
+  Print(L"  PackageVersionName          - \"%s\"\n", PackageVersionName);
+  Print(L"  PackageVersionNameMaxLen    - 0x%x\n", PackageVersionNameMaxLen);
+  Print(L"  AttributesSupported         - 0x%lx\n", AttributesSupported);
+  Print(L"    IMAGE_UPDATABLE           - 0x%lx\n", AttributesSupported & 
IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+  Print(L"    RESET_REQUIRED            - 0x%lx\n", AttributesSupported & 
IMAGE_ATTRIBUTE_RESET_REQUIRED);
+  Print(L"    AUTHENTICATION_REQUIRED   - 0x%lx\n", AttributesSupported & 
IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+  Print(L"  AttributesSetting           - 0x%lx\n", AttributesSetting);
+  Print(L"    IMAGE_UPDATABLE           - 0x%lx\n", AttributesSetting & 
IMAGE_ATTRIBUTE_IMAGE_UPDATABLE);
+  Print(L"    RESET_REQUIRED            - 0x%lx\n", AttributesSetting & 
IMAGE_ATTRIBUTE_RESET_REQUIRED);
+  Print(L"    AUTHENTICATION_REQUIRED   - 0x%lx\n", AttributesSetting & 
IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+}
+
+/**
+  Dump FMP protocol info.
+**/
+VOID
+DumpFmpData (
+  VOID
+  )
+{
+  EFI_STATUS                                    Status;
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
+  EFI_HANDLE                                    *HandleBuffer;
+  UINTN                                         NumberOfHandles;
+  UINTN                                         Index;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
+  UINTN                                         ImageInfoSize;
+  UINT32                                        FmpImageInfoDescriptorVer;
+  UINT8                                         FmpImageInfoCount;
+  UINTN                                         DescriptorSize;
+  UINT32                                        PackageVersion;
+  CHAR16                                        *PackageVersionName;
+  UINT32                                        PackageVersionNameMaxLen;
+  UINT64                                        AttributesSupported;
+  UINT64                                        AttributesSetting;
+
+  Print(L"############\n");
+  Print(L"# FMP DATA #\n");
+  Print(L"############\n");
+  Status = gBS->LocateHandleBuffer (
+                  ByProtocol,
+                  &gEfiFirmwareManagementProtocolGuid,
+                  NULL,
+                  &NumberOfHandles,
+                  &HandleBuffer
+                  );
+  if (EFI_ERROR(Status)) {
+    Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);
+    return;
+  }
+
+  for (Index = 0; Index < NumberOfHandles; Index++) {
+    Status = gBS->HandleProtocol(
+                    HandleBuffer[Index],
+                    &gEfiFirmwareManagementProtocolGuid,
+                    (VOID **)&Fmp
+                    );
+    if (EFI_ERROR(Status)) {
+      continue;
+    }
+
+    ImageInfoSize = 0;
+    Status = Fmp->GetImageInfo (
+                    Fmp,
+                    &ImageInfoSize,
+                    NULL,
+                    NULL,
+                    NULL,
+                    NULL,
+                    NULL,
+                    NULL
+                    );
+    if (Status != EFI_BUFFER_TOO_SMALL) {
+      continue;
+    }
+
+    FmpImageInfoBuf = NULL;
+    FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+    if (FmpImageInfoBuf == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      goto EXIT;
+    }
+
+    PackageVersionName = NULL;
+    Status = Fmp->GetImageInfo (
+                    Fmp,
+                    &ImageInfoSize,               // ImageInfoSize
+                    FmpImageInfoBuf,              // ImageInfo
+                    &FmpImageInfoDescriptorVer,   // DescriptorVersion
+                    &FmpImageInfoCount,           // DescriptorCount
+                    &DescriptorSize,              // DescriptorSize
+                    &PackageVersion,              // PackageVersion
+                    &PackageVersionName           // PackageVersionName
+                    );
+
+    //
+    // If FMP GetInformation interface failed, skip this resource
+    //
+    if (EFI_ERROR(Status)) {
+      Print(L"FMP (%d) ImageInfo - %r\n", Index, Status);
+      FreePool(FmpImageInfoBuf);
+      continue;
+    }
+
+    Print(L"FMP (%d) ImageInfo:\n", Index);
+    DumpFmpImageInfo(
+      ImageInfoSize,               // ImageInfoSize
+      FmpImageInfoBuf,             // ImageInfo
+      FmpImageInfoDescriptorVer,   // DescriptorVersion
+      FmpImageInfoCount,           // DescriptorCount
+      DescriptorSize,              // DescriptorSize
+      PackageVersion,              // PackageVersion
+      PackageVersionName           // PackageVersionName
+      );
+
+    if (PackageVersionName != NULL) {
+      FreePool(PackageVersionName);
+    }
+    FreePool(FmpImageInfoBuf);
+
+    //
+    // Get package info
+    //
+    PackageVersionName = NULL;
+    Status = Fmp->GetPackageInfo (
+                    Fmp,
+                    &PackageVersion,              // PackageVersion
+                    &PackageVersionName,          // PackageVersionName
+                    &PackageVersionNameMaxLen,    // PackageVersionNameMaxLen
+                    &AttributesSupported,         // AttributesSupported
+                    &AttributesSetting            // AttributesSetting
+                    );
+    if (EFI_ERROR(Status)) {
+      Print(L"FMP (%d) PackageInfo - %r\n", Index, Status);
+    } else {
+      Print(L"FMP (%d) ImageInfo:\n", Index);
+      DumpFmpPackageInfo(
+        PackageVersion,              // PackageVersion
+        PackageVersionName,          // PackageVersionName
+        PackageVersionNameMaxLen,    // PackageVersionNameMaxLen
+        AttributesSupported,         // AttributesSupported
+        AttributesSetting            // AttributesSetting
+        );
+
+      if (PackageVersionName != NULL) {
+        FreePool(PackageVersionName);
+      }
+    }
+  }
+  Print(L"\n");
+
+EXIT:
+  FreePool(HandleBuffer);
+}
-- 
2.7.4.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to