From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received-SPF: Pass (sender SPF authorized) identity=mailfrom; client-ip=192.55.52.151; helo=mga17.intel.com; envelope-from=jian.j.wang@intel.com; receiver=edk2-devel@lists.01.org Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id 3F5B1211B696B for ; Tue, 29 Jan 2019 06:01:55 -0800 (PST) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga107.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 29 Jan 2019 06:01:55 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.56,537,1539673200"; d="scan'208";a="120385998" Received: from fmsmsx106.amr.corp.intel.com ([10.18.124.204]) by fmsmga008.fm.intel.com with ESMTP; 29 Jan 2019 06:01:55 -0800 Received: from fmsmsx120.amr.corp.intel.com (10.18.124.208) by FMSMSX106.amr.corp.intel.com (10.18.124.204) with Microsoft SMTP Server (TLS) id 14.3.408.0; Tue, 29 Jan 2019 06:01:55 -0800 Received: from shsmsx151.ccr.corp.intel.com (10.239.6.50) by fmsmsx120.amr.corp.intel.com (10.18.124.208) with Microsoft SMTP Server (TLS) id 14.3.408.0; Tue, 29 Jan 2019 06:01:54 -0800 Received: from shsmsx107.ccr.corp.intel.com ([169.254.9.162]) by SHSMSX151.ccr.corp.intel.com ([169.254.3.172]) with mapi id 14.03.0415.000; Tue, 29 Jan 2019 22:01:52 +0800 From: "Wang, Jian J" To: "Chen, Chen A" , "edk2-devel@lists.01.org" CC: "Wu, Hao A" , "Zhang, Chao B" Thread-Topic: [PATCH v3 4/4] MdeModulePkg/CapsuleApp: Enhance CapsuleApp to support Capsule-on-Disk Thread-Index: AQHUt6ZoFuxMJ2nqvUylyEoqlNFT+aXGRwVg Date: Tue, 29 Jan 2019 14:01:52 +0000 Message-ID: References: <20190129074341.7032-1-chen.a.chen@intel.com> <20190129074341.7032-5-chen.a.chen@intel.com> In-Reply-To: <20190129074341.7032-5-chen.a.chen@intel.com> Accept-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-titus-metadata-40: eyJDYXRlZ29yeUxhYmVscyI6IiIsIk1ldGFkYXRhIjp7Im5zIjoiaHR0cDpcL1wvd3d3LnRpdHVzLmNvbVwvbnNcL0ludGVsMyIsImlkIjoiNjVhZWQzNGEtZmNiZC00YjNiLThjMzgtM2FlZGY1MjQxMTc2IiwicHJvcHMiOlt7Im4iOiJDVFBDbGFzc2lmaWNhdGlvbiIsInZhbHMiOlt7InZhbHVlIjoiQ1RQX05UIn1dfV19LCJTdWJqZWN0TGFiZWxzIjpbXSwiVE1DVmVyc2lvbiI6IjE3LjEwLjE4MDQuNDkiLCJUcnVzdGVkTGFiZWxIYXNoIjoib0d2Z1JtZ3VPTkxoVlRjeEFRZmN0a3ZhbzBJZ1dSNktScGR2WXNqVzlUNWxxWnBTRHZnTllENW40WXJcL0lCVjMifQ== x-ctpclassification: CTP_NT dlp-product: dlpe-windows dlp-version: 11.0.400.15 dlp-reaction: no-action x-originating-ip: [10.239.127.40] MIME-Version: 1.0 Subject: Re: [PATCH v3 4/4] MdeModulePkg/CapsuleApp: Enhance CapsuleApp to support Capsule-on-Disk X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 X-List-Received-Date: Tue, 29 Jan 2019 14:01:56 -0000 Content-Language: en-US Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: quoted-printable Reviewed-by: Jian J Wang > -----Original Message----- > From: Chen, Chen A > Sent: Tuesday, January 29, 2019 3:44 PM > To: edk2-devel@lists.01.org > Cc: Chen, Chen A ; Wang, Jian J > ; Wu, Hao A ; Zhang, Chao B > > Subject: [PATCH v3 4/4] MdeModulePkg/CapsuleApp: Enhance CapsuleApp to > support Capsule-on-Disk >=20 > BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=3D1482 >=20 > 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. >=20 > Cc: Jian J Wang > Cc: Hao Wu > Cc: Zhang Chao B > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Chen A Chen > --- > 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(-) >=20 > 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. >=20 > - Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
> 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 > #include > #include > +#include > #include > #include > #include > @@ -105,6 +106,44 @@ DumpEsrtData ( > VOID > ); >=20 > +/** > + 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. >=20 > @@ -799,19 +838,22 @@ PrintUsage ( > ) > { > Print(L"CapsuleApp: usage\n"); > - Print(L" CapsuleApp [-NR]\n"); > + Print(L" CapsuleApp [-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 -O \n"); > Print(L" CapsuleApp -N -O \n"); > Print(L" CapsuleApp -D \n"); > Print(L" CapsuleApp -P GET -O \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 'GE= T'\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 imag= e\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; >=20 > @@ -936,6 +985,20 @@ UefiMain ( > return EFI_SUCCESS; > } >=20 > + if (StrCmp(Argv[1], L"-L") =3D=3D 0) { > + if (Argc >=3D 3 && StrCmp(Argv[2], L"INFO") =3D=3D 0) { > + DumpProvisionedCapsule(TRUE); > + } else { > + DumpProvisionedCapsule(FALSE); > + } > + return EFI_SUCCESS; > + } > + > + if (StrCmp(Argv[1], L"-F") =3D=3D 0) { > + DumpAllEfiSysPartition(); > + return EFI_SUCCESS; > + } > + > if (Argv[1][0] =3D=3D L'-') { > Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]); > return EFI_UNSUPPORTED; > @@ -943,12 +1006,56 @@ UefiMain ( >=20 > CapsuleFirstIndex =3D 1; > NoReset =3D FALSE; > - if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") =3D=3D 0)) { > - NoReset =3D TRUE; > - CapsuleLastIndex =3D Argc - 2; > + CapsuleOnDisk =3D FALSE; > + ParaOdIndex =3D 0; > + ParaNrIndex =3D 0; > + > + for (Index =3D 1; Index < Argc; Index++) { > + if (StrCmp(Argv[Index], L"-OD") =3D=3D 0) { > + ParaOdIndex =3D Index; > + CapsuleOnDisk =3D TRUE; > + } else if (StrCmp(Argv[Index], L"-NR") =3D=3D 0) { > + ParaNrIndex =3D Index; > + NoReset =3D TRUE; > + } > + } > + > + if (ParaOdIndex !=3D 0) { > + if (ParaOdIndex =3D=3D Argc - 1) { > + MapFsStr =3D NULL; > + } else if (ParaOdIndex =3D=3D Argc - 2) { > + MapFsStr =3D Argv[Argc-1]; > + } else { > + Print (L"CapsuleApp: Invalid Position for -OD Options\n"); > + Status =3D EFI_INVALID_PARAMETER; > + goto Done; > + } > + > + if (ParaNrIndex !=3D 0) { > + if (ParaNrIndex + 1 =3D=3D ParaOdIndex) { > + CapsuleLastIndex =3D ParaNrIndex - 1; > + } else { > + Print (L"CapsuleApp: Invalid Position for -NR Options\n"); > + Status =3D EFI_INVALID_PARAMETER; > + goto Done; > + } > + } else { > + CapsuleLastIndex =3D ParaOdIndex - 1; > + } > } else { > - CapsuleLastIndex =3D Argc - 1; > + if (ParaNrIndex !=3D 0) { > + if (ParaNrIndex =3D=3D Argc -1) { > + CapsuleLastIndex =3D ParaNrIndex - 1; > + } else { > + Print (L"CapsuleApp: Invalid Position for -NR Options\n"); > + Status =3D EFI_INVALID_PARAMETER; > + goto Done; > + } > + } else { > + CapsuleLastIndex =3D Argc - 1; > + } > } > + > CapsuleNum =3D CapsuleLastIndex - CapsuleFirstIndex + 1; >=20 > if (CapsuleFirstIndex > CapsuleLastIndex) { > @@ -961,26 +1068,27 @@ UefiMain ( > } >=20 > ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer)); > - ZeroMem(&FileSize, sizeof(FileSize)); > + ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize)); > BlockDescriptors =3D NULL; >=20 > for (Index =3D 0; Index < CapsuleNum; Index++) { > CapsuleName =3D Argv[CapsuleFirstIndex + Index]; > - Status =3D ReadFileToBuffer(CapsuleName, &FileSize[Index], > &CapsuleBuffer[Index]); > + Status =3D ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index], > &CapsuleBuffer[Index]); > if (EFI_ERROR(Status)) { > Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleNa= me); > goto Done; > } > - if (!IsValidCapsuleHeader (CapsuleBuffer[Index], FileSize[Index])) { > + if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[I= ndex])) { > Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", > CapsuleName); > return EFI_INVALID_PARAMETER; > } > + CapsuleNames[Index] =3D CapsuleName; > } >=20 > // > // Every capsule use 2 descriptor 1 for data 1 for end > // > - Status =3D BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, > &BlockDescriptors); > + Status =3D BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNu= m, > &BlockDescriptors); > if (EFI_ERROR(Status)) { > goto Done; > } > @@ -1007,13 +1115,30 @@ UefiMain ( > } >=20 > for (Index =3D 0; Index < CapsuleNum; Index++) { > - if (FileSize[Index] > MaxCapsuleSize) { > + if (CapsuleBufferSize[Index] > MaxCapsuleSize) { > Print (L"CapsuleApp: capsule is too large to update, %ld is allowe= d\n", > MaxCapsuleSize); > Status =3D EFI_UNSUPPORTED; > goto Done; > } > } >=20 > + // > + // Check whether is capsule on disk. > + // > + if (CapsuleOnDisk) { > + Status =3D ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, > CapsuleNames, MapFsStr, CapsuleNum); > + if (Status !=3D 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 acros= s 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 >=20 > [Packages] > @@ -40,16 +41,20 @@ > MdeModulePkg/MdeModulePkg.dec >=20 > [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 >=20 > [Protocols] > gEfiGraphicsOutputProtocolGuid ## CONSUMES > gEfiFirmwareManagementProtocolGuid ## CONSUMES > gEfiShellParametersProtocolGuid ## CONSUMES > gEfiShellProtocolGuid ## CONSUMES > + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES >=20 > [LibraryClasses] > BaseLib > @@ -61,6 +66,9 @@ > UefiLib > PrintLib > BmpSupportLib > + FileHandleLib > + UefiBootManagerLib > + SortLib >=20 > [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. >=20 > - Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
> + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
> 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 > #include > #include > +#include > +#include > +#include > +#include > #include > +#include > +#include > #include > #include > #include > #include > +#include > #include >=20 > +// > +// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for b= ytes) > +// > +#define MAX_FILE_NAME_SIZE 522 > +#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16)) > + > /** > Read a file. >=20 > @@ -61,6 +74,37 @@ WriteFileFromBuffer ( > IN VOID *Buffer > ); >=20 > +/** > + 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 >=20 > @@ -123,7 +167,7 @@ DumpFmpCapsule ( > UINTN Count; > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER > *FmpImageHeader; >=20 > - 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"); > } >=20 > + > +/** > + 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->CapsuleImageSi= ze); > + 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 =3D Str; *Cptr; Cptr++) { > + if (L'a' <=3D *Cptr && *Cptr <=3D L'z') { > + *Cptr =3D *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 =3D 0; Str[Index] !=3D L'.' && Str[Index] !=3D L'\0'; Index= ++) { > + SubStr[Index] =3D Str[Index]; > + } > + > + SubStr[Index] =3D L'\0'; > + *SubStrLen =3D Index; > +} > + > +/** > + This routine pad the string in tail with input character. > + > + @param[in] StrBuf Str buffer to be padded, should be enou= gh 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 =3D 0; StrBuf[Index] !=3D L'\0'; Index++); > + > + while(PadLen !=3D 0) { > + StrBuf[Index] =3D Character; > + Index++; > + PadLen--; > + } > + > + StrBuf[Index] =3D L'\0'; > + } > + > +/** > + This routine find the offset of the last period '.' of string. if No p= eriod 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 =3D StrLen(FileName); > + for (Index =3D StringLen; Index > 0 && FileName[Index] !=3D L'.'; Inde= x--); > + > + // > + // No period exists. No FileName Extension > + // > + if (Index =3D=3D 0 && FileName[Index] !=3D L'.') { > + FileNameExtension[0] =3D L'\0'; > + Index =3D 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] =3D L'\0'; > +} > + > +/** > + The function is called by PerformQuickSort to sort file name in alphab= et. > + > + @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 =3D (EFI_FILE_INFO *) *Left; > + FileInfo2 =3D (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 =3D StrnCmp (TempSubStr1, TempSubStr2, > MAX_FILE_NAME_LEN); > + if (SubStrCmpResult !=3D 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 th= e > 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 =3D NULL; > + FileHandle =3D NULL; > + Index =3D 0; > + FileCount =3D 0; > + NoFile =3D FALSE; > + > + Status =3D Fs->OpenVolume (Fs, &Root); > + if (EFI_ERROR (Status)) { > + Print (L"Cannot open volume. Status =3D %r\n", Status); > + return EFI_NOT_FOUND; > + } > + > + Status =3D 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 =3D %r\n", EFI_CAPSULE_FROM_FILE_DIR= , > Status); > + return EFI_NOT_FOUND; > + } > + > + // > + // Get file count first > + // > + for ( Status =3D FileHandleFindFirstFile (DirHandle, &FileInfo) > + ; !EFI_ERROR(Status) && !NoFile > + ; Status =3D FileHandleFindNextFile (DirHandle, FileInfo, &NoFile) > + ){ > + if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) =3D= =3D 0) { > + continue; > + } > + FileCount++; > + } > + > + if (FileCount =3D=3D 0) { > + Print (L"Error: No capsule file found!\n"); > + return EFI_NOT_FOUND; > + } > + > + FileInfoBuffer =3D AllocatePool (sizeof(FileInfo) * FileCount); > + NoFile =3D FALSE; > + > + // > + // Get all file info > + // > + for ( Status =3D FileHandleFindFirstFile (DirHandle, &FileInfo) > + ; !EFI_ERROR (Status) && !NoFile > + ; Status =3D FileHandleFindNextFile (DirHandle, FileInfo, &NoFile) > + ){ > + if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) =3D= =3D 0) { > + continue; > + } > + FileInfoBuffer[Index++] =3D AllocateCopyPool (FileInfo->Size, FileIn= fo); > + } > + > + // > + // 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 =3D 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 =3D 0; Index < FileCount; Index++) { > + FileHandle =3D NULL; > + Status =3D DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[I= ndex]- > >FileName, EFI_FILE_MODE_READ, 0); > + if (EFI_ERROR (Status)) { > + break; > + } > + > + Status =3D FileHandleGetSize (FileHandle, (UINT64 *) &FileSize); > + if (EFI_ERROR (Status)) { > + Print (L"Cannot read file %s. Status =3D %r\n", FileInfoBuffer[Ind= ex]- > >FileName, Status); > + FileHandleClose (FileHandle); > + return Status; > + } > + > + FileBuffer =3D AllocatePool (FileSize); > + if (FileBuffer =3D=3D NULL) { > + return RETURN_OUT_OF_RESOURCES; > + } > + > + Status =3D FileHandleRead (FileHandle, &FileSize, FileBuffer); > + if (EFI_ERROR (Status)) { > + Print (L"Cannot read file %s. Status =3D %r\n", FileInfoBuffer[Ind= ex]- > >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 ima= ges > + @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 =3D BlockDescriptors; > + > + while (TRUE) { > + if (TempBlockPtr->Length !=3D 0) { > + if (DumpCapsuleInfo) { > + > Print(L"******************************************************\n"); > + } > + Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlo= ckPtr- > >Union.DataBlock, TempBlockPtr->Length); > + if (DumpCapsuleInfo) { > + > Print(L"******************************************************\n"); > + DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN) > TempBlockPtr->Union.DataBlock); > + } > + TempBlockPtr +=3D 1; > + } else { > + if (TempBlockPtr->Union.ContinuationPointer =3D=3D (UINTN)NULL) { > + break; > + } else { > + TempBlockPtr =3D (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 =3D GetShellProtocol (); > + > + Index =3D 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 =3D CapsuleVarName + StrLen (CapsuleVarName); > + while (TRUE) { > + if (Index > 0) { > + UnicodeValueToStringS ( > + TempVarName, > + sizeof (CapsuleVarName) - ((UINTN)TempVarName - > (UINTN)CapsuleVarName), > + 0, > + Index, > + 0 > + ); > + } > + > + Status =3D GetVariable2 ( > + CapsuleVarName, > + &gEfiCapsuleVendorGuid, > + (VOID **) &CapsuleDataPtr64, > + NULL > + ); > + if (EFI_ERROR (Status)) { > + if (Index =3D=3D 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 =3D GetVariable2 ( > + L"BootNext", > + &gEfiGlobalVariableGuid, > + (VOID **) &BootNext, > + NULL > + ); > + if (!EFI_ERROR (Status)) { > + UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", > *BootNext); > + Status =3D EfiBootManagerVariableToLoadOption (BootOptionName, > &BootNextOptionEntry); > + if (!EFI_ERROR (Status)) { > + // > + // Display description and device path > + // > + GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.File= Path, > &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. >=20 > -- > 2.16.2.windows.1