MdeModulePkg/CapsuleApp: Add CapsuleApp application.
This CapsuleApp can help perform capsule update in UEFI shell environment. It can also dump capsule information, capsule status variable, ESRT and FMP. Cc: Feng Tian <feng.tian@intel.com> Cc: Star Zeng <star.zeng@intel.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Chao Zhang <chao.b.zhang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiewen Yao <jiewen.yao@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Michael Kinney <michael.d.kinney@intel.com> Tested-by: Michael Kinney <michael.d.kinney@intel.com>
This commit is contained in:
448
MdeModulePkg/Application/CapsuleApp/AppSupport.c
Normal file
448
MdeModulePkg/Application/CapsuleApp/AppSupport.c
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
/** @file
|
||||||
|
A shell application that triggers capsule update process.
|
||||||
|
|
||||||
|
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
|
This program and the accompanying materials
|
||||||
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <Uefi.h>
|
||||||
|
#include <Library/BaseLib.h>
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||||
|
#include <Library/UefiLib.h>
|
||||||
|
#include <Library/PrintLib.h>
|
||||||
|
#include <Protocol/LoadedImage.h>
|
||||||
|
#include <Protocol/SimpleFileSystem.h>
|
||||||
|
#include <Protocol/ShellParameters.h>
|
||||||
|
#include <Guid/FileInfo.h>
|
||||||
|
#include <Guid/Gpt.h>
|
||||||
|
|
||||||
|
#define MAX_ARG_NUM 11
|
||||||
|
|
||||||
|
UINTN Argc;
|
||||||
|
CHAR16 **Argv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
This function parse application ARG.
|
||||||
|
|
||||||
|
@return Status
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
GetArg (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
|
||||||
|
|
||||||
|
Status = gBS->HandleProtocol (
|
||||||
|
gImageHandle,
|
||||||
|
&gEfiShellParametersProtocolGuid,
|
||||||
|
(VOID**)&ShellParameters
|
||||||
|
);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Argc = ShellParameters->Argc;
|
||||||
|
Argv = ShellParameters->Argv;
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return File System Volume containing this shell application.
|
||||||
|
|
||||||
|
@return File System Volume containing this shell application.
|
||||||
|
**/
|
||||||
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *
|
||||||
|
GetMyVol (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
|
||||||
|
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Vol;
|
||||||
|
|
||||||
|
Status = gBS->HandleProtocol (
|
||||||
|
gImageHandle,
|
||||||
|
&gEfiLoadedImageProtocolGuid,
|
||||||
|
(VOID **)&LoadedImage
|
||||||
|
);
|
||||||
|
ASSERT_EFI_ERROR (Status);
|
||||||
|
|
||||||
|
Status = gBS->HandleProtocol (
|
||||||
|
LoadedImage->DeviceHandle,
|
||||||
|
&gEfiSimpleFileSystemProtocolGuid,
|
||||||
|
(VOID **)&Vol
|
||||||
|
);
|
||||||
|
if (!EFI_ERROR (Status)) {
|
||||||
|
return Vol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read a file from this volume.
|
||||||
|
|
||||||
|
@param[in] Vol File System Volume
|
||||||
|
@param[in] FileName The file to be read.
|
||||||
|
@param[out] BufferSize The file buffer size
|
||||||
|
@param[out] 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[in] ThisVol File System Volume
|
||||||
|
@param[in] FileName The file to be read.
|
||||||
|
@param[out] BufferSize The file buffer size
|
||||||
|
@param[out] Buffer The file buffer
|
||||||
|
@param[in] 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[in] FileName The file to be read.
|
||||||
|
@param[out] BufferSize The file buffer size
|
||||||
|
@param[out] 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[in] FileName The file to be written.
|
||||||
|
@param[in] BufferSize The file buffer size
|
||||||
|
@param[in] 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();
|
||||||
|
if (Vol == NULL) {
|
||||||
|
return EFI_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
850
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
Normal file
850
MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
Normal file
@ -0,0 +1,850 @@
|
|||||||
|
/** @file
|
||||||
|
A shell application that triggers capsule update process.
|
||||||
|
|
||||||
|
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
|
This program and the accompanying materials
|
||||||
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <Uefi.h>
|
||||||
|
#include <Library/BaseLib.h>
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||||
|
#include <Library/UefiLib.h>
|
||||||
|
#include <Library/PrintLib.h>
|
||||||
|
#include <Protocol/LoadedImage.h>
|
||||||
|
#include <Protocol/SimpleFileSystem.h>
|
||||||
|
#include <Protocol/GraphicsOutput.h>
|
||||||
|
#include <Guid/FileInfo.h>
|
||||||
|
#include <Guid/Gpt.h>
|
||||||
|
#include <Guid/GlobalVariable.h>
|
||||||
|
#include <Guid/CapsuleReport.h>
|
||||||
|
#include <Guid/SystemResourceTable.h>
|
||||||
|
#include <Guid/FmpCapsule.h>
|
||||||
|
#include <IndustryStandard/WindowsUxCapsule.h>
|
||||||
|
|
||||||
|
#define CAPSULE_HEADER_SIZE 0x20
|
||||||
|
|
||||||
|
#define NESTED_CAPSULE_HEADER_SIZE SIZE_4KB
|
||||||
|
#define SYSTEM_FIRMWARE_FLAG 0x50000
|
||||||
|
#define DEVICE_FIRMWARE_FLAG 0x78010
|
||||||
|
|
||||||
|
#define EFI_CAPSULE_FROM_FILE_DIR L"\\EFI\\UpdateCapsule\\"
|
||||||
|
#define EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED 0x0000000000000004
|
||||||
|
|
||||||
|
#define MAJOR_VERSION 1
|
||||||
|
#define MINOR_VERSION 0
|
||||||
|
|
||||||
|
#define MAX_CAPSULE_NUM 10
|
||||||
|
|
||||||
|
extern UINTN Argc;
|
||||||
|
extern CHAR16 **Argv;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Define how many block descriptors we want to test with.
|
||||||
|
//
|
||||||
|
UINTN NumberOfDescriptors = 1;
|
||||||
|
UINTN CapsuleFirstIndex;
|
||||||
|
UINTN CapsuleLastIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Dump capsule information
|
||||||
|
|
||||||
|
@param[in] CapsuleName The name of the capsule image.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The capsule information is dumped.
|
||||||
|
@retval EFI_UNSUPPORTED Input parameter is not valid.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DumpCapsule (
|
||||||
|
IN CHAR16 *CapsuleName
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
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[in] FileName The file to be read.
|
||||||
|
@param[out] BufferSize The file buffer size
|
||||||
|
@param[out] 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[in] FileName The file to be written.
|
||||||
|
@param[in] BufferSize The file buffer size
|
||||||
|
@param[in] Buffer The file buffer
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Write file successfully
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
WriteFileFromBuffer (
|
||||||
|
IN CHAR16 *FileName,
|
||||||
|
IN UINTN BufferSize,
|
||||||
|
IN VOID *Buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
|
||||||
|
This function parse application ARG.
|
||||||
|
|
||||||
|
@return Status
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
GetArg (
|
||||||
|
VOID
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create UX capsule.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The capsule header is appended.
|
||||||
|
@retval EFI_UNSUPPORTED Input parameter is not valid.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
CreateBmpFmp (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CHAR16 *OutputCapsuleName;
|
||||||
|
VOID *BmpBuffer;
|
||||||
|
UINTN FileSize;
|
||||||
|
CHAR16 *BmpName;
|
||||||
|
UINT8 *FullCapsuleBuffer;
|
||||||
|
UINTN FullCapsuleBufferSize;
|
||||||
|
EFI_DISPLAY_CAPSULE *DisplayCapsule;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
|
||||||
|
|
||||||
|
Status = gBS->LocateProtocol(&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print(L"CapsuleApp: NO GOP is found.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
Print(L"Current GOP: Mode - %d, ", Gop->Mode->Mode);
|
||||||
|
Print(L"HorizontalResolution - %d, ", Gop->Mode->Info->HorizontalResolution);
|
||||||
|
Print(L"VerticalResolution - %d\n", Gop->Mode->Info->VerticalResolution);
|
||||||
|
// HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth
|
||||||
|
// VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight
|
||||||
|
|
||||||
|
if (Argc != 5) {
|
||||||
|
Print(L"CapsuleApp: Invalid Parameter.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrCmp(Argv[3], L"-O") != 0) {
|
||||||
|
Print(L"CapsuleApp: NO output capsule name.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
OutputCapsuleName = Argv[4];
|
||||||
|
|
||||||
|
BmpBuffer = NULL;
|
||||||
|
FileSize = 0;
|
||||||
|
FullCapsuleBuffer = NULL;
|
||||||
|
|
||||||
|
BmpName = Argv[2];
|
||||||
|
Status = ReadFileToBuffer(BmpName, &FileSize, &BmpBuffer);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print(L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullCapsuleBufferSize = sizeof(EFI_DISPLAY_CAPSULE) + FileSize;
|
||||||
|
FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
|
||||||
|
if (FullCapsuleBuffer == NULL) {
|
||||||
|
Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
|
||||||
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;
|
||||||
|
CopyGuid(&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);
|
||||||
|
DisplayCapsule->CapsuleHeader.HeaderSize = sizeof(DisplayCapsule->CapsuleHeader);
|
||||||
|
DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
|
||||||
|
DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
|
||||||
|
|
||||||
|
DisplayCapsule->ImagePayload.Version = 1;
|
||||||
|
DisplayCapsule->ImagePayload.Checksum = 0;
|
||||||
|
DisplayCapsule->ImagePayload.ImageType = 0; // BMP
|
||||||
|
DisplayCapsule->ImagePayload.Reserved = 0;
|
||||||
|
DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;
|
||||||
|
DisplayCapsule->ImagePayload.OffsetX = 0;
|
||||||
|
DisplayCapsule->ImagePayload.OffsetY = 0;
|
||||||
|
|
||||||
|
CopyMem((DisplayCapsule + 1), BmpBuffer, FileSize);
|
||||||
|
|
||||||
|
DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8(FullCapsuleBuffer, FullCapsuleBufferSize);
|
||||||
|
|
||||||
|
Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
|
||||||
|
Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (BmpBuffer != NULL) {
|
||||||
|
FreePool(BmpBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FullCapsuleBuffer != NULL) {
|
||||||
|
FreePool(FullCapsuleBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get ImageTypeId in the FMP capsule header.
|
||||||
|
|
||||||
|
@param[in] 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[in] 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)) {
|
||||||
|
ASSERT(Esrt != NULL);
|
||||||
|
EsrtEntry = (VOID *)(Esrt + 1);
|
||||||
|
for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {
|
||||||
|
if (CompareGuid(&EsrtEntry->FwClass, ImageTypeId)) {
|
||||||
|
return EsrtEntry->FwType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESRT_FW_TYPE_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Append a capsule header on top of current image.
|
||||||
|
This function follows Windows UEFI Firmware Update Platform document.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The capsule header is appended.
|
||||||
|
@retval EFI_UNSUPPORTED Input parameter is not valid.
|
||||||
|
@retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
CreateNestedFmp (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
CHAR16 *OutputCapsuleName;
|
||||||
|
VOID *CapsuleBuffer;
|
||||||
|
UINTN FileSize;
|
||||||
|
CHAR16 *CapsuleName;
|
||||||
|
UINT8 *FullCapsuleBuffer;
|
||||||
|
UINTN FullCapsuleBufferSize;
|
||||||
|
EFI_CAPSULE_HEADER *NestedCapsuleHeader;
|
||||||
|
EFI_GUID *ImageTypeId;
|
||||||
|
UINT32 FwType;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
if (Argc != 5) {
|
||||||
|
Print(L"CapsuleApp: Invalid Parameter.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StrCmp(Argv[3], L"-O") != 0) {
|
||||||
|
Print(L"CapsuleApp: NO output capsule name.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
OutputCapsuleName = Argv[4];
|
||||||
|
|
||||||
|
CapsuleBuffer = NULL;
|
||||||
|
FileSize = 0;
|
||||||
|
FullCapsuleBuffer = NULL;
|
||||||
|
|
||||||
|
CapsuleName = Argv[2];
|
||||||
|
Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer);
|
||||||
|
if (ImageTypeId == NULL) {
|
||||||
|
Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n");
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
FwType = GetEsrtFwType(ImageTypeId);
|
||||||
|
if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {
|
||||||
|
Print(L"CapsuleApp: Capsule FwType is invalid.\n");
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;
|
||||||
|
FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize);
|
||||||
|
if (FullCapsuleBuffer == NULL) {
|
||||||
|
Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);
|
||||||
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;
|
||||||
|
ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);
|
||||||
|
CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);
|
||||||
|
NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;
|
||||||
|
NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_DEVICEFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;
|
||||||
|
NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;
|
||||||
|
|
||||||
|
CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);
|
||||||
|
|
||||||
|
Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);
|
||||||
|
Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);
|
||||||
|
|
||||||
|
Done:
|
||||||
|
if (CapsuleBuffer != NULL) {
|
||||||
|
FreePool(CapsuleBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FullCapsuleBuffer != NULL) {
|
||||||
|
FreePool(FullCapsuleBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clear capsule status variable.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The capsule status variable is cleared.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
ClearCapsuleStatusVariable (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT32 Index;
|
||||||
|
CHAR16 CapsuleVarName[20];
|
||||||
|
CHAR16 *TempVarName;
|
||||||
|
|
||||||
|
StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
|
||||||
|
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
|
||||||
|
Index = 0;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
|
||||||
|
|
||||||
|
Status = gRT->SetVariable (
|
||||||
|
CapsuleVarName,
|
||||||
|
&gEfiCapsuleReportGuid,
|
||||||
|
EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
||||||
|
0,
|
||||||
|
(VOID *)NULL
|
||||||
|
);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
//
|
||||||
|
// There is no capsule variables, quit
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Index++;
|
||||||
|
if (Index > 0xFFFF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Build Gather list for a list of capsule images.
|
||||||
|
|
||||||
|
@param[in] CapsuleBuffer An array of pointer to capsule images
|
||||||
|
@param[in] FileSize An array of UINTN to capsule images size
|
||||||
|
@param[in] CapsuleNum The count of capsule images
|
||||||
|
@param[out] BlockDescriptors The block descriptors for the capsule images
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The block descriptors for the capsule images are constructed.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
BuildGatherList (
|
||||||
|
IN VOID **CapsuleBuffer,
|
||||||
|
IN UINTN *FileSize,
|
||||||
|
IN UINTN CapsuleNum,
|
||||||
|
OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
|
||||||
|
UINT8 *TempDataPtr;
|
||||||
|
UINTN SizeLeft;
|
||||||
|
UINTN Size;
|
||||||
|
INT32 Count;
|
||||||
|
INT32 Number;
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
TempBlockPtr = NULL;
|
||||||
|
BlockDescriptors1 = NULL;
|
||||||
|
BlockDescriptors2 = NULL;
|
||||||
|
BlockDescriptorPre = NULL;
|
||||||
|
BlockDescriptorsHeader = NULL;
|
||||||
|
|
||||||
|
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||||
|
//
|
||||||
|
// Allocate memory for the descriptors.
|
||||||
|
//
|
||||||
|
if (NumberOfDescriptors == 1) {
|
||||||
|
Count = 2;
|
||||||
|
} else {
|
||||||
|
Count = (INT32)(NumberOfDescriptors + 2) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
|
||||||
|
BlockDescriptors1 = AllocateRuntimeZeroPool (Size);
|
||||||
|
if (BlockDescriptors1 == NULL) {
|
||||||
|
Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
|
||||||
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
|
goto ERREXIT;
|
||||||
|
} else {
|
||||||
|
Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1);
|
||||||
|
Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer, FileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Record descirptor header
|
||||||
|
//
|
||||||
|
if (Index == 0) {
|
||||||
|
BlockDescriptorsHeader = BlockDescriptors1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BlockDescriptorPre != NULL) {
|
||||||
|
BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1;
|
||||||
|
BlockDescriptorPre->Length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill them in
|
||||||
|
//
|
||||||
|
TempBlockPtr = BlockDescriptors1;
|
||||||
|
TempDataPtr = CapsuleBuffer[Index];
|
||||||
|
SizeLeft = FileSize[Index];
|
||||||
|
for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {
|
||||||
|
//
|
||||||
|
// Divide remaining data in half
|
||||||
|
//
|
||||||
|
if (NumberOfDescriptors != 1) {
|
||||||
|
if (SizeLeft == 1) {
|
||||||
|
Size = 1;
|
||||||
|
} else {
|
||||||
|
Size = SizeLeft / 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Size = SizeLeft;
|
||||||
|
}
|
||||||
|
TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
|
||||||
|
TempBlockPtr->Length = Size;
|
||||||
|
Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
|
||||||
|
SizeLeft -= Size;
|
||||||
|
TempDataPtr += Size;
|
||||||
|
TempBlockPtr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocate the second list, point the first block's last entry to point
|
||||||
|
// to this one, and fill this one in. Worst case is that the previous
|
||||||
|
// list only had one element that pointed here, so we need at least two
|
||||||
|
// elements -- one to point to all the data, another to terminate the list.
|
||||||
|
//
|
||||||
|
if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {
|
||||||
|
Count = (INT32)(NumberOfDescriptors + 2) - Count;
|
||||||
|
if (Count == 1) {
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);
|
||||||
|
BlockDescriptors2 = AllocateRuntimeZeroPool (Size);
|
||||||
|
if (BlockDescriptors2 == NULL) {
|
||||||
|
Print (L"CapsuleApp: failed to allocate memory for descriptors\n");
|
||||||
|
Status = EFI_OUT_OF_RESOURCES;
|
||||||
|
goto ERREXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Point the first list's last element to point to this second list.
|
||||||
|
//
|
||||||
|
TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2;
|
||||||
|
|
||||||
|
TempBlockPtr->Length = 0;
|
||||||
|
TempBlockPtr = BlockDescriptors2;
|
||||||
|
for (Number = 0; Number < Count - 1; Number++) {
|
||||||
|
//
|
||||||
|
// If second-to-last one, then dump rest to this element
|
||||||
|
//
|
||||||
|
if (Number == (Count - 2)) {
|
||||||
|
Size = SizeLeft;
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Divide remaining data in half
|
||||||
|
//
|
||||||
|
if (SizeLeft == 1) {
|
||||||
|
Size = 1;
|
||||||
|
} else {
|
||||||
|
Size = SizeLeft / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;
|
||||||
|
TempBlockPtr->Length = Size;
|
||||||
|
Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size);
|
||||||
|
SizeLeft -= Size;
|
||||||
|
TempDataPtr += Size;
|
||||||
|
TempBlockPtr++;
|
||||||
|
if (SizeLeft == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockDescriptorPre = TempBlockPtr;
|
||||||
|
BlockDescriptors1 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Null-terminate.
|
||||||
|
//
|
||||||
|
if (TempBlockPtr != NULL) {
|
||||||
|
TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;
|
||||||
|
TempBlockPtr->Length = 0;
|
||||||
|
*BlockDescriptors = BlockDescriptorsHeader;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
|
||||||
|
ERREXIT:
|
||||||
|
if (BlockDescriptors1 != NULL) {
|
||||||
|
FreePool(BlockDescriptors1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BlockDescriptors2 != NULL) {
|
||||||
|
FreePool(BlockDescriptors2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Clear the Gather list for a list of capsule images.
|
||||||
|
|
||||||
|
@param[in] BlockDescriptors The block descriptors for the capsule images
|
||||||
|
@param[in] CapsuleNum The count of capsule images
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
CleanGatherList (
|
||||||
|
IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,
|
||||||
|
IN UINTN CapsuleNum
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
if (BlockDescriptors != NULL) {
|
||||||
|
TempBlockPtr1 = BlockDescriptors;
|
||||||
|
while (1){
|
||||||
|
TempBlockPtr = TempBlockPtr1;
|
||||||
|
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||||
|
if (TempBlockPtr[Index].Length == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TempBlockPtr2 = (VOID *) ((UINTN) TempBlockPtr->Union.ContinuationPointer);
|
||||||
|
FreePool(TempBlockPtr1);
|
||||||
|
TempBlockPtr1 = TempBlockPtr2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Print APP usage.
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
PrintUsage (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Print(L"CapsuleApp: usage\n");
|
||||||
|
Print(L" CapsuleApp <Capsule...>\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 <Capsule>\n");
|
||||||
|
Print(L"Parameter:\n");
|
||||||
|
Print(L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
|
||||||
|
Print(L" which is defined in UEFI specification.\n");
|
||||||
|
Print(L" -C: Clear capsule report variable (EFI_CAPSULE_RPORT_GUID),\n");
|
||||||
|
Print(L" which is defined in UEFI specification.\n");
|
||||||
|
Print(L" -P: Dump UEFI FMP protocol info.\n");
|
||||||
|
Print(L" -E: Dump UEFI ESRT table info.\n");
|
||||||
|
Print(L" -G: Convert a BMP file to be a UX capsule,\n");
|
||||||
|
Print(L" according to Windows Firmware Update document\n");
|
||||||
|
Print(L" -N: Append a Capsule Header to an existing capsule image,\n");
|
||||||
|
Print(L" according to Windows Firmware Update document\n");
|
||||||
|
Print(L" -O: Output new Capsule file name\n");
|
||||||
|
Print(L" -D: Dump Capsule image header information and FMP header information,\n");
|
||||||
|
Print(L" if it is an FMP capsule.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Update Capsule image.
|
||||||
|
|
||||||
|
@param[in] ImageHandle The image handle.
|
||||||
|
@param[in] SystemTable The system table.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS Command completed successfully.
|
||||||
|
@retval EFI_INVALID_PARAMETER Command usage error.
|
||||||
|
@retval EFI_NOT_FOUND The input file can't be found.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
EFIAPI
|
||||||
|
UefiMain (
|
||||||
|
IN EFI_HANDLE ImageHandle,
|
||||||
|
IN EFI_SYSTEM_TABLE *SystemTable
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINTN FileSize[MAX_CAPSULE_NUM];
|
||||||
|
VOID *CapsuleBuffer[MAX_CAPSULE_NUM];
|
||||||
|
EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
|
||||||
|
EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
|
||||||
|
UINT64 MaxCapsuleSize;
|
||||||
|
EFI_RESET_TYPE ResetType;
|
||||||
|
BOOLEAN NeedReset;
|
||||||
|
CHAR16 *CapsuleName;
|
||||||
|
UINTN CapsuleNum;
|
||||||
|
UINTN Index;
|
||||||
|
|
||||||
|
Status = GetArg();
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print(L"Please use UEFI SHELL to run this application!\n", Status);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
if (Argc < 2) {
|
||||||
|
PrintUsage();
|
||||||
|
return EFI_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-D") == 0) {
|
||||||
|
Status = DumpCapsule(Argv[2]);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-G") == 0) {
|
||||||
|
Status = CreateBmpFmp();
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-N") == 0) {
|
||||||
|
Status = CreateNestedFmp();
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-S") == 0) {
|
||||||
|
Status = DmpCapsuleStatusVariable();
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-C") == 0) {
|
||||||
|
Status = ClearCapsuleStatusVariable();
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-P") == 0) {
|
||||||
|
DumpFmpData();
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
if (StrCmp(Argv[1], L"-E") == 0) {
|
||||||
|
DumpEsrtData();
|
||||||
|
return EFI_SUCCESS;
|
||||||
|
}
|
||||||
|
CapsuleFirstIndex = 1;
|
||||||
|
CapsuleLastIndex = Argc - 1;
|
||||||
|
CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
|
||||||
|
|
||||||
|
if (CapsuleFirstIndex > CapsuleLastIndex) {
|
||||||
|
Print(L"CapsuleApp: NO capsule image.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
if (CapsuleNum > MAX_CAPSULE_NUM) {
|
||||||
|
Print(L"CapsuleApp: Too many capsule images.\n");
|
||||||
|
return EFI_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
|
||||||
|
ZeroMem(&FileSize, sizeof(FileSize));
|
||||||
|
BlockDescriptors = NULL;
|
||||||
|
|
||||||
|
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||||
|
CapsuleName = Argv[CapsuleFirstIndex + Index];
|
||||||
|
Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Every capsule use 2 descriptor 1 for data 1 for end
|
||||||
|
//
|
||||||
|
Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Call the runtime service capsule.
|
||||||
|
//
|
||||||
|
NeedReset = FALSE;
|
||||||
|
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||||
|
CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index];
|
||||||
|
if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {
|
||||||
|
NeedReset = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CapsuleHeaderArray[CapsuleNum] = NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Inquire platform capability of UpdateCapsule.
|
||||||
|
//
|
||||||
|
Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||||
|
if (FileSize[Index] > MaxCapsuleSize) {
|
||||||
|
Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
|
||||||
|
Status = EFI_UNSUPPORTED;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check whether the input capsule image has the flag of persist across system reset.
|
||||||
|
//
|
||||||
|
if (NeedReset) {
|
||||||
|
Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
|
||||||
|
if (Status != EFI_SUCCESS) {
|
||||||
|
Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// For capsule who has reset flag, after calling UpdateCapsule service,triger a
|
||||||
|
// system reset to process capsule persist across a system reset.
|
||||||
|
//
|
||||||
|
gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// For capsule who has no reset flag, only call UpdateCapsule Service without a
|
||||||
|
// system reset. The service will process the capsule immediately.
|
||||||
|
//
|
||||||
|
Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors);
|
||||||
|
if (Status != EFI_SUCCESS) {
|
||||||
|
Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
|
||||||
|
Done:
|
||||||
|
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||||
|
if (CapsuleBuffer[Index] != NULL) {
|
||||||
|
FreePool (CapsuleBuffer[Index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CleanGatherList(BlockDescriptors, CapsuleNum);
|
||||||
|
|
||||||
|
return Status;
|
||||||
|
}
|
71
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
Normal file
71
MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
## @file
|
||||||
|
# A shell application that triggers capsule update process.
|
||||||
|
#
|
||||||
|
# This application can trigger capsule update process. It can also
|
||||||
|
# generate capsule image, or dump capsule variable information.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
|
# This program and the accompanying materials
|
||||||
|
# are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
# which accompanies this distribution. The full text of the license may be found at
|
||||||
|
# http://opensource.org/licenses/bsd-license.php
|
||||||
|
#
|
||||||
|
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
#
|
||||||
|
##
|
||||||
|
|
||||||
|
[Defines]
|
||||||
|
INF_VERSION = 0x00010006
|
||||||
|
BASE_NAME = CapsuleApp
|
||||||
|
MODULE_UNI_FILE = CapsuleApp.uni
|
||||||
|
FILE_GUID = 4CEF31DA-8682-4274-9CC4-AEE7516A5E7B
|
||||||
|
MODULE_TYPE = UEFI_APPLICATION
|
||||||
|
VERSION_STRING = 1.0
|
||||||
|
ENTRY_POINT = UefiMain
|
||||||
|
|
||||||
|
#
|
||||||
|
# The following information is for reference only and not required by the build tools.
|
||||||
|
#
|
||||||
|
# VALID_ARCHITECTURES = IA32 X64
|
||||||
|
#
|
||||||
|
|
||||||
|
[Sources]
|
||||||
|
CapsuleApp.c
|
||||||
|
CapsuleDump.c
|
||||||
|
AppSupport.c
|
||||||
|
|
||||||
|
[Packages]
|
||||||
|
MdePkg/MdePkg.dec
|
||||||
|
MdeModulePkg/MdeModulePkg.dec
|
||||||
|
|
||||||
|
[Guids]
|
||||||
|
gEfiFileInfoGuid
|
||||||
|
gEfiPartTypeSystemPartGuid
|
||||||
|
gEfiGlobalVariableGuid
|
||||||
|
gEfiCapsuleReportGuid
|
||||||
|
gEfiFmpCapsuleGuid
|
||||||
|
gWindowsUxCapsuleGuid
|
||||||
|
gEfiCertTypeRsa2048Sha256Guid
|
||||||
|
gEfiCertPkcs7Guid
|
||||||
|
gEfiSystemResourceTableGuid
|
||||||
|
|
||||||
|
[Protocols]
|
||||||
|
gEfiLoadedImageProtocolGuid
|
||||||
|
gEfiSimpleFileSystemProtocolGuid
|
||||||
|
gEfiGraphicsOutputProtocolGuid
|
||||||
|
gEfiFirmwareManagementProtocolGuid
|
||||||
|
gEfiShellParametersProtocolGuid
|
||||||
|
|
||||||
|
[LibraryClasses]
|
||||||
|
BaseLib
|
||||||
|
UefiApplicationEntryPoint
|
||||||
|
DebugLib
|
||||||
|
MemoryAllocationLib
|
||||||
|
UefiBootServicesTableLib
|
||||||
|
UefiRuntimeServicesTableLib
|
||||||
|
UefiLib
|
||||||
|
PrintLib
|
||||||
|
|
||||||
|
[UserExtensions.TianoCore."ExtraFiles"]
|
||||||
|
CapsuleAppExtra.uni
|
22
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
Normal file
22
MdeModulePkg/Application/CapsuleApp/CapsuleApp.uni
Normal file
@ -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."
|
||||||
|
|
19
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
Normal file
19
MdeModulePkg/Application/CapsuleApp/CapsuleAppExtra.uni
Normal file
@ -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"
|
||||||
|
|
||||||
|
|
738
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
Normal file
738
MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
Normal file
@ -0,0 +1,738 @@
|
|||||||
|
/** @file
|
||||||
|
Dump Capsule image information.
|
||||||
|
|
||||||
|
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
|
||||||
|
This program and the accompanying materials
|
||||||
|
are licensed and made available under the terms and conditions of the BSD License
|
||||||
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
http://opensource.org/licenses/bsd-license.php
|
||||||
|
|
||||||
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||||
|
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include <PiDxe.h>
|
||||||
|
#include <Library/BaseLib.h>
|
||||||
|
#include <Library/DebugLib.h>
|
||||||
|
#include <Library/BaseMemoryLib.h>
|
||||||
|
#include <Library/MemoryAllocationLib.h>
|
||||||
|
#include <Library/UefiBootServicesTableLib.h>
|
||||||
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||||
|
#include <Library/UefiLib.h>
|
||||||
|
#include <Library/PrintLib.h>
|
||||||
|
#include <Protocol/FirmwareManagement.h>
|
||||||
|
#include <Guid/ImageAuthentication.h>
|
||||||
|
#include <Guid/CapsuleReport.h>
|
||||||
|
#include <Guid/SystemResourceTable.h>
|
||||||
|
#include <Guid/FmpCapsule.h>
|
||||||
|
#include <IndustryStandard/WindowsUxCapsule.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
Read a file.
|
||||||
|
|
||||||
|
@param[in] FileName The file to be read.
|
||||||
|
@param[in] BufferSize The file buffer size
|
||||||
|
@param[in] 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
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Dump UX capsule information.
|
||||||
|
|
||||||
|
@param[in] 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[in] Image The FMP capsule image
|
||||||
|
@param[in] ImageSize The size of the FMP capsule image in bytes.
|
||||||
|
|
||||||
|
@return the size of FMP authentication.
|
||||||
|
**/
|
||||||
|
UINTN
|
||||||
|
DumpImageAuthentication (
|
||||||
|
IN VOID *Image,
|
||||||
|
IN UINTN ImageSize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_FIRMWARE_IMAGE_AUTHENTICATION *ImageAuthentication;
|
||||||
|
|
||||||
|
ImageAuthentication = Image;
|
||||||
|
if (CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertPkcs7Guid) ||
|
||||||
|
CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {
|
||||||
|
Print(L"[ImageAuthentication]\n");
|
||||||
|
Print(L" MonotonicCount - 0x%lx\n", ImageAuthentication->MonotonicCount);
|
||||||
|
Print(L"WIN_CERTIFICATE:\n");
|
||||||
|
Print(L" dwLength - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.dwLength);
|
||||||
|
Print(L" wRevision - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wRevision);
|
||||||
|
Print(L" wCertificateType - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wCertificateType);
|
||||||
|
Print(L" CertType - %g\n", &ImageAuthentication->AuthInfo.CertType);
|
||||||
|
return sizeof(ImageAuthentication->MonotonicCount) + ImageAuthentication->AuthInfo.Hdr.dwLength;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Dump a non-nested FMP capsule.
|
||||||
|
|
||||||
|
@param[in] CapsuleHeader A pointer to CapsuleHeader
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
DumpFmpCapsule (
|
||||||
|
IN EFI_CAPSULE_HEADER *CapsuleHeader
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
|
||||||
|
UINT64 *ItemOffsetList;
|
||||||
|
UINTN Index;
|
||||||
|
UINTN Count;
|
||||||
|
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader;
|
||||||
|
|
||||||
|
Print(L"[FmpCapusule]\n");
|
||||||
|
Print(L"CapsuleHeader:\n");
|
||||||
|
Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);
|
||||||
|
Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);
|
||||||
|
Print(L" Flags - 0x%x\n", CapsuleHeader->Flags);
|
||||||
|
Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
|
||||||
|
|
||||||
|
FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
|
||||||
|
ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
|
||||||
|
Print(L"FmpHeader:\n");
|
||||||
|
Print(L" Version - 0x%x\n", FmpCapsuleHeader->Version);
|
||||||
|
Print(L" EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount);
|
||||||
|
Print(L" PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount);
|
||||||
|
Count = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
|
||||||
|
for (Index = 0; Index < Count; Index++) {
|
||||||
|
Print(L" Offset[%d] - 0x%x\n", Index, ItemOffsetList[Index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) {
|
||||||
|
Print(L"FmpPayload[%d] ImageHeader:\n", Index);
|
||||||
|
FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
|
||||||
|
Print(L" Version - 0x%x\n", FmpImageHeader->Version);
|
||||||
|
Print(L" UpdateImageTypeId - %g\n", &FmpImageHeader->UpdateImageTypeId);
|
||||||
|
Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateImageIndex);
|
||||||
|
Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateImageSize);
|
||||||
|
Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize);
|
||||||
|
if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
|
||||||
|
Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return if there is a FMP header below capsule header.
|
||||||
|
|
||||||
|
@param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
|
||||||
|
|
||||||
|
@retval TRUE There is a FMP header below capsule header.
|
||||||
|
@retval FALSE There is not a FMP header below capsule header
|
||||||
|
**/
|
||||||
|
BOOLEAN
|
||||||
|
IsNestedFmpCapsule (
|
||||||
|
IN EFI_CAPSULE_HEADER *CapsuleHeader
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
EFI_SYSTEM_RESOURCE_TABLE *Esrt;
|
||||||
|
EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
|
||||||
|
UINTN Index;
|
||||||
|
BOOLEAN EsrtGuidFound;
|
||||||
|
EFI_CAPSULE_HEADER *NestedCapsuleHeader;
|
||||||
|
UINTN NestedCapsuleSize;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check ESRT
|
||||||
|
//
|
||||||
|
EsrtGuidFound = FALSE;
|
||||||
|
Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt);
|
||||||
|
if (!EFI_ERROR(Status)) {
|
||||||
|
ASSERT (Esrt != NULL);
|
||||||
|
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
|
||||||
|
|
||||||
|
@param[in] CapsuleName The name of the capsule image.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The capsule information is dumped.
|
||||||
|
@retval EFI_UNSUPPORTED Input parameter is not valid.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DumpCapsule (
|
||||||
|
IN CHAR16 *CapsuleName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
VOID *Buffer;
|
||||||
|
UINTN FileSize;
|
||||||
|
EFI_CAPSULE_HEADER *CapsuleHeader;
|
||||||
|
EFI_STATUS Status;
|
||||||
|
|
||||||
|
Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer);
|
||||||
|
if (EFI_ERROR(Status)) {
|
||||||
|
Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
CapsuleHeader = Buffer;
|
||||||
|
if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
|
||||||
|
DumpUxCapsule(CapsuleHeader);
|
||||||
|
Status = EFI_SUCCESS;
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
|
||||||
|
DumpFmpCapsule(CapsuleHeader);
|
||||||
|
}
|
||||||
|
if (IsNestedFmpCapsule(CapsuleHeader)) {
|
||||||
|
Print(L"[NestedCapusule]\n");
|
||||||
|
Print(L"CapsuleHeader:\n");
|
||||||
|
Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);
|
||||||
|
Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);
|
||||||
|
Print(L" Flags - 0x%x\n", CapsuleHeader->Flags);
|
||||||
|
Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
|
||||||
|
DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
FreePool(Buffer);
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Dump capsule status variable.
|
||||||
|
|
||||||
|
@retval EFI_SUCCESS The capsule status variable is dumped.
|
||||||
|
@retval EFI_UNSUPPORTED Input parameter is not valid.
|
||||||
|
**/
|
||||||
|
EFI_STATUS
|
||||||
|
DmpCapsuleStatusVariable (
|
||||||
|
VOID
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EFI_STATUS Status;
|
||||||
|
UINT32 Index;
|
||||||
|
CHAR16 CapsuleVarName[20];
|
||||||
|
CHAR16 *TempVarName;
|
||||||
|
EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult;
|
||||||
|
EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp;
|
||||||
|
UINTN CapsuleFileNameSize;
|
||||||
|
CHAR16 CapsuleIndexData[12];
|
||||||
|
CHAR16 *CapsuleIndex;
|
||||||
|
|
||||||
|
Status = GetVariable2(
|
||||||
|
L"CapsuleMax",
|
||||||
|
&gEfiCapsuleReportGuid,
|
||||||
|
(VOID **)&CapsuleIndex,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (!EFI_ERROR(Status)) {
|
||||||
|
CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));
|
||||||
|
CapsuleIndexData[11] = 0;
|
||||||
|
Print(L"CapsuleMax - %s\n", CapsuleIndexData);
|
||||||
|
FreePool(CapsuleIndex);
|
||||||
|
}
|
||||||
|
Status = GetVariable2(
|
||||||
|
L"CapsuleLast",
|
||||||
|
&gEfiCapsuleReportGuid,
|
||||||
|
(VOID **)&CapsuleIndex,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (!EFI_ERROR(Status)) {
|
||||||
|
CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));
|
||||||
|
CapsuleIndexData[11] = 0;
|
||||||
|
Print(L"CapsuleLast - %s\n", CapsuleIndexData);
|
||||||
|
FreePool(CapsuleIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule");
|
||||||
|
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
|
||||||
|
Index = 0;
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index);
|
||||||
|
|
||||||
|
Status = GetVariable2 (
|
||||||
|
CapsuleVarName,
|
||||||
|
&gEfiCapsuleReportGuid,
|
||||||
|
(VOID **) &CapsuleResult,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
if (Status == EFI_NOT_FOUND) {
|
||||||
|
break;
|
||||||
|
} else if (EFI_ERROR(Status)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ASSERT (CapsuleResult != NULL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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[in] 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[in] 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[in] 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[in] Esrt ESRT table
|
||||||
|
**/
|
||||||
|
VOID
|
||||||
|
DumpEsrt (
|
||||||
|
IN EFI_SYSTEM_RESOURCE_TABLE *Esrt
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UINTN Index;
|
||||||
|
EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
|
||||||
|
|
||||||
|
if (Esrt == NULL) {
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
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[in] ImageInfoSize The size of ImageInfo, in bytes.
|
||||||
|
@param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
||||||
|
@param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
||||||
|
@param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
|
||||||
|
@param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
|
||||||
|
@param[in] PackageVersion The version of package.
|
||||||
|
@param[in] 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[in] PackageVersion The version of package.
|
||||||
|
@param[in] PackageVersionName The version name of package.
|
||||||
|
@param[in] PackageVersionNameMaxLen The maximum length of PackageVersionName.
|
||||||
|
@param[in] AttributesSupported Package attributes that are supported by this device.
|
||||||
|
@param[in] 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);
|
||||||
|
}
|
Reference in New Issue
Block a user