Reviewed-by: Jian J Wang <jian.j.w...@intel.com>
> -----Original Message-----
> From: Chen, Chen A
> Sent: Tuesday, January 29, 2019 3:44 PM
> To: edk2-devel@lists.01.org
> Cc: Chen, Chen A <chen.a.c...@intel.com>; Wang, Jian J
> <jian.j.w...@intel.com>; Wu, Hao A <hao.a...@intel.com>; Zhang, Chao B
> <chao.b.zh...@intel.com>
> Subject: [PATCH v3 4/4] 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.w...@intel.com>
> Cc: Hao Wu <hao.a...@intel.com>
> Cc: Zhang Chao B <chao.b.zh...@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Chen A Chen <chen.a.c...@intel.com>
> ---
> MdeModulePkg/Application/CapsuleApp/CapsuleApp.c | 155 +++++-
> MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf | 8 +
> MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 538
> ++++++++++++++++++++-
> 3 files changed, 684 insertions(+), 17 deletions(-)
>
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> index 4d907242f3..258e6995bc 100644
> --- a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> @@ -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,44 @@ 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] FileSize An array of UINTN to capsule images size
> + @param[in] OrgFileName An array of orginal capsule images name
> + @param[in] NewFileName An array of new capsule images name
> + @param[in] CapsuleNum The count of capsule images
> +
> + @retval EFI_SUCCESS Capsule on disk success.
> +**/
> +EFI_STATUS
> +ProcessCapsuleOnDisk (
> + IN VOID **CapsuleBuffer,
> + IN UINTN *CapsuleBufferSize,
> + IN CHAR16 **FilePath,
> + IN CHAR16 *Map,
> + IN UINTN CapsuleNum
> + );
> +
> /**
> Read a file.
>
> @@ -799,19 +838,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 +862,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 +895,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,9 +903,14 @@ 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;
>
> @@ -936,6 +985,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 +1006,56 @@ UefiMain (
>
> CapsuleFirstIndex = 1;
> NoReset = FALSE;
> - if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) {
> - NoReset = TRUE;
> - CapsuleLastIndex = Argc - 2;
> + 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 {
> - CapsuleLastIndex = Argc - 1;
> + 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 +1068,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 +1115,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.
> //
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> index 8a21875286..0334e0caaf 100644
> --- a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> @@ -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
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> index 7a3eb94362..9079aedf68 100644
> --- a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> @@ -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; 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 EFI_PHYSICAL_ADDRESS *Left,
> + IN EFI_PHYSICAL_ADDRESS *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 *) *Left;
> + FileInfo2 = (EFI_FILE_INFO *) *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] DevicePath 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_FROM_FILE_DIR,
> EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
> + if (EFI_ERROR (Status)) {
> + Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FROM_FILE_DIR,
> 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 (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.
>
> --
> 2.16.2.windows.1
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel