That is good idea. I will add more description.

From: Kinney, Michael D
Sent: Wednesday, October 26, 2016 10:05 AM
To: Yao, Jiewen <[email protected]>; [email protected]; Kinney, 
Michael D <[email protected]>
Cc: Tian, Feng <[email protected]>; Zeng, Star <[email protected]>; Gao, 
Liming <[email protected]>; Zhang, Chao B <[email protected]>
Subject: RE: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp 
application.

Jiewen,

Thanks for the details.  Can you add some more help information for CapsuleApp 
so the usage of the flags you keep are clear.  I agree that keeping flags that 
support some unit tests makes sense.

Mike

From: Yao, Jiewen
Sent: Tuesday, October 25, 2016 5:42 PM
To: Kinney, Michael D 
<[email protected]<mailto:[email protected]>>; 
[email protected]<mailto:[email protected]>
Cc: Tian, Feng <[email protected]<mailto:[email protected]>>; Zeng, Star 
<[email protected]<mailto:[email protected]>>; Gao, Liming 
<[email protected]<mailto:[email protected]>>; Zhang, Chao B 
<[email protected]<mailto:[email protected]>>
Subject: RE: [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 <[email protected]<mailto:[email protected]>>; 
[email protected]<mailto:[email protected]>; Kinney, Michael D 
<[email protected]<mailto:[email protected]>>
Cc: Tian, Feng <[email protected]<mailto:[email protected]>>; Zeng, Star 
<[email protected]<mailto:[email protected]>>; Gao, Liming 
<[email protected]<mailto:[email protected]>>; Zhang, Chao B 
<[email protected]<mailto:[email protected]>>
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: [email protected]<mailto:[email protected]>
> Cc: Tian, Feng <[email protected]<mailto:[email protected]>>; Zeng, Star 
> <[email protected]<mailto:[email protected]>>; Kinney, Michael
> D <[email protected]<mailto:[email protected]>>; Gao, 
> Liming <[email protected]<mailto:[email protected]>>; Zhang, Chao B
> <[email protected]<mailto:[email protected]>>
> 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 <[email protected]<mailto:[email protected]>>
> Cc: Star Zeng <[email protected]<mailto:[email protected]>>
> Cc: Michael D Kinney 
> <[email protected]<mailto:[email protected]>>
> Cc: Liming Gao <[email protected]<mailto:[email protected]>>
> Cc: Chao Zhang <[email protected]<mailto:[email protected]>>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <[email protected]<mailto:[email protected]>>
> Reviewed-by: Liming Gao <[email protected]<mailto:[email protected]>>
> ---
>  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\>"
> +#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
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to