[PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.


Yao, Jiewen
 

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

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


Michael D Kinney
 

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zeng, Star <star.zeng@...>; Kinney, Michael
D <michael.d.kinney@...>; Gao, Liming <liming.gao@...>; Zhang, Chao B
<chao.b.zhang@...>
Subject: [PATCH 17/45] 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@...>
Cc: Star Zeng <star.zeng@...>
Cc: Michael D Kinney <michael.d.kinney@...>
Cc: Liming Gao <liming.gao@...>
Cc: Chao Zhang <chao.b.zhang@...>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Yao, Jiewen
 

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...>; edk2-devel@...; Kinney, Michael D <michael.d.kinney@...>
Cc: Tian, Feng <feng.tian@...>; Zeng, Star <star.zeng@...>; Gao, Liming <liming.gao@...>; Zhang, Chao B <chao.b.zhang@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Ni, Ruiyu <ruiyu.ni@...>
 

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...<mailto:edk2-devel@...%3cmailto:edk2-devel@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...<mailto:jiewen.yao@...%3cmailto:jiewen.yao@...>>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Carsey, Jaben
 

I am confused.

Why is LoadOption and LoadOptionSize not working? This is specified as part of UEFI Spec (Note: Not UEFI Shell Spec) as a standard way to pass parameters to UEFI appliations. I think this should work (although it is more work than just examining argc/argv).

-Jaben

From: Ni, Ruiyu
Sent: Wednesday, September 28, 2016 11:40 PM
To: Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>; Carsey, Jaben <jaben.carsey@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...<mailto:edk2-devel@...%3cmailto:edk2-devel@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...<mailto:jiewen.yao@...%3cmailto:jiewen.yao@...>>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Ni, Ruiyu <ruiyu.ni@...>
 

Supposing user inputs "CapsuleApp.efi Parameter1 Parameter2".
There is no spec to define what the LoadOption should equal to.
If there is another UEFI Shell implementation, it could interpret the command line then sets only "Parameter1 Parameter2" into LoadOption, or sets "CapsuleApp.efi\tParameter1\tParameter2" to LoadOption, or sets "[Shell]\tCapsuleApp.efi\tParameter1\tParameter2" to LoadOption.
Because it"produces" such LoadOption, it knows how to "consume"/parse it to get the ARGVs.

So I suggest we put the CapsuleApp in ShellPkg and let it use the ShellParameter protocol.

Regards,
Ray

From: Carsey, Jaben
Sent: Friday, September 30, 2016 3:11 AM
To: Ni, Ruiyu <ruiyu.ni@...>; Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>; Carsey, Jaben <jaben.carsey@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

I am confused.

Why is LoadOption and LoadOptionSize not working? This is specified as part of UEFI Spec (Note: Not UEFI Shell Spec) as a standard way to pass parameters to UEFI appliations. I think this should work (although it is more work than just examining argc/argv).

-Jaben

From: Ni, Ruiyu
Sent: Wednesday, September 28, 2016 11:40 PM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...<mailto:edk2-devel@...%3cmailto:edk2-devel@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...<mailto:jiewen.yao@...%3cmailto:jiewen.yao@...>>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Carsey, Jaben
 

Mike Rothman,

Can we get LoadOptions and LoadOptionsSize clarified in the UEFI Spec? This seems like a simple clarification and I would argue its needed. The UEFI Shell is not the only producer of this protocol. BDS launches things (like the UEFI Shell itself) and the shell already consumes it for itself (and it works). I think it just needs clarification so people can depend on the current implementation not changing.

-Jaben

From: Ni, Ruiyu
Sent: Thursday, September 29, 2016 9:13 PM
To: Carsey, Jaben <jaben.carsey@...>; Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Supposing user inputs "CapsuleApp.efi Parameter1 Parameter2".
There is no spec to define what the LoadOption should equal to.
If there is another UEFI Shell implementation, it could interpret the command line then sets only "Parameter1 Parameter2" into LoadOption, or sets "CapsuleApp.efi\tParameter1\tParameter2" to LoadOption, or sets "[Shell]\tCapsuleApp.efi\tParameter1\tParameter2" to LoadOption.
Because it"produces" such LoadOption, it knows how to "consume"/parse it to get the ARGVs.

So I suggest we put the CapsuleApp in ShellPkg and let it use the ShellParameter protocol.

Regards,
Ray

From: Carsey, Jaben
Sent: Friday, September 30, 2016 3:11 AM
To: Ni, Ruiyu <ruiyu.ni@...<mailto:ruiyu.ni@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

I am confused.

Why is LoadOption and LoadOptionSize not working? This is specified as part of UEFI Spec (Note: Not UEFI Shell Spec) as a standard way to pass parameters to UEFI appliations. I think this should work (although it is more work than just examining argc/argv).

-Jaben

From: Ni, Ruiyu
Sent: Wednesday, September 28, 2016 11:40 PM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...<mailto:edk2-devel@...%3cmailto:edk2-devel@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...<mailto:jiewen.yao@...%3cmailto:jiewen.yao@...>>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Rothman, Michael A <michael.a.rothman@...>
 

You mean update the LoadOptions reference to refer to the EFI_LOAD_OPTION structure? Because that’s in essence what it means.

Thanks,
Mike Rothman
(迈克 罗斯曼 / माइकल रोथ्मेन् / Михаил Ротман / משה רוטמן)
רועה עיקרי של חתולים

From: Carsey, Jaben
Sent: Friday, September 30, 2016 8:31 AM
To: Ni, Ruiyu <ruiyu.ni@...>; Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...; Rothman, Michael A <michael.a.rothman@...>
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>; Carsey, Jaben <jaben.carsey@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Mike Rothman,

Can we get LoadOptions and LoadOptionsSize clarified in the UEFI Spec? This seems like a simple clarification and I would argue its needed. The UEFI Shell is not the only producer of this protocol. BDS launches things (like the UEFI Shell itself) and the shell already consumes it for itself (and it works). I think it just needs clarification so people can depend on the current implementation not changing.

-Jaben

From: Ni, Ruiyu
Sent: Thursday, September 29, 2016 9:13 PM
To: Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Supposing user inputs “CapsuleApp.efi Parameter1 Parameter2”.
There is no spec to define what the LoadOption should equal to.
If there is another UEFI Shell implementation, it could interpret the command line then sets only “Parameter1 Parameter2” into LoadOption, or sets “CapsuleApp.efi\tParameter1\tParameter2” to LoadOption, or sets “[Shell]\tCapsuleApp.efi\tParameter1\tParameter2” to LoadOption.
Because it“produces” such LoadOption, it knows how to “consume”/parse it to get the ARGVs.

So I suggest we put the CapsuleApp in ShellPkg and let it use the ShellParameter protocol.

Regards,
Ray

From: Carsey, Jaben
Sent: Friday, September 30, 2016 3:11 AM
To: Ni, Ruiyu <ruiyu.ni@...<mailto:ruiyu.ni@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

I am confused.

Why is LoadOption and LoadOptionSize not working? This is specified as part of UEFI Spec (Note: Not UEFI Shell Spec) as a standard way to pass parameters to UEFI appliations. I think this should work (although it is more work than just examining argc/argv).

-Jaben

From: Ni, Ruiyu
Sent: Wednesday, September 28, 2016 11:40 PM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...<mailto:edk2-devel@...%3cmailto:edk2-devel@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...<mailto:jiewen.yao@...%3cmailto:jiewen.yao@...>>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Carsey, Jaben
 

I don’t think that is what I meant. It’s a string and a length, not a structure.

I mean clarify the following:

1) Is the name of the binary itself in the LoadOptions string as the first option or not there at all?

2) Then clarify that all Parameters are space delimited.

From: Rothman, Michael A
Sent: Monday, October 03, 2016 11:36 AM
To: Carsey, Jaben <jaben.carsey@...>; Ni, Ruiyu <ruiyu.ni@...>; Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>; Rothman, Michael A <michael.a.rothman@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

You mean update the LoadOptions reference to refer to the EFI_LOAD_OPTION structure? Because that’s in essence what it means.

Thanks,
Mike Rothman
(迈克 罗斯曼 / माइकल रोथ्मेन् / Михаил Ротман / משה רוטמן)
רועה עיקרי של חתולים

From: Carsey, Jaben
Sent: Friday, September 30, 2016 8:31 AM
To: Ni, Ruiyu <ruiyu.ni@...<mailto:ruiyu.ni@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>; Rothman, Michael A <michael.a.rothman@...<mailto:michael.a.rothman@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Mike Rothman,

Can we get LoadOptions and LoadOptionsSize clarified in the UEFI Spec? This seems like a simple clarification and I would argue its needed. The UEFI Shell is not the only producer of this protocol. BDS launches things (like the UEFI Shell itself) and the shell already consumes it for itself (and it works). I think it just needs clarification so people can depend on the current implementation not changing.

-Jaben

From: Ni, Ruiyu
Sent: Thursday, September 29, 2016 9:13 PM
To: Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Supposing user inputs “CapsuleApp.efi Parameter1 Parameter2”.
There is no spec to define what the LoadOption should equal to.
If there is another UEFI Shell implementation, it could interpret the command line then sets only “Parameter1 Parameter2” into LoadOption, or sets “CapsuleApp.efi\tParameter1\tParameter2” to LoadOption, or sets “[Shell]\tCapsuleApp.efi\tParameter1\tParameter2” to LoadOption.
Because it“produces” such LoadOption, it knows how to “consume”/parse it to get the ARGVs.

So I suggest we put the CapsuleApp in ShellPkg and let it use the ShellParameter protocol.

Regards,
Ray

From: Carsey, Jaben
Sent: Friday, September 30, 2016 3:11 AM
To: Ni, Ruiyu <ruiyu.ni@...<mailto:ruiyu.ni@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

I am confused.

Why is LoadOption and LoadOptionSize not working? This is specified as part of UEFI Spec (Note: Not UEFI Shell Spec) as a standard way to pass parameters to UEFI appliations. I think this should work (although it is more work than just examining argc/argv).

-Jaben

From: Ni, Ruiyu
Sent: Wednesday, September 28, 2016 11:40 PM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but
The logic after that point looks incomplete.

Also, if I clear the Persist and Reset flags on the capsule,
the immediate processing of the capsule does not work.

Is there any FW code that will look for capsules on disk?

If there are incomplete features in CapsuleApp, then I think
we should remove them.

Mike

-----Original Message-----
From: Yao, Jiewen
Sent: Tuesday, September 20, 2016 11:45 PM
To: edk2-devel@...<mailto:edk2-devel@...<mailto:edk2-devel@...%3cmailto:edk2-devel@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>; Kinney, Michael
D <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>; Zhang, Chao B
<chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Subject: [PATCH 17/45] 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@...<mailto:feng.tian@...<mailto:feng.tian@...%3cmailto:feng.tian@...>>>
Cc: Star Zeng <star.zeng@...<mailto:star.zeng@...<mailto:star.zeng@...%3cmailto:star.zeng@...>>>
Cc: Michael D Kinney <michael.d.kinney@...<mailto:michael.d.kinney@...<mailto:michael.d.kinney@...%3cmailto:michael.d.kinney@...>>>
Cc: Liming Gao <liming.gao@...<mailto:liming.gao@...<mailto:liming.gao@...%3cmailto:liming.gao@...>>>
Cc: Chao Zhang <chao.b.zhang@...<mailto:chao.b.zhang@...<mailto:chao.b.zhang@...%3cmailto:chao.b.zhang@...>>>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@...<mailto:jiewen.yao@...<mailto:jiewen.yao@...%3cmailto:jiewen.yao@...>>>
---
MdeModulePkg/Application/CapsuleApp/AppSupport.c | 480 +++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 1047 ++++++++++++++++++++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 71 ++
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni | 22 +
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni | 19 +
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 840 ++++++++++++++++
6 files changed, 2479 insertions(+)

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


Ni, Ruiyu <ruiyu.ni@...>
 

Jaben,
How about moving the contents in ShellPkg\Include\Protocol\ to MdePkg\Include\Protocol\?
All industry standard protocols are defined in MdePkg, except the Shell related protocols.

Thanks/Ray

From: Carsey, Jaben
Sent: Tuesday, October 4, 2016 4:38 AM
To: Rothman, Michael A <michael.a.rothman@...>; Ni, Ruiyu <ruiyu.ni@...>; Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>; Carsey, Jaben <jaben.carsey@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

I don’t think that is what I meant. It’s a string and a length, not a structure.

I mean clarify the following:

1) Is the name of the binary itself in the LoadOptions string as the first option or not there at all?

2) Then clarify that all Parameters are space delimited.

From: Rothman, Michael A
Sent: Monday, October 03, 2016 11:36 AM
To: Carsey, Jaben <jaben.carsey@...>; Ni, Ruiyu <ruiyu.ni@...>; Yao, Jiewen <jiewen.yao@...>; Kinney, Michael D <michael.d.kinney@...>; edk2-devel@...
Cc: Tian, Feng <feng.tian@...>; Zhang, Chao B <chao.b.zhang@...>; Gao, Liming <liming.gao@...>; Zeng, Star <star.zeng@...>; Rothman, Michael A <michael.a.rothman@...>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

You mean update the LoadOptions reference to refer to the EFI_LOAD_OPTION structure? Because that’s in essence what it means.

Thanks,
Mike Rothman
(迈克 罗斯曼 / माइकल रोथ्मेन् / Михаил Ротман / משה רוטמן)
רועה עיקרי של חתולים

From: Carsey, Jaben
Sent: Friday, September 30, 2016 8:31 AM
To: Ni, Ruiyu <ruiyu.ni@...<mailto:ruiyu.ni@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>; Rothman, Michael A <michael.a.rothman@...<mailto:michael.a.rothman@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Mike Rothman,

Can we get LoadOptions and LoadOptionsSize clarified in the UEFI Spec? This seems like a simple clarification and I would argue its needed. The UEFI Shell is not the only producer of this protocol. BDS launches things (like the UEFI Shell itself) and the shell already consumes it for itself (and it works). I think it just needs clarification so people can depend on the current implementation not changing.

-Jaben

From: Ni, Ruiyu
Sent: Thursday, September 29, 2016 9:13 PM
To: Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Supposing user inputs “CapsuleApp.efi Parameter1 Parameter2”.
There is no spec to define what the LoadOption should equal to.
If there is another UEFI Shell implementation, it could interpret the command line then sets only “Parameter1 Parameter2” into LoadOption, or sets “CapsuleApp.efi\tParameter1\tParameter2” to LoadOption, or sets “[Shell]\tCapsuleApp.efi\tParameter1\tParameter2” to LoadOption.
Because it“produces” such LoadOption, it knows how to “consume”/parse it to get the ARGVs.

So I suggest we put the CapsuleApp in ShellPkg and let it use the ShellParameter protocol.

Regards,
Ray

From: Carsey, Jaben
Sent: Friday, September 30, 2016 3:11 AM
To: Ni, Ruiyu <ruiyu.ni@...<mailto:ruiyu.ni@...>>; Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

I am confused.

Why is LoadOption and LoadOptionSize not working? This is specified as part of UEFI Spec (Note: Not UEFI Shell Spec) as a standard way to pass parameters to UEFI appliations. I think this should work (although it is more work than just examining argc/argv).

-Jaben

From: Ni, Ruiyu
Sent: Wednesday, September 28, 2016 11:40 PM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Carsey, Jaben <jaben.carsey@...<mailto:jaben.carsey@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.
Importance: High

Jiewen,
The way CapsuleApp extracts the ARGV assumes UEFI Shell encodes the parameters using a certain way. But the parameter encoding way is not described in the Shell spec.
Maybe we can put the CapsuleApp in ShellPkg, then let it directly use ShellParameter protocol to get the ARGV.

Copying Jaben.

Regards,
Ray

From: edk2-devel [mailto:edk2-devel-bounces@...] On Behalf Of Yao, Jiewen
Sent: Thursday, September 29, 2016 10:37 AM
To: Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>; edk2-devel@...<mailto:edk2-devel@...>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>
Subject: Re: [edk2] [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Right. CapsuleOnDisk is not supported in BIOS yet.
I will remove it in CapsuleApp.

CapsuleApp just works as an agent to pass capsule to CapsuleDxeRuntime driver.
So it is checked by CapsuleDxeRuntime, not CapsuleApp.

Thank you
Yao Jiewen

From: Kinney, Michael D
Sent: Thursday, September 29, 2016 9:06 AM
To: Yao, Jiewen <jiewen.yao@...<mailto:jiewen.yao@...>>; edk2-devel@...<mailto:edk2-devel@...>; Kinney, Michael D <michael.d.kinney@...<mailto:michael.d.kinney@...>>
Cc: Tian, Feng <feng.tian@...<mailto:feng.tian@...>>; Zeng, Star <star.zeng@...<mailto:star.zeng@...>>; Gao, Liming <liming.gao@...<mailto:liming.gao@...>>; Zhang, Chao B <chao.b.zhang@...<mailto:chao.b.zhang@...>>
Subject: RE: [PATCH 17/45] MdeModulePkg/CapsuleApp: Add CapsuleApp application.

Jiewen,

Does the capsule on disk feature provided by this app work?

I tried it with the QuarkPlatformPkg capsule and I can get
The app to copy the capsule to an EFI System Partition, but