From: "Kinney, Michael D" <michael.d.kinney@intel.com>
To: "Yao, Jiewen" <jiewen.yao@intel.com>,
"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
"Kinney, Michael D" <michael.d.kinney@intel.com>
Cc: "Tian, Feng" <feng.tian@intel.com>,
"Zeng, Star" <star.zeng@intel.com>,
"Gao, Liming" <liming.gao@intel.com>,
"Zhang, Chao B" <chao.b.zhang@intel.com>
Subject: Re: [PATCH V4 08/15] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Date: Tue, 25 Oct 2016 23:26:00 +0000 [thread overview]
Message-ID: <E92EE9817A31E24EB0585FDF735412F56483AECC@ORSMSX113.amr.corp.intel.com> (raw)
In-Reply-To: <1477189240-11336-9-git-send-email-jiewen.yao@intel.com>
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
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?
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.
4) Typo in help for -N flag. "accroding" should be "according".
Mike
> -----Original Message-----
> From: Yao, Jiewen
> Sent: Saturday, October 22, 2016 7:21 PM
> To: edk2-devel@lists.01.org
> Cc: Tian, Feng <feng.tian@intel.com>; Zeng, Star <star.zeng@intel.com>; Kinney, Michael
> D <michael.d.kinney@intel.com>; Gao, Liming <liming.gao@intel.com>; Zhang, Chao B
> <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>
> Cc: Star Zeng <star.zeng@intel.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Chao Zhang <chao.b.zhang@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
> Reviewed-by: Liming Gao <liming.gao@intel.com>
> ---
> 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\\"
> +#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
next prev parent reply other threads:[~2016-10-25 23:26 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 [this message]
2016-10-26 0:42 ` Yao, Jiewen
2016-10-26 1:50 ` Yao, Jiewen
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=E92EE9817A31E24EB0585FDF735412F56483AECC@ORSMSX113.amr.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