public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Yao, Jiewen" <jiewen.yao@intel.com>
To: "Yao, Jiewen" <jiewen.yao@intel.com>,
	"Kinney, Michael D" <michael.d.kinney@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Tian, Feng" <feng.tian@intel.com>,
	"Zhang, Chao B" <chao.b.zhang@intel.com>,
	"Gao, Liming" <liming.gao@intel.com>,
	"Zeng, Star" <star.zeng@intel.com>
Subject: Re: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Date: Wed, 26 Oct 2016 01:50:09 +0000	[thread overview]
Message-ID: <74D8A39837DF1E4DA445A8C0B3885C50386B7532@shsmsx102.ccr.corp.intel.com> (raw)
In-Reply-To: <74D8A39837DF1E4DA445A8C0B3885C50386B73AC@shsmsx102.ccr.corp.intel.com>

Sorry. Fixed a typo in my rely.
This UX capsule is already supported in MdeModulePkg\Library\DxeCapsuleLib.

Sean also provides feedback to remove BMP handling from this and abstract BMP handle by using a new lib.
I think it is a good idea and will follow up on that.


From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On Behalf Of Yao, Jiewen
Sent: Wednesday, October 26, 2016 8:42 AM
To: Kinney, Michael D <michael.d.kinney@intel.com>; edk2-devel@lists.01.org
Cc: Tian, Feng <feng.tian@intel.com>; Zhang, Chao B <chao.b.zhang@intel.com>; Gao, Liming <liming.gao@intel.com>; Zeng, Star <star.zeng@intel.com>
Subject: Re: [edk2] [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Comments inline:

From: Kinney, Michael D
Sent: Wednesday, October 26, 2016 7:26 AM
To: Yao, Jiewen <jiewen.yao@intel.com<mailto:jiewen.yao@intel.com>>; edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org>; Kinney, Michael D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
Cc: Tian, Feng <feng.tian@intel.com<mailto:feng.tian@intel.com>>; Zeng, Star <star.zeng@intel.com<mailto:star.zeng@intel.com>>; Gao, Liming <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Zhang, Chao B <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com>>
Subject: RE: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Hi Jiewen,

When I run the CapsuleApp.efi, it shows the following help:

CapsuleApp:  usage
  CapsuleApp <Capsule...> [-NR]
  CapsuleApp -S
  CapsuleApp -C
  CapsuleApp -P
  CapsuleApp -E
  CapsuleApp -G <BMP> -O <Capsule>
  CapsuleApp -N <Capsule> -O <NestedCapsule>
  CapsuleApp -D|-DS <Capsule>
Parameter:
  -NR: No Reset.
  -S:  Dump capsule status.
  -C:  Clear capsule status.
  -P:  Dump FMP protocol info.
  -E:  Dump ESRT table info.
  -G:  Input BMP file name
  -N:  Append Capsule Header accroding to Windows Firmware Update
  -O:  Output Capsule file name
  -D:  Dump Capsule

I have verified that that standard use case for Galileo Gen 2 works:

  CapsuleApp.efi QUARKFIRMWAREUPDATECAPSULEFMPPKCS7.Cap

I then explored some of the other options and there are some that do
not work as expected:


1) If I set the no reset flag (-NR), it still resets.

  CapsuleApp.efi QUARKFIRMWAREUPDATECAPSULEFMPPKCS7.Cap -NR
[Jiewen] This flag/code is inherit from the original EDKI code.
I made a mistake that I thought it should work.
But not actually because I just realize the reset process is moved to CapsuleService driver.
I will remove [NR] flag totally.


2) Because (1) does not work, the flags to view or operate on a previously
   Loaded capsule cannot be used such as -S, -C, -N, -O, -D.  So I do not
   know if any of these flags work.  Have you tested them?
[Jiewen] Yes, any of these flags are new added by me to assist Capsule process debug.
All of below are validated. None of them are related to [NR]

  -S:  Dump capsule status. // The capsule status variable is defined by UEFI spec. Just dump the variable. No touch capsule image.
  -C:  Clear capsule status. // The capsule status variable is defined by UEFI spec. Just clear the variable. No touch capsule image.
  -N:  Append Capsule Header accroding to Windows Firmware Update // this is to follow "Windows Firmware Update" document to append a header. We need input a capsule image and out a new capsule image. So we can test the nested capsule image. No capsule service is called. Just append header and generate a new image.
  -O:  Output Capsule file name // -O is an option working with others such as "-G <BMP> -O <Capsule>", or "-N <Capsule> -O <NestedCapsule>"
  -D:  Dump Capsule // this is just dump the capsule image information.

If you find some do not work, please let me know and I will fix them.

3) What does -G do?  I do not see a standard way to update only
   a BMP logo image in this series of patches.  If that is not
   really functional, then the code and help for -G should be
   removed.
[Jiewen] Yes, any of these flags are new added by me to assist Capsule process debug.

  -G:  Input BMP file name // this is to follow "windows firmware update" document to wrap a BMP file to be a UX capsule. So that end user may see a picture during capsule process, ideally. The prerequisite is that the platform need have a valid console.

This UX capsule is already supported in IntelFrameworkModulePkg\Library\DxeCapsuleLib.

I think this app just provides the capability to generate a UX capsule for unit test.
I think this is useful and I suggest we keep it.
If you find it does not work, please let me know and I will fix it.

4) Typo in help for -N flag.  "accroding" should be "according".
[Jiewen] Thank you. Fixed.

Mike

> -----Original Message-----
> From: Yao, Jiewen
> Sent: Saturday, October 22, 2016 7:21 PM
> To: edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org<mailto:edk2-devel@lists.01.org%3cmailto:edk2-devel@lists.01.org>>
> Cc: Tian, Feng <feng.tian@intel.com<mailto:feng.tian@intel.com<mailto:feng.tian@intel.com%3cmailto:feng.tian@intel.com>>>; Zeng, Star <star.zeng@intel.com<mailto:star.zeng@intel.com<mailto:star.zeng@intel.com%3cmailto:star.zeng@intel.com>>>; Kinney, Michael
> D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com%3cmailto:michael.d.kinney@intel.com>>>; Gao, Liming <liming.gao@intel.com<mailto:liming.gao@intel.com<mailto:liming.gao@intel.com%3cmailto:liming.gao@intel.com>>>; Zhang, Chao B
> <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com%3cmailto:chao.b.zhang@intel.com>>>
> Subject: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
>
> 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<mailto:feng.tian@intel.com<mailto:feng.tian@intel.com%3cmailto:feng.tian@intel.com>>>
> Cc: Star Zeng <star.zeng@intel.com<mailto:star.zeng@intel.com<mailto:star.zeng@intel.com%3cmailto:star.zeng@intel.com>>>
> Cc: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com%3cmailto:michael.d.kinney@intel.com>>>
> Cc: Liming Gao <liming.gao@intel.com<mailto:liming.gao@intel.com<mailto:liming.gao@intel.com%3cmailto:liming.gao@intel.com>>>
> Cc: Chao Zhang <chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com<mailto:chao.b.zhang@intel.com%3cmailto:chao.b.zhang@intel.com>>>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com<mailto:jiewen.yao@intel.com<mailto:jiewen.yao@intel.com%3cmailto:jiewen.yao@intel.com>>>
> Reviewed-by: Liming Gao <liming.gao@intel.com<mailto:liming.gao@intel.com<mailto:liming.gao@intel.com%3cmailto:liming.gao@intel.com>>>
> ---
>  MdeModulePkg/Application/CapsuleApp/AppSupport.c        | 445 ++++++++++
>  MdeModulePkg/Application/CapsuleApp/CapsuleApp.c        | 853 ++++++++++++++++++++
>  MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf      |  71 ++
>  MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni      |  22 +
>  MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni |  19 +
>  MdeModulePkg/Application/CapsuleApp/CapsuleDump.c       | 740 +++++++++++++++++
>  6 files changed, 2150 insertions(+)
>
> diff --git a/MdeModulePkg/Application/CapsuleApp/AppSupport.c
> b/MdeModulePkg/Application/CapsuleApp/AppSupport.c
> new file mode 100644
> index 0000000..90ca1fd
> --- /dev/null
> +++ b/MdeModulePkg/Application/CapsuleApp/AppSupport.c
> @@ -0,0 +1,445 @@
> +/** @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/ShellParameters.h>
> +#include <Guid/FileInfo.h>
> +#include <Guid/Gpt.h>
> +
> +#define MAX_ARG_NUM     11
> +
> +UINTN  Argc;
> +CHAR16 **Argv;
> +
> +/**
> +
> +  This function parse application ARG.
> +
> +  @return Status
> +**/
> +EFI_STATUS
> +GetArg (
> +  VOID
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
> +
> +  Status = gBS->HandleProtocol (
> +                  gImageHandle,
> +                  &gEfiShellParametersProtocolGuid,
> +                  (VOID**)&ShellParameters
> +                  );
> +  if (EFI_ERROR(Status)) {
> +    return Status;
> +  }
> +
> +  Argc = ShellParameters->Argc;
> +  Argv = ShellParameters->Argv;
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  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..6bb778a
> --- /dev/null
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> @@ -0,0 +1,853 @@
> +/** @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\\<file:///\\EFI\UpdateCapsule\><file:///\\EFI\UpdateCapsule\%3cfile:\EFI\UpdateCapsule\%3e>"
> +#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED  0x0000000000000004
> +
> +#define MAJOR_VERSION   1
> +#define MINOR_VERSION   0
> +
> +#define MAX_CAPSULE_NUM 10
> +
> +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
> +  );
> +
> +/**
> +  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;
> +}
> +
> +/**
> +  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 <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"  -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");
> +}
> +
> +/**
> +  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;
> +  CHAR16                         *CapsuleName;
> +  UINTN                          CapsuleNum;
> +  UINTN                          Index;
> +
> +  Status = GetArg();
> +  if (EFI_ERROR(Status)) {
> +    Print(L"Please use UEFI SHELL to run this application!\n", Status);
> +    return Status;
> +  }
> +  if (Argc < 2) {
> +    PrintUsage();
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  if (StrCmp(Argv[1], L"-D") == 0) {
> +    Status = DumpCapsule();
> +    return Status;
> +  }
> +  if (StrCmp(Argv[1], L"-G") == 0) {
> +    Status = CreateBmpFmp();
> +    return Status;
> +  }
> +  if (StrCmp(Argv[1], L"-N") == 0) {
> +    Status = CreateNestedFmp();
> +    return Status;
> +  }
> +  if (StrCmp(Argv[1], L"-S") == 0) {
> +    Status = DmpCapsuleStatusVariable();
> +    return EFI_SUCCESS;
> +  }
> +  if (StrCmp(Argv[1], L"-C") == 0) {
> +    Status = ClearCapsuleStatusVariable();
> +    return Status;
> +  }
> +  if (StrCmp(Argv[1], L"-P") == 0) {
> +    DumpFmpData();
> +    return EFI_SUCCESS;
> +  }
> +  if (StrCmp(Argv[1], L"-E") == 0) {
> +    DumpEsrtData();
> +    return EFI_SUCCESS;
> +  }
> +  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");
> +    return EFI_UNSUPPORTED;
> +  }
> +  if (CapsuleNum > MAX_CAPSULE_NUM) {
> +    Print(L"CapsuleApp: Too many capsule images.\n");
> +    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;
> +    }
> +  }
> +
> +  //
> +  // 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);
> +
> +  return Status;
> +}
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> new file mode 100644
> index 0000000..2084e5f
> --- /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
> +  gEfiShellParametersProtocolGuid
> +
> +[LibraryClasses]
> +  BaseLib
> +  UefiApplicationEntryPoint
> +  DebugLib
> +  MemoryAllocationLib
> +  UefiBootServicesTableLib
> +  UefiRuntimeServicesTableLib
> +  UefiLib
> +  PrintLib
> +
> +[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..b383fe1
> --- /dev/null
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> @@ -0,0 +1,740 @@
> +/** @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 <Protocol/FirmwareManagement.h>
> +#include <Guid/ImageAuthentication.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 a non-nested FMP capsule.
> +
> +  @param  CapsuleHeader  A pointer to CapsuleHeader
> +**/
> +VOID
> +DumpFmpCapsule(
> +  IN EFI_CAPSULE_HEADER  *CapsuleHeader
> +  )
> +{
> +  EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
> +  UINT64                                        *ItemOffsetList;
> +  UINTN                                         Index;
> +  UINTN                                         Count;
> +  EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *FmpImageHeader;
> +
> +  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);
> +    }
> +  }
> +}
> +
> +/**
> +  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;
> +  EFI_CAPSULE_HEADER                            *CapsuleHeader;
> +  EFI_STATUS                                    Status;
> +
> +  if (Argc != 3) {
> +    Print(L"CapsuleApp: Invalid Parameter.\n");
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  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);
> +  }
> +  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));
> +  }
> +
> +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	other threads:[~2016-10-26  1:50 UTC|newest]

Thread overview: 32+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-23  2:20 [PATCH V4 00/15] Add capsule support lib and app Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 01/15] MdeModulePkg/Include: Add FmpAuthenticationLib header Jiewen Yao
2016-10-25 23:54   ` Kinney, Michael D
2016-10-26  0:50     ` Yao, Jiewen
2016-10-26  2:06       ` Kinney, Michael D
2016-10-23  2:20 ` [PATCH V4 02/15] MdeModulePkg/CapsuleLib: Add ProcessCapsules() API Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 03/15] MdeModulePkg/MdeModulePkg.dec: Add capsule related definition Jiewen Yao
2016-10-26  2:01   ` Kinney, Michael D
2016-10-26  2:27     ` Yao, Jiewen
2016-10-26  3:00       ` Kinney, Michael D
2016-10-26  4:45         ` Yao, Jiewen
2016-10-26  4:58           ` Yao, Jiewen
2016-10-23  2:20 ` [PATCH V4 04/15] MdeModulePkg/FmpAuthenticationLibNull: Add NULL instance FMP Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 05/15] MdeModulePkg/DxeCapsuleLibNull: Add ProcessCapsules() interface Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 06/15] MdeModulePkg/DxeCapsuleLibFmp: Add DxeCapsuleLibFmp instance Jiewen Yao
2016-10-27  0:09   ` Kinney, Michael D
2016-10-27  1:33     ` Yao, Jiewen
2016-10-23  2:20 ` [PATCH V4 07/15] MdeModulePkg/Esrt: Add ESRT_FW_TYPE_SYSTEMFIRMWARE check Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application Jiewen Yao
2016-10-25 23:26   ` Kinney, Michael D
2016-10-26  0:42     ` Yao, Jiewen
2016-10-26  1:50       ` Yao, Jiewen [this message]
2016-10-26  2:05       ` Kinney, Michael D
2016-10-26  2:19         ` Yao, Jiewen
2016-10-27  0:13   ` Kinney, Michael D
2016-10-23  2:20 ` [PATCH V4 09/15] MdeModulePkg/UiApp: Show test key warning info in FrontPage Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 10/15] MdeModulePkg/MdeModulePkg.dsc: Add FMP related component Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 11/15] IntelFrameworkModulePkg/DxeCapsuleLib: Add ProcessCapsules() interface Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 12/15] SecurityPkg/SecurityPkg.dec: Add PcdPkcs7CertBuffer PCD Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 13/15] SecurityPkg/FmpAuthenticationLibPkcs7: Add PKCS7 instance for FMP Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 14/15] SecurityPkg/FmpAuthenticationLibRsa2048Sha256: Add RSA2048 instance Jiewen Yao
2016-10-23  2:20 ` [PATCH V4 15/15] SecurityPkg/SecurityPkg.dsc: Add FmpAuthenticationLib* Jiewen Yao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=74D8A39837DF1E4DA445A8C0B3885C50386B7532@shsmsx102.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox