mirror of https://github.com/acidanthera/audk.git
MdeModulePkg/CapsuleApp: Enhance CapsuleApp to support Capsule-on-Disk
BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=1482 CapsuleApp is used for trigger capsule update. Add -OD option in CapsuleApp to support doing capsule update via storage. Add -F and -L options to support dumping information feature. Finish unit test for -F and -L options. Already verify this feature on Denlow platform, success to update capsule via hard disk with -OD option. Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Hao Wu <hao.a.wu@intel.com> Cc: Zhang Chao B <chao.b.zhang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Chen A Chen <chen.a.chen@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
This commit is contained in:
parent
d67ade0994
commit
9747329114
|
@ -1,7 +1,7 @@
|
|||
/** @file
|
||||
A shell application that triggers capsule update process.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2016 - 2019, 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
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include <Library/PrintLib.h>
|
||||
#include <Library/BmpSupportLib.h>
|
||||
#include <Protocol/GraphicsOutput.h>
|
||||
#include <Guid/GlobalVariable.h>
|
||||
#include <Guid/CapsuleReport.h>
|
||||
#include <Guid/SystemResourceTable.h>
|
||||
#include <Guid/FmpCapsule.h>
|
||||
|
@ -105,6 +106,46 @@ DumpEsrtData (
|
|||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Dump Provisioned Capsule.
|
||||
|
||||
@param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
|
||||
**/
|
||||
VOID
|
||||
DumpProvisionedCapsule (
|
||||
IN BOOLEAN DumpCapsuleInfo
|
||||
);
|
||||
|
||||
/**
|
||||
Dump all EFI System Partition.
|
||||
**/
|
||||
VOID
|
||||
DumpAllEfiSysPartition (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Process Capsule On Disk.
|
||||
|
||||
@param[in] CapsuleBuffer An array of pointer to capsule images
|
||||
@param[in] CapsuleBufferSize An array of UINTN to capsule images size
|
||||
@param[in] FilePath An array of capsule images file path
|
||||
@param[in] Map File system mapping string
|
||||
@param[in] CapsuleNum The count of capsule images
|
||||
|
||||
@retval EFI_SUCCESS Capsule on disk success.
|
||||
@retval others Capsule on disk fail.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
ProcessCapsuleOnDisk (
|
||||
IN VOID **CapsuleBuffer,
|
||||
IN UINTN *CapsuleBufferSize,
|
||||
IN CHAR16 **FilePath,
|
||||
IN CHAR16 *Map,
|
||||
IN UINTN CapsuleNum
|
||||
);
|
||||
|
||||
/**
|
||||
Read a file.
|
||||
|
||||
|
@ -799,19 +840,22 @@ PrintUsage (
|
|||
)
|
||||
{
|
||||
Print(L"CapsuleApp: usage\n");
|
||||
Print(L" CapsuleApp <Capsule...> [-NR]\n");
|
||||
Print(L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
|
||||
Print(L" CapsuleApp -S\n");
|
||||
Print(L" CapsuleApp -C\n");
|
||||
Print(L" CapsuleApp -P\n");
|
||||
Print(L" CapsuleApp -E\n");
|
||||
Print(L" CapsuleApp -L\n");
|
||||
Print(L" CapsuleApp -L INFO\n");
|
||||
Print(L" CapsuleApp -F\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" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
|
||||
Print(L"Parameter:\n");
|
||||
Print(L" -NR: No reset will be triggered for the capsule with\n");
|
||||
Print(L" CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without\n");
|
||||
Print(L" CAPSULE_FLAGS_INITIATE_RESET.\n");
|
||||
Print(L" -NR: No reset will be triggered for the capsule\n");
|
||||
Print(L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");
|
||||
Print(L" -OD: Delivery of Capsules via file on Mass Storage device.");
|
||||
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_REPORT_GUID),\n");
|
||||
|
@ -820,6 +864,8 @@ PrintUsage (
|
|||
Print(L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");
|
||||
Print(L" option is used.\n");
|
||||
Print(L" -E: Dump UEFI ESRT table info.\n");
|
||||
Print(L" -L: Dump provisioned capsule image information.\n");
|
||||
Print(L" -F: Dump all EFI System Partition.\n");
|
||||
Print(L" -G: Convert a BMP file to be an UX capsule,\n");
|
||||
Print(L" according to Windows Firmware Update document\n");
|
||||
Print(L" -N: Append a Capsule Header to an existing FMP capsule image\n");
|
||||
|
@ -851,7 +897,7 @@ UefiMain (
|
|||
{
|
||||
EFI_STATUS Status;
|
||||
RETURN_STATUS RStatus;
|
||||
UINTN FileSize[MAX_CAPSULE_NUM];
|
||||
UINTN CapsuleBufferSize[MAX_CAPSULE_NUM];
|
||||
VOID *CapsuleBuffer[MAX_CAPSULE_NUM];
|
||||
EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
|
||||
EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
|
||||
|
@ -859,12 +905,20 @@ UefiMain (
|
|||
EFI_RESET_TYPE ResetType;
|
||||
BOOLEAN NeedReset;
|
||||
BOOLEAN NoReset;
|
||||
BOOLEAN CapsuleOnDisk;
|
||||
CHAR16 *CapsuleName;
|
||||
CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];
|
||||
CHAR16 *MapFsStr;
|
||||
UINTN CapsuleNum;
|
||||
UINTN Index;
|
||||
UINTN ParaOdIndex;
|
||||
UINTN ParaNrIndex;
|
||||
EFI_GUID ImageTypeId;
|
||||
UINTN ImageIndex;
|
||||
|
||||
MapFsStr = NULL;
|
||||
CapsuleNum = 0;
|
||||
|
||||
Status = GetArg();
|
||||
if (EFI_ERROR(Status)) {
|
||||
Print(L"Please use UEFI SHELL to run this application!\n", Status);
|
||||
|
@ -936,6 +990,20 @@ UefiMain (
|
|||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if (StrCmp(Argv[1], L"-L") == 0) {
|
||||
if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {
|
||||
DumpProvisionedCapsule(TRUE);
|
||||
} else {
|
||||
DumpProvisionedCapsule(FALSE);
|
||||
}
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if (StrCmp(Argv[1], L"-F") == 0) {
|
||||
DumpAllEfiSysPartition();
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
if (Argv[1][0] == L'-') {
|
||||
Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);
|
||||
return EFI_UNSUPPORTED;
|
||||
|
@ -943,12 +1011,56 @@ UefiMain (
|
|||
|
||||
CapsuleFirstIndex = 1;
|
||||
NoReset = FALSE;
|
||||
if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) {
|
||||
NoReset = TRUE;
|
||||
CapsuleLastIndex = Argc - 2;
|
||||
} else {
|
||||
CapsuleLastIndex = Argc - 1;
|
||||
CapsuleOnDisk = FALSE;
|
||||
ParaOdIndex = 0;
|
||||
ParaNrIndex = 0;
|
||||
|
||||
for (Index = 1; Index < Argc; Index++) {
|
||||
if (StrCmp(Argv[Index], L"-OD") == 0) {
|
||||
ParaOdIndex = Index;
|
||||
CapsuleOnDisk = TRUE;
|
||||
} else if (StrCmp(Argv[Index], L"-NR") == 0) {
|
||||
ParaNrIndex = Index;
|
||||
NoReset = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (ParaOdIndex != 0) {
|
||||
if (ParaOdIndex == Argc - 1) {
|
||||
MapFsStr = NULL;
|
||||
} else if (ParaOdIndex == Argc - 2) {
|
||||
MapFsStr = Argv[Argc-1];
|
||||
} else {
|
||||
Print (L"CapsuleApp: Invalid Position for -OD Options\n");
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (ParaNrIndex != 0) {
|
||||
if (ParaNrIndex + 1 == ParaOdIndex) {
|
||||
CapsuleLastIndex = ParaNrIndex - 1;
|
||||
} else {
|
||||
Print (L"CapsuleApp: Invalid Position for -NR Options\n");
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
} else {
|
||||
CapsuleLastIndex = ParaOdIndex - 1;
|
||||
}
|
||||
} else {
|
||||
if (ParaNrIndex != 0) {
|
||||
if (ParaNrIndex == Argc -1) {
|
||||
CapsuleLastIndex = ParaNrIndex - 1;
|
||||
} else {
|
||||
Print (L"CapsuleApp: Invalid Position for -NR Options\n");
|
||||
Status = EFI_INVALID_PARAMETER;
|
||||
goto Done;
|
||||
}
|
||||
} else {
|
||||
CapsuleLastIndex = Argc - 1;
|
||||
}
|
||||
}
|
||||
|
||||
CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
|
||||
|
||||
if (CapsuleFirstIndex > CapsuleLastIndex) {
|
||||
|
@ -961,26 +1073,27 @@ UefiMain (
|
|||
}
|
||||
|
||||
ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
|
||||
ZeroMem(&FileSize, sizeof(FileSize));
|
||||
ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));
|
||||
BlockDescriptors = NULL;
|
||||
|
||||
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||
CapsuleName = Argv[CapsuleFirstIndex + Index];
|
||||
Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]);
|
||||
Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);
|
||||
if (EFI_ERROR(Status)) {
|
||||
Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
|
||||
goto Done;
|
||||
}
|
||||
if (!IsValidCapsuleHeader (CapsuleBuffer[Index], FileSize[Index])) {
|
||||
if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {
|
||||
Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
CapsuleNames[Index] = CapsuleName;
|
||||
}
|
||||
|
||||
//
|
||||
// Every capsule use 2 descriptor 1 for data 1 for end
|
||||
//
|
||||
Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors);
|
||||
Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);
|
||||
if (EFI_ERROR(Status)) {
|
||||
goto Done;
|
||||
}
|
||||
|
@ -1007,13 +1120,30 @@ UefiMain (
|
|||
}
|
||||
|
||||
for (Index = 0; Index < CapsuleNum; Index++) {
|
||||
if (FileSize[Index] > MaxCapsuleSize) {
|
||||
if (CapsuleBufferSize[Index] > MaxCapsuleSize) {
|
||||
Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);
|
||||
Status = EFI_UNSUPPORTED;
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check whether is capsule on disk.
|
||||
//
|
||||
if (CapsuleOnDisk) {
|
||||
Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);
|
||||
if (Status != EFI_SUCCESS) {
|
||||
Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
|
||||
goto Done;
|
||||
} else {
|
||||
if (!NoReset) {
|
||||
gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
|
||||
} else {
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Check whether the input capsule image has the flag of persist across system reset.
|
||||
//
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
[Sources]
|
||||
CapsuleApp.c
|
||||
CapsuleDump.c
|
||||
CapsuleOnDisk.c
|
||||
AppSupport.c
|
||||
|
||||
[Packages]
|
||||
|
@ -40,16 +41,20 @@
|
|||
MdeModulePkg/MdeModulePkg.dec
|
||||
|
||||
[Guids]
|
||||
gEfiGlobalVariableGuid ## CONSUMES ## GUID
|
||||
gEfiCapsuleReportGuid ## CONSUMES ## GUID
|
||||
gEfiFmpCapsuleGuid ## CONSUMES ## GUID
|
||||
gWindowsUxCapsuleGuid ## CONSUMES ## GUID
|
||||
gEfiSystemResourceTableGuid ## CONSUMES ## GUID
|
||||
gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ## Variable:L"CapsuleUpdateData"
|
||||
gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES ## GUID
|
||||
|
||||
[Protocols]
|
||||
gEfiGraphicsOutputProtocolGuid ## CONSUMES
|
||||
gEfiFirmwareManagementProtocolGuid ## CONSUMES
|
||||
gEfiShellParametersProtocolGuid ## CONSUMES
|
||||
gEfiShellProtocolGuid ## CONSUMES
|
||||
gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
|
@ -61,6 +66,9 @@
|
|||
UefiLib
|
||||
PrintLib
|
||||
BmpSupportLib
|
||||
FileHandleLib
|
||||
UefiBootManagerLib
|
||||
SortLib
|
||||
|
||||
[UserExtensions.TianoCore."ExtraFiles"]
|
||||
CapsuleAppExtra.uni
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/** @file
|
||||
Dump Capsule image information.
|
||||
|
||||
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||||
Copyright (c) 2016 - 2019, 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
|
||||
|
@ -21,13 +21,26 @@
|
|||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/FileHandleLib.h>
|
||||
#include <Library/SortLib.h>
|
||||
#include <Library/UefiBootManagerLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Protocol/FirmwareManagement.h>
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <Protocol/Shell.h>
|
||||
#include <Guid/ImageAuthentication.h>
|
||||
#include <Guid/CapsuleReport.h>
|
||||
#include <Guid/SystemResourceTable.h>
|
||||
#include <Guid/FmpCapsule.h>
|
||||
#include <Guid/CapsuleVendor.h>
|
||||
#include <IndustryStandard/WindowsUxCapsule.h>
|
||||
|
||||
//
|
||||
// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
|
||||
//
|
||||
#define MAX_FILE_NAME_SIZE 522
|
||||
#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16))
|
||||
|
||||
/**
|
||||
Read a file.
|
||||
|
||||
|
@ -61,6 +74,37 @@ WriteFileFromBuffer (
|
|||
IN VOID *Buffer
|
||||
);
|
||||
|
||||
/**
|
||||
Get shell protocol.
|
||||
|
||||
@return Pointer to shell protocol.
|
||||
|
||||
**/
|
||||
EFI_SHELL_PROTOCOL *
|
||||
GetShellProtocol (
|
||||
VOID
|
||||
);
|
||||
|
||||
/**
|
||||
Get SimpleFileSystem from boot option file path.
|
||||
|
||||
@param[in] DevicePath The file path of boot option
|
||||
@param[out] FullPath The full device path of boot device
|
||||
@param[out] Fs The file system within EfiSysPartition
|
||||
|
||||
@retval EFI_SUCCESS Get file system successfully
|
||||
@retval EFI_NOT_FOUND No valid file system found
|
||||
@retval others Get file system failed
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
GetEfiSysPartitionFromBootOptionFilePath (
|
||||
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
|
||||
OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,
|
||||
OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
|
||||
);
|
||||
|
||||
/**
|
||||
Validate if it is valid capsule header
|
||||
|
||||
|
@ -123,7 +167,7 @@ DumpFmpCapsule (
|
|||
UINTN Count;
|
||||
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader;
|
||||
|
||||
Print(L"[FmpCapusule]\n");
|
||||
Print(L"[FmpCapsule]\n");
|
||||
Print(L"CapsuleHeader:\n");
|
||||
Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);
|
||||
Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);
|
||||
|
@ -504,6 +548,496 @@ DumpEsrtData (
|
|||
Print(L"\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Dump capsule information from CapsuleHeader
|
||||
|
||||
@param[in] CapsuleHeader The CapsuleHeader of the capsule image.
|
||||
|
||||
@retval EFI_SUCCESS The capsule information is dumped.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
DumpCapsuleFromBuffer (
|
||||
IN EFI_CAPSULE_HEADER *CapsuleHeader
|
||||
)
|
||||
{
|
||||
if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {
|
||||
DumpUxCapsule (CapsuleHeader);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
This routine is called to upper case given unicode string.
|
||||
|
||||
@param[in] Str String to upper case
|
||||
|
||||
@retval upper cased string after process
|
||||
|
||||
**/
|
||||
STATIC
|
||||
CHAR16 *
|
||||
UpperCaseString (
|
||||
IN CHAR16 *Str
|
||||
)
|
||||
{
|
||||
CHAR16 *Cptr;
|
||||
|
||||
for (Cptr = Str; *Cptr != L'\0'; Cptr++) {
|
||||
if (L'a' <= *Cptr && *Cptr <= L'z') {
|
||||
*Cptr = *Cptr - L'a' + L'A';
|
||||
}
|
||||
}
|
||||
|
||||
return Str;
|
||||
}
|
||||
|
||||
/**
|
||||
This routine is used to return substring before period '.' or '\0'
|
||||
Caller should respsonsible of substr space allocation & free
|
||||
|
||||
@param[in] Str String to check
|
||||
@param[out] SubStr First part of string before period or '\0'
|
||||
@param[out] SubStrLen Length of first part of string
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
GetSubStringBeforePeriod (
|
||||
IN CHAR16 *Str,
|
||||
OUT CHAR16 *SubStr,
|
||||
OUT UINTN *SubStrLen
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
|
||||
SubStr[Index] = Str[Index];
|
||||
}
|
||||
|
||||
SubStr[Index] = L'\0';
|
||||
*SubStrLen = Index;
|
||||
}
|
||||
|
||||
/**
|
||||
This routine pad the string in tail with input character.
|
||||
|
||||
@param[in] StrBuf Str buffer to be padded, should be enough room for
|
||||
@param[in] PadLen Expected padding length
|
||||
@param[in] Character Character used to pad
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
PadStrInTail (
|
||||
IN CHAR16 *StrBuf,
|
||||
IN UINTN PadLen,
|
||||
IN CHAR16 Character
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; StrBuf[Index] != L'\0'; Index++);
|
||||
|
||||
while(PadLen != 0) {
|
||||
StrBuf[Index] = Character;
|
||||
Index++;
|
||||
PadLen--;
|
||||
}
|
||||
|
||||
StrBuf[Index] = L'\0';
|
||||
}
|
||||
|
||||
/**
|
||||
This routine find the offset of the last period '.' of string. if No period exists
|
||||
function FileNameExtension is set to L'\0'
|
||||
|
||||
@param[in] FileName File name to split between last period
|
||||
@param[out] FileNameFirst First FileName before last period
|
||||
@param[out] FileNameExtension FileName after last period
|
||||
|
||||
**/
|
||||
STATIC
|
||||
VOID
|
||||
SplitFileNameExtension (
|
||||
IN CHAR16 *FileName,
|
||||
OUT CHAR16 *FileNameFirst,
|
||||
OUT CHAR16 *FileNameExtension
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
UINTN StringLen;
|
||||
|
||||
StringLen = StrLen(FileName);
|
||||
for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);
|
||||
|
||||
//
|
||||
// No period exists. No FileName Extension
|
||||
//
|
||||
if (Index == 0 && FileName[Index] != L'.') {
|
||||
FileNameExtension[0] = L'\0';
|
||||
Index = StringLen;
|
||||
} else {
|
||||
StrCpyS (FileNameExtension, MAX_FILE_NAME_LEN, &FileName[Index+1]);
|
||||
}
|
||||
|
||||
//
|
||||
// Copy First file name
|
||||
//
|
||||
StrnCpyS (FileNameFirst, MAX_FILE_NAME_LEN, FileName, Index);
|
||||
FileNameFirst[Index] = L'\0';
|
||||
}
|
||||
|
||||
/**
|
||||
The function is called by PerformQuickSort to sort file name in alphabet.
|
||||
|
||||
@param[in] Left The pointer to first buffer.
|
||||
@param[in] Right The pointer to second buffer.
|
||||
|
||||
@retval 0 Buffer1 equal to Buffer2.
|
||||
@return <0 Buffer1 is less than Buffer2.
|
||||
@return >0 Buffer1 is greater than Buffer2.
|
||||
|
||||
**/
|
||||
INTN
|
||||
EFIAPI
|
||||
CompareFileNameInAlphabet (
|
||||
IN VOID *Left,
|
||||
IN VOID *Right
|
||||
)
|
||||
{
|
||||
EFI_FILE_INFO *FileInfo1;
|
||||
EFI_FILE_INFO *FileInfo2;
|
||||
CHAR16 FileName1[MAX_FILE_NAME_SIZE];
|
||||
CHAR16 FileExtension1[MAX_FILE_NAME_SIZE];
|
||||
CHAR16 FileName2[MAX_FILE_NAME_SIZE];
|
||||
CHAR16 FileExtension2[MAX_FILE_NAME_SIZE];
|
||||
CHAR16 TempSubStr1[MAX_FILE_NAME_SIZE];
|
||||
CHAR16 TempSubStr2[MAX_FILE_NAME_SIZE];
|
||||
UINTN SubStrLen1;
|
||||
UINTN SubStrLen2;
|
||||
INTN SubStrCmpResult;
|
||||
|
||||
FileInfo1 = (EFI_FILE_INFO *) (*(UINTN *)Left);
|
||||
FileInfo2 = (EFI_FILE_INFO *) (*(UINTN *)Right);
|
||||
|
||||
SplitFileNameExtension (FileInfo1->FileName, FileName1, FileExtension1);
|
||||
SplitFileNameExtension (FileInfo2->FileName, FileName2, FileExtension2);
|
||||
|
||||
UpperCaseString (FileName1);
|
||||
UpperCaseString (FileName2);
|
||||
|
||||
GetSubStringBeforePeriod (FileName1, TempSubStr1, &SubStrLen1);
|
||||
GetSubStringBeforePeriod (FileName2, TempSubStr2, &SubStrLen2);
|
||||
|
||||
if (SubStrLen1 > SubStrLen2) {
|
||||
//
|
||||
// Substr in NewFileName is longer. Pad tail with SPACE
|
||||
//
|
||||
PadStrInTail (TempSubStr2, SubStrLen1 - SubStrLen2, L' ');
|
||||
} else if (SubStrLen1 < SubStrLen2){
|
||||
//
|
||||
// Substr in ListedFileName is longer. Pad tail with SPACE
|
||||
//
|
||||
PadStrInTail (TempSubStr1, SubStrLen2 - SubStrLen1, L' ');
|
||||
}
|
||||
|
||||
SubStrCmpResult = StrnCmp (TempSubStr1, TempSubStr2, MAX_FILE_NAME_LEN);
|
||||
if (SubStrCmpResult != 0) {
|
||||
return SubStrCmpResult;
|
||||
}
|
||||
|
||||
UpperCaseString (FileExtension1);
|
||||
UpperCaseString (FileExtension2);
|
||||
|
||||
return StrnCmp (FileExtension1, FileExtension2, MAX_FILE_NAME_LEN);
|
||||
}
|
||||
|
||||
/**
|
||||
Dump capsule information from disk.
|
||||
|
||||
@param[in] Fs The device path of disk.
|
||||
@param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
|
||||
|
||||
@retval EFI_SUCCESS The capsule information is dumped.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
DumpCapsuleFromDisk (
|
||||
IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs,
|
||||
IN BOOLEAN DumpCapsuleInfo
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_FILE *Root;
|
||||
EFI_FILE *DirHandle;
|
||||
EFI_FILE *FileHandle;
|
||||
UINTN Index;
|
||||
UINTN FileSize;
|
||||
VOID *FileBuffer;
|
||||
EFI_FILE_INFO **FileInfoBuffer;
|
||||
EFI_FILE_INFO *FileInfo;
|
||||
UINTN FileCount;
|
||||
BOOLEAN NoFile;
|
||||
|
||||
DirHandle = NULL;
|
||||
FileHandle = NULL;
|
||||
Index = 0;
|
||||
FileCount = 0;
|
||||
NoFile = FALSE;
|
||||
|
||||
Status = Fs->OpenVolume (Fs, &Root);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Print (L"Cannot open volume. Status = %r\n", Status);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status);
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
//
|
||||
// Get file count first
|
||||
//
|
||||
for ( Status = FileHandleFindFirstFile (DirHandle, &FileInfo)
|
||||
; !EFI_ERROR(Status) && !NoFile
|
||||
; Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile)
|
||||
){
|
||||
if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) == 0) {
|
||||
continue;
|
||||
}
|
||||
FileCount++;
|
||||
}
|
||||
|
||||
if (FileCount == 0) {
|
||||
Print (L"Error: No capsule file found!\n");
|
||||
return EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
FileInfoBuffer = AllocatePool (sizeof(FileInfo) * FileCount);
|
||||
NoFile = FALSE;
|
||||
|
||||
//
|
||||
// Get all file info
|
||||
//
|
||||
for ( Status = FileHandleFindFirstFile (DirHandle, &FileInfo)
|
||||
; !EFI_ERROR (Status) && !NoFile
|
||||
; Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile)
|
||||
){
|
||||
if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) == 0) {
|
||||
continue;
|
||||
}
|
||||
FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);
|
||||
}
|
||||
|
||||
//
|
||||
// Sort FileInfoBuffer by alphabet order
|
||||
//
|
||||
PerformQuickSort (
|
||||
FileInfoBuffer,
|
||||
FileCount,
|
||||
sizeof (FileInfo),
|
||||
(SORT_COMPARE) CompareFileNameInAlphabet
|
||||
);
|
||||
|
||||
Print (L"The capsules will be performed by following order:\n");
|
||||
|
||||
for (Index = 0; Index < FileCount; Index++) {
|
||||
Print (L" %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName);
|
||||
}
|
||||
|
||||
if (!DumpCapsuleInfo) {
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
Print(L"The infomation of the capsules:\n");
|
||||
|
||||
for (Index = 0; Index < FileCount; Index++) {
|
||||
FileHandle = NULL;
|
||||
Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]->FileName, EFI_FILE_MODE_READ, 0);
|
||||
if (EFI_ERROR (Status)) {
|
||||
break;
|
||||
}
|
||||
|
||||
Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);
|
||||
FileHandleClose (FileHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
FileBuffer = AllocatePool (FileSize);
|
||||
if (FileBuffer == NULL) {
|
||||
return RETURN_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);
|
||||
if (EFI_ERROR (Status)) {
|
||||
Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);
|
||||
FreePool (FileBuffer);
|
||||
FileHandleClose (FileHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Print (L"**************************\n");
|
||||
Print (L" %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName);
|
||||
Print (L"**************************\n");
|
||||
DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer);
|
||||
FileHandleClose (FileHandle);
|
||||
FreePool (FileBuffer);
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
Dump capsule inforomation form Gather list.
|
||||
|
||||
@param[in] BlockDescriptors The block descriptors for the capsule images
|
||||
@param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
|
||||
|
||||
**/
|
||||
VOID
|
||||
DumpBlockDescriptors (
|
||||
IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,
|
||||
IN BOOLEAN DumpCapsuleInfo
|
||||
)
|
||||
{
|
||||
EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;
|
||||
|
||||
TempBlockPtr = BlockDescriptors;
|
||||
|
||||
while (TRUE) {
|
||||
if (TempBlockPtr->Length != 0) {
|
||||
if (DumpCapsuleInfo) {
|
||||
Print(L"******************************************************\n");
|
||||
}
|
||||
Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlockPtr->Union.DataBlock, TempBlockPtr->Length);
|
||||
if (DumpCapsuleInfo) {
|
||||
Print(L"******************************************************\n");
|
||||
DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN) TempBlockPtr->Union.DataBlock);
|
||||
}
|
||||
TempBlockPtr += 1;
|
||||
} else {
|
||||
if (TempBlockPtr->Union.ContinuationPointer == (UINTN)NULL) {
|
||||
break;
|
||||
} else {
|
||||
TempBlockPtr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockPtr->Union.ContinuationPointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Dump Provisioned Capsule.
|
||||
|
||||
@param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.
|
||||
|
||||
**/
|
||||
VOID
|
||||
DumpProvisionedCapsule (
|
||||
IN BOOLEAN DumpCapsuleInfo
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
CHAR16 CapsuleVarName[30];
|
||||
CHAR16 *TempVarName;
|
||||
UINTN Index;
|
||||
EFI_PHYSICAL_ADDRESS *CapsuleDataPtr64;
|
||||
UINT16 *BootNext;
|
||||
CHAR16 BootOptionName[20];
|
||||
EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
|
||||
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
|
||||
EFI_SHELL_PROTOCOL *ShellProtocol;
|
||||
|
||||
ShellProtocol = GetShellProtocol ();
|
||||
|
||||
Index = 0;
|
||||
|
||||
//
|
||||
// Dump capsule provisioned on Memory
|
||||
//
|
||||
Print (L"#########################\n");
|
||||
Print (L"### Capsule on Memory ###\n");
|
||||
Print (L"#########################\n");
|
||||
StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);
|
||||
TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
|
||||
while (TRUE) {
|
||||
if (Index > 0) {
|
||||
UnicodeValueToStringS (
|
||||
TempVarName,
|
||||
sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),
|
||||
0,
|
||||
Index,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
Status = GetVariable2 (
|
||||
CapsuleVarName,
|
||||
&gEfiCapsuleVendorGuid,
|
||||
(VOID **) &CapsuleDataPtr64,
|
||||
NULL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
if (Index == 0) {
|
||||
Print (L"No data.\n");
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
Index++;
|
||||
Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64);
|
||||
DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN) *CapsuleDataPtr64, DumpCapsuleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Dump capsule provisioned on Disk
|
||||
//
|
||||
Print (L"#########################\n");
|
||||
Print (L"### Capsule on Disk #####\n");
|
||||
Print (L"#########################\n");
|
||||
Status = GetVariable2 (
|
||||
L"BootNext",
|
||||
&gEfiGlobalVariableGuid,
|
||||
(VOID **) &BootNext,
|
||||
NULL
|
||||
);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNext);
|
||||
Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
//
|
||||
// Display description and device path
|
||||
//
|
||||
GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath, &DevicePath, &Fs);
|
||||
if(!EFI_ERROR (Status)) {
|
||||
Print (L"Capsules are provisioned on BootOption: %s\n", BootNextOptionEntry.Description);
|
||||
Print (L" %s %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE));
|
||||
DumpCapsuleFromDisk (Fs, DumpCapsuleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Dump FMP information.
|
||||
|
||||
|
|
|
@ -167,6 +167,7 @@
|
|||
HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
|
||||
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
|
||||
DebugLib|MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf
|
||||
FileHandleLib|MdePkg/Library/UefiFileHandleLib/UefiFileHandleLib.inf
|
||||
|
||||
[LibraryClasses.common.MM_STANDALONE]
|
||||
HobLib|MdeModulePkg/Library/BaseHobLibNull/BaseHobLibNull.inf
|
||||
|
|
Loading…
Reference in New Issue