From: "Xu, Wei6" <wei6.xu@intel.com>
To: "Wu, Hao A" <hao.a.wu@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Wang, Jian J" <jian.j.wang@intel.com>,
"Zhang, Chao B" <chao.b.zhang@intel.com>
Subject: Re: [edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On Disk APIs into CapsuleLib.
Date: Wed, 19 Jun 2019 07:55:02 +0000 [thread overview]
Message-ID: <59B8EAB3797CDB4091332F0685A110ED50D9746F@SHSMSX104.ccr.corp.intel.com> (raw)
In-Reply-To: <B80AF82E9BFB8E4FBD8C89DA810C6A093C8EDBF4@SHSMSX104.ccr.corp.intel.com>
Thanks a lot for the comments.
Please find my answer bellow.
> -----Original Message-----
> From: Wu, Hao A
> Sent: Wednesday, June 12, 2019 3:50 PM
> To: devel@edk2.groups.io; Xu, Wei6 <wei6.xu@intel.com>
> Cc: Wang, Jian J <jian.j.wang@intel.com>; Zhang, Chao B
> <chao.b.zhang@intel.com>
> Subject: RE: [edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On
> Disk APIs into CapsuleLib.
>
> > -----Original Message-----
> > From: devel@edk2.groups.io [mailto:devel@edk2.groups.io] On Behalf Of
> Xu,
> > Wei6
> > Sent: Wednesday, June 05, 2019 11:42 PM
> > To: devel@edk2.groups.io
> > Cc: Wang, Jian J; Wu, Hao A; Zhang, Chao B; Xu, Wei6
> > Subject: [edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On Disk
> > APIs into CapsuleLib.
>
>
> Not directly related with this patch, I saw many function declarations
> within .C file for this library. Could you help to propose another series
> to add header files to address this (Maybe like the case in
> MdeModulePkg/Universal/Variable/RuntimeDxe to handle multi-phases).
>
Sure, I will work on it after this patch is done.
>
> Some general level comments:
>
> I saw some of the new functions whose scope is limited within a single
> file have been decorated with keyword 'STATIC'. Could you help to make it
> consistent for all the newly added global variables/functions? Also, could
> you help to use keyword 'static' (lower case) instead?
>
I will update all 'STATIC' to 'static'.
>
> >
> > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1852
> >
> > CoDCheckCapsuleOnDiskFlag() is to check if CapsuleOnDisk flag in
> > "OsIndications" Variable is enabled. It is used to indicate whether
> > capsule on disk is provisioned in normal boot path.
> >
> > CoDClearCapsuleOnDiskFlag() is to to clear CapsuleOnDisk flags,
> > including "OsIndications" and "BootNext" variable.
> >
> > CoDRelocateCapsule() is to relocate the capsules from EFI system
> > partition. Depends on PcdCapsuleInRamSupport, there are two solutions
> > to relocate the capsule on disk images:
> > When Capsule In Ram is supported, the Capsule On Disk images are
> > relocated into memory, and call UpdateCapsule() service to deliver
> > the capsules.
> > When Capsule In Ram is not supported, the Capsule On Disk images are
> > relocated into a temp file which will be stored in root directory on
> > a platform specific storage device. CapsuleOnDiskLoadPei PEIM will
> > retrieve the capsules from the relocation temp file and report
> > capsule hobs for them.
> >
> > CoDRemoveTempFile() is to remove the relocation temp file in the next
> > boot after capsules are processed.
> >
> > Cc: Jian J Wang <jian.j.wang@intel.com>
> > Cc: Hao A Wu <hao.a.wu@intel.com>
> > Cc: Chao B Zhang <chao.b.zhang@intel.com>
> > Signed-off-by: Wei6 Xu <wei6.xu@intel.com>
> > ---
> > MdeModulePkg/Include/Library/CapsuleLib.h | 94 +-
> > .../Library/DxeCapsuleLibFmp/CapsuleOnDisk.c | 1983
> > ++++++++++++++++++++
> > .../Library/DxeCapsuleLibFmp/CapsuleOnDisk.h | 63 +
> > .../Library/DxeCapsuleLibFmp/DxeCapsuleLib.c | 56 +-
> > .../Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf | 21 +-
> > .../DxeCapsuleLibFmp/DxeCapsuleProcessLib.c | 121 +-
> > .../Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c | 67 +-
> > .../DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf | 3 +-
> > .../Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c | 85 +-
> > 9 files changed, 2466 insertions(+), 27 deletions(-)
> > create mode 100644
> > MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
> > create mode 100644
> > MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
> >
> > diff --git a/MdeModulePkg/Include/Library/CapsuleLib.h
> > b/MdeModulePkg/Include/Library/CapsuleLib.h
> > index 1fc2fba3a2..f3cb17cbf9 100644
> > --- a/MdeModulePkg/Include/Library/CapsuleLib.h
> > +++ b/MdeModulePkg/Include/Library/CapsuleLib.h
> > @@ -1,17 +1,37 @@
> > /** @file
> >
> > This library class defines a set of interfaces for how to process capsule
> > image updates.
> >
> > -Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
> > SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > **/
> >
> > #ifndef __CAPSULE_LIB_H__
> > #define __CAPSULE_LIB_H__
> >
> > +#include <Guid/FileInfo.h>
> > +
> > +
> > +typedef struct {
> > + //
> > + // image address.
> > + //
> > + VOID *ImageAddress;
> > + //
> > + // The file info of the image comes from.
> > + // if FileInfo == NULL. means image does not come from file
> > + //
> > + EFI_FILE_INFO *FileInfo;
> > +} IMAGE_INFO;
>
>
> Will this 'IMAGE_INFO' structure (FileInfo.h include as well) be used by
> the consumer of CapsuleLib? For this series, this one is only used within
> DxeCapsuleLibFmp (implementation of CapsuleLib).
>
> If it is only used internally, I suggest to move the definition into
> MdeModulePkg\Library\DxeCapsuleLibFmp\CapsuleOnDisk.h.
>
>
> > +
> > +//
> > +// BOOLEAN Variable to save the total size of all Capsule On Disk during
> > relocation
> > +//
>
>
> The above description comment seems not matching the usage of the
> variable
> perfectly. Looks to me the variable is used to reflect whether the system
> is in the capsule on disk state rather than the size information.
>
>
> > +#define COD_RELOCATION_INFO_VAR_NAME L"CodRelocationInfo"
> > +
> > /**
> > The firmware checks whether the capsule image is supported
> > by the CapsuleGuid in CapsuleHeader or if there is other specific
> > information in
> > the capsule image.
> >
> > @@ -79,6 +99,78 @@ EFI_STATUS
> > EFIAPI
> > ProcessCapsules (
> > VOID
> > );
> >
> > +/**
> > + This routine is called to check if CapsuleOnDisk flag in OsIndications
> > Variable
> > + is enabled.
> > +
> > + @retval TRUE Flag is enabled
> > + @retval FALSE Flag is not enabled
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +CoDCheckCapsuleOnDiskFlag(
> > + VOID
> > + );
> > +
> > +
> > +/**
> > + This routine is called to clear CapsuleOnDisk flags including OsIndications
> > and BootNext variable
> > +
> > + @retval EFI_SUCCESS All Capsule On Disk flags are cleared
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDClearCapsuleOnDiskFlag(
> > + VOID
> > + );
> > +
> > +/**
> > + Relocate Capsule on Disk from EFI system partition.
> > +
> > + Two solution to deliver Capsule On Disk:
> > + Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On
> > Disk to memory and call UpdateCapsule().
> > + Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On
> > Disk to a platform-specific NV storage
> > + device with BlockIo protocol.
> > +
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + Side Effects:
> > + Capsule Delivery Supported Flag in OsIndication variable and BootNext
> > variable will be cleared.
> > + Solution B: Content corruption. Block IO write directly touches low level
> > write. Orignal partitions, file
> > + systems of the relocation device will be corrupted.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
>
>
> For me, it would be better to explicitly mention the behavior for
> 'MaxRetry' with the value 0. Judging from the implementation, 0 means no
> retry.
>
> Similar case for API CoDRemoveTempFile() as well.
>
> > +
> > + @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated.
>
>
> sucessfully -> successfully
> Please help to update this typo in library instances as well.
>
>
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDRelocateCapsule(
> > + UINTN MaxRetry
> > + );
> > +
> > +/**
> > + Remove the temp file from the root of EFI System Partition.
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Remove the temp file successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDRemoveTempFile (
> > + UINTN MaxRetry
> > + );
> > +
> > #endif
> > diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
> > new file mode 100644
> > index 0000000000..5f1edbbbae
> > --- /dev/null
> > +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.c
> > @@ -0,0 +1,1983 @@
> > +/** @file
> > + The implementation supports Capusle on Disk.
> > +
> > + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#include "CapsuleOnDisk.h"
> > +
> > +/**
> > + Return if this capsule is a capsule name capsule, based upon
> > CapsuleHeader.
> > +
> > + @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
> > +
> > + @retval TRUE It is a capsule name capsule.
> > + @retval FALSE It is not a capsule name capsule.
> > +**/
> > +BOOLEAN
> > +IsCapsuleNameCapsule (
> > + IN EFI_CAPSULE_HEADER *CapsuleHeader
> > + );
> > +
> > +/**
> > + Check the integrity of the capsule name capsule.
> > + If the capsule is vaild, return the physical address of each capsule name
> > string.
> > +
> > + @param[in] CapsuleHeader Pointer to the capsule header of a capsule
> > name capsule.
> > + @param[out] CapsuleNameNum Number of capsule name.
> > +
> > + @retval NULL Capsule name capsule is not valid.
> > + @retval CapsuleNameBuf Array of capsule name physical address.
> > +
> > +**/
> > +EFI_PHYSICAL_ADDRESS *
> > +ValidateCapsuleNameCapsuleIntegrity (
> > + IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > + OUT UINTN *CapsuleNameNum
> > + )
> > +{
> > + UINT8 *CapsuleNamePtr;
> > + UINT8 *CapsuleNameBufStart;
> > + UINT8 *CapsuleNameBufEnd;
> > + UINTN Index;
> > + UINTN StringSize;
> > + EFI_PHYSICAL_ADDRESS *CapsuleNameBuf;
> > +
> > + if (!IsCapsuleNameCapsule (CapsuleHeader)) {
> > + return NULL;
> > + }
> > +
> > + //
> > + // Total string size must be even.
> > + //
> > + if (((CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize)
> &
> > BIT0) != 0) {
> > + return NULL;
> > + }
> > +
> > + *CapsuleNameNum = 0;
> > + Index = 0;
> > + CapsuleNameBufStart = (UINT8 *) CapsuleHeader + CapsuleHeader-
> > >HeaderSize;
> > +
> > + //
> > + // If strings are not aligned on a 16-bit boundary, reallocate memory for it.
> > + //
> > + if (((UINTN) CapsuleNameBufStart & BIT0) != 0) {
> > + CapsuleNameBufStart = AllocateCopyPool (CapsuleHeader-
> > >CapsuleImageSize - CapsuleHeader->HeaderSize, CapsuleNameBufStart);
> > + }
> > +
> > + CapsuleNameBufEnd = CapsuleNameBufStart + CapsuleHeader-
> > >CapsuleImageSize - CapsuleHeader->HeaderSize;
> > +
> > + CapsuleNamePtr = CapsuleNameBufStart;
> > + while (CapsuleNamePtr < CapsuleNameBufEnd) {
> > + StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr,
> (CapsuleNameBufEnd
> > - CapsuleNamePtr)/sizeof(CHAR16));
> > + CapsuleNamePtr += StringSize;
> > + (*CapsuleNameNum) ++;
> > + }
> > +
> > + //
> > + // Integrity check.
> > + //
> > + if (CapsuleNamePtr != CapsuleNameBufEnd) {
> > + if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader-
> > >HeaderSize) {
> > + FreePool (CapsuleNameBufStart);
> > + }
> > + return NULL;
> > + }
> > +
> > + CapsuleNameBuf = AllocatePool (*CapsuleNameNum * sizeof
> > (EFI_PHYSICAL_ADDRESS));
> > + if (CapsuleNameBuf == NULL) {
> > + if (CapsuleNameBufStart != (UINT8 *)CapsuleHeader + CapsuleHeader-
> > >HeaderSize) {
> > + FreePool (CapsuleNameBufStart);
> > + }
> > + return NULL;
> > + }
> > +
> > + CapsuleNamePtr = CapsuleNameBufStart;
> > + while (CapsuleNamePtr < CapsuleNameBufEnd) {
> > + StringSize= StrnSizeS ((CHAR16 *) CapsuleNamePtr,
> (CapsuleNameBufEnd
> > - CapsuleNamePtr)/sizeof(CHAR16));
> > + CapsuleNameBuf[Index] = (EFI_PHYSICAL_ADDRESS)(UINTN)
> > CapsuleNamePtr;
> > + CapsuleNamePtr += StringSize;
> > + Index ++;
> > + }
> > +
> > + return CapsuleNameBuf;
> > +}
> > +
> > +/**
> > + 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 = StrnLenS(FileName, MAX_FILE_NAME_SIZE);
> > + 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_SIZE,
> > &FileName[Index+1]);
> > + }
> > +
> > + //
> > + // Copy First file name
> > + //
> > + StrnCpyS(FileNameFirst, MAX_FILE_NAME_SIZE, FileName, Index);
> > + FileNameFirst[Index] = L'\0';
> > +}
> > +
> > +/**
> > + This routine is called to get all boot options in the order determnined by:
> > + 1. "OptionBuf"
> > + 2. "BootOrder"
> > +
> > + @param[out] OptionBuf BootList buffer to all boot options returned
> > + @param[out] OptionCount BootList count of all boot options
> returned
> > +
> > + @retval EFI_SUCCESS There is no error when processing capsule
> > +
> > +**/
> > +EFI_STATUS
> > +GetBootOptionInOrder(
> > + OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf,
> > + OUT UINTN *OptionCount
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN DataSize;
> > + UINT16 BootNext;
> > + CHAR16 BootOptionName[20];
> > + EFI_BOOT_MANAGER_LOAD_OPTION *BootOrderOptionBuf;
> > + UINTN BootOrderCount;
> > + EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;
> > + UINTN BootNextCount;
> > + EFI_BOOT_MANAGER_LOAD_OPTION *TempBuf;
> > +
> > + BootOrderOptionBuf = NULL;
> > + TempBuf = NULL;
> > + BootNextCount = 0;
> > + BootOrderCount = 0;
> > + *OptionBuf = NULL;
> > + *OptionCount = 0;
> > +
> > + //
> > + // First Get BootOption from "BootNext"
> > + //
> > + DataSize = sizeof(BootNext);
> > + Status = gRT->GetVariable (
> > + EFI_BOOT_NEXT_VARIABLE_NAME,
> > + &gEfiGlobalVariableGuid,
> > + NULL,
> > + &DataSize,
> > + (VOID *)&BootNext
> > + );
> > + //
> > + // BootNext variable is a single UINT16
> > + //
> > + if (!EFI_ERROR(Status) && DataSize == sizeof(UINT16)) {
> > + //
> > + // Add the boot next boot option
> > + //
> > + UnicodeSPrint (BootOptionName, sizeof (BootOptionName),
> > L"Boot%04x", BootNext);
> > + ZeroMem(&BootNextOptionEntry,
> > sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));
> > + Status = EfiBootManagerVariableToLoadOption (BootOptionName,
> > &BootNextOptionEntry);
> > +
> > + if (!EFI_ERROR(Status)) {
> > + BootNextCount = 1;
> > + }
> > + }
> > +
> > + //
> > + // Second get BootOption from "BootOrder"
> > + //
> > + BootOrderOptionBuf = EfiBootManagerGetLoadOptions
> > (&BootOrderCount, LoadOptionTypeBoot);
> > + if (BootNextCount == 0 && BootOrderCount == 0) {
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + //
> > + // At least one BootOption is found
> > + //
> > + TempBuf = AllocatePool(sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) *
> > (BootNextCount + BootOrderCount));
> > + if (TempBuf != NULL) {
> > + if (BootNextCount == 1) {
> > + CopyMem(TempBuf, &BootNextOptionEntry,
> > sizeof(EFI_BOOT_MANAGER_LOAD_OPTION));
> > + }
> > +
> > + if (BootOrderCount > 0) {
> > + CopyMem(TempBuf + BootNextCount, BootOrderOptionBuf,
> > sizeof(EFI_BOOT_MANAGER_LOAD_OPTION) * BootOrderCount);
> > + }
> > +
> > + *OptionBuf = TempBuf;
> > + *OptionCount = BootNextCount + BootOrderCount;
> > + Status = EFI_SUCCESS;
> > + } else {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + FreePool(BootOrderOptionBuf);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This routine is called to get boot option by OptionNumber.
> > +
> > + @param[in] Number The OptionNumber of boot option
> > + @param[out] OptionBuf BootList buffer to all boot options returned
> > +
> > + @retval EFI_SUCCESS There is no error when getting boot option
> > +
> > +**/
> > +EFI_STATUS
> > +GetBootOptionByNumber(
> > + IN UINT16 Number,
> > + OUT EFI_BOOT_MANAGER_LOAD_OPTION **OptionBuf
> > + )
> > +{
> > + EFI_STATUS Status;
> > + CHAR16 BootOptionName[20];
> > + EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
> > +
> > + UnicodeSPrint (BootOptionName, sizeof (BootOptionName),
> L"Boot%04x",
> > Number);
> > + ZeroMem (&BootOption, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));
> > + Status = EfiBootManagerVariableToLoadOption (BootOptionName,
> > &BootOption);
> > +
> > + if (!EFI_ERROR (Status)) {
> > + *OptionBuf = AllocatePool (sizeof
> > (EFI_BOOT_MANAGER_LOAD_OPTION));
> > + CopyMem (*OptionBuf, &BootOption, sizeof
> > (EFI_BOOT_MANAGER_LOAD_OPTION));
> > + return EFI_SUCCESS;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Get Active EFI System Partition within GPT based on device path.
> > +
> > + @param[in] DevicePath Device path to find a active EFI System Partition
> > + @param[out] FsHandle BootList points to all boot options returned
> > +
> > + @retval EFI_SUCCESS Active EFI System Partition is succesfully found
> > + @retval EFI_NOT_FOUND No Active EFI System Partition is found
> > +
> > +**/
> > +EFI_STATUS
> > +GetEfiSysPartitionFromDevPath(
> > + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
> > + OUT EFI_HANDLE *FsHandle
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
> > + HARDDRIVE_DEVICE_PATH *Hd;
> > + EFI_HANDLE Handle;
> > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
> > +
> > + //
> > + // Check if the device path contains GPT node
> > + //
> > + TempDevicePath = DevicePath;
> > + while (!IsDevicePathEnd (TempDevicePath)) {
> > + if ((DevicePathType (TempDevicePath) == MEDIA_DEVICE_PATH) &&
> > + (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP))
> {
> > + Hd = (HARDDRIVE_DEVICE_PATH *)TempDevicePath;
> > + if (Hd->MBRType == MBR_TYPE_EFI_PARTITION_TABLE_HEADER) {
> > + break;
> > + }
> > + }
> > + TempDevicePath = NextDevicePathNode (TempDevicePath);
> > + }
> > +
> > + if (!IsDevicePathEnd (TempDevicePath)) {
> > + //
> > + // Search for EFI system partition protocol on full device path in Boot
> > Option
> > + //
> > + Status = gBS->LocateDevicePath (&gEfiPartTypeSystemPartGuid,
> > &DevicePath, &Handle);
> > +
> > + //
> > + // Search for simple file system on this handler
> > + //
> > + if (!EFI_ERROR(Status)) {
> > + Status = gBS->HandleProtocol(Handle,
> > &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
> > + if (!EFI_ERROR(Status)) {
> > + *FsHandle = Handle;
> > + return EFI_SUCCESS;
> > + }
> > + }
> > + }
> > +
> > + return EFI_NOT_FOUND;
> > +}
> > +
> > +/**
> > + This routine is called to get Simple File System protocol on the first EFI
> > system partition found in
> > + active boot option. The boot option list is detemined in order by
> > + 1. "BootNext"
> > + 2. "BootOrder"
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + device like USB can get enumerated.
> > + @param[in, out] LoadOptionNumber On input, specify the boot option
> to
> > get EFI system partition.
> > + On output, return the OptionNumber of the boot
> option
> > where EFI
> > + system partition is got from.
> > + @param[out] FsFsHandle Simple File System Protocol found on
> first
> > active EFI system partition
> > +
> > + @retval EFI_SUCCESS Simple File System protocol found for EFI system
> > partition
> > + @retval EFI_NOT_FOUND No Simple File System protocol found for EFI
> > system partition
> > +
> > +**/
> > +EFI_STATUS
> > +GetEfiSysPartitionFromActiveBootOption(
> > + IN UINTN MaxRetry,
> > + IN OUT UINT16 **LoadOptionNumber,
> > + OUT EFI_HANDLE *FsHandle
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_BOOT_MANAGER_LOAD_OPTION *BootOptionBuf;
> > + UINTN BootOptionNum;
> > + UINTN Index;
> > + EFI_DEVICE_PATH_PROTOCOL *DevicePath;
> > + EFI_DEVICE_PATH_PROTOCOL *CurFullPath;
> > + EFI_DEVICE_PATH_PROTOCOL *PreFullPath;
> > +
> > + *FsHandle = NULL;
> > +
> > + if (*LoadOptionNumber != NULL) {
> > + BootOptionNum = 1;
> > + Status = GetBootOptionByNumber(**LoadOptionNumber,
> > &BootOptionBuf);
> > + if (EFI_ERROR(Status)) {
> > + DEBUG ((DEBUG_ERROR, "GetBootOptionByIndex Failed %x! No
> > BootOption available for connection\n", Status));
> > + return Status;
> > + }
> > + } else {
> > + Status = GetBootOptionInOrder(&BootOptionBuf, &BootOptionNum);
> > + if (EFI_ERROR(Status)) {
> > + DEBUG ((DEBUG_ERROR, "GetBootOptionInOrder Failed %x! No
> > BootOption available for connection\n", Status));
> > + return Status;
> > + }
> > + }
> > +
> > + //
> > + // Search BootOptionList to check if it is an active boot option with EFI
> > system partition
> > + // 1. Connect device path
> > + // 2. expend short/plug in devicepath
> > + // 3. LoadImage
> > + //
> > + for (Index = 0; Index < BootOptionNum; Index++) {
> > + //
> > + // Get the boot option from the link list
> > + //
> > + DevicePath = BootOptionBuf[Index].FilePath;
> > +
> > + //
> > + // Skip inactive or legacy boot options
> > + //
> > + if ((BootOptionBuf[Index].Attributes & LOAD_OPTION_ACTIVE) == 0 ||
> > + DevicePathType (DevicePath) == BBS_DEVICE_PATH) {
> > + continue;
> > + }
> > +
> > + DEBUG_CODE (
> > + CHAR16 *DevicePathStr;
> > +
> > + DevicePathStr = ConvertDevicePathToText(DevicePath, TRUE, TRUE);
> > + if (DevicePathStr != NULL){
> > + DEBUG((DEBUG_INFO, "Try BootOption %s\n", DevicePathStr));
> > + FreePool(DevicePathStr);
> > + } else {
> > + DEBUG((DEBUG_INFO, "DevicePathToStr failed\n"));
> > + }
> > + );
> > +
> > + CurFullPath = NULL;
> > + //
> > + // Try every full device Path generated from bootoption
> > + //
> > + do {
> > + PreFullPath = CurFullPath;
> > + CurFullPath =
> > EfiBootManagerGetNextLoadOptionDevicePath(DevicePath, CurFullPath);
> > +
> > + if (PreFullPath != NULL) {
> > + FreePool (PreFullPath);
> > + }
> > +
> > + if (CurFullPath == NULL) {
> > + //
> > + // No Active EFI system partition is found in BootOption device path
> > + //
> > + Status = EFI_NOT_FOUND;
> > + break;
> > + }
> > +
> > + DEBUG_CODE (
> > + CHAR16 *DevicePathStr1;
> > +
> > + DevicePathStr1 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);
> > + if (DevicePathStr1 != NULL){
> > + DEBUG((DEBUG_INFO, "Full device path %s\n", DevicePathStr1));
> > + FreePool(DevicePathStr1);
> > + }
> > + );
> > +
> > + //
> > + // Make sure the boot option device path connected.
> > + // Only handle first device in boot option. Other optional device paths
> > are described as OSV specific
> > + // FullDevice could contain extra directory & file info. So don't check
> > connection status here.
> > + //
> > + EfiBootManagerConnectDevicePath (CurFullPath, NULL);
> > + Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);
> > +
> > + //
> > + // Some relocation device like USB need more time to get enumerated
> > + //
> > + while (EFI_ERROR(Status) && MaxRetry > 0) {
> > + EfiBootManagerConnectDevicePath(CurFullPath, NULL);
> > +
> > + //
> > + // Search for EFI system partition protocol on full device path in Boot
> > Option
> > + //
> > + Status = GetEfiSysPartitionFromDevPath(CurFullPath, FsHandle);
> > + if (!EFI_ERROR(Status)) {
> > + break;
> > + }
> > + DEBUG((DEBUG_ERROR, "GetEfiSysPartitionFromDevPath
> Loop %x\n",
> > Status));
> > + //
> > + // Stall 100ms if connection failed to ensure USB stack is ready
> > + //
> > + gBS->Stall(100000);
> > + MaxRetry --;
> > + }
> > + } while(EFI_ERROR(Status));
> > +
> > + //
> > + // Find a qualified Simple File System
> > + //
> > + if (!EFI_ERROR(Status)) {
> > + break;
> > + }
> > +
> > + }
> > +
> > + //
> > + // Return the OptionNumber of the boot option where EFI system
> > partition is got from
> > + //
> > + if (*LoadOptionNumber == NULL) {
> > + *LoadOptionNumber = AllocateCopyPool (sizeof(UINT16), (UINT16 *)
> > &BootOptionBuf[Index].OptionNumber);
> > + }
> > +
> > + //
> > + // No qualified EFI system partition found
> > + //
> > + if (*FsHandle == NULL) {
> > + Status = EFI_NOT_FOUND;
> > + }
> > +
> > + DEBUG_CODE (
> > + CHAR16 *DevicePathStr2;
> > + if (*FsHandle != NULL) {
> > + DevicePathStr2 = ConvertDevicePathToText(CurFullPath, TRUE, TRUE);
> > + if (DevicePathStr2 != NULL){
> > + DEBUG((DEBUG_INFO, "Found Active EFI System Partion on %s\n",
> > DevicePathStr2));
> > + FreePool(DevicePathStr2);
> > + }
> > + } else {
> > + DEBUG((DEBUG_INFO, "Failed to found Active EFI System Partion\n"));
> > + }
> > + );
> > +
> > + if (CurFullPath != NULL) {
> > + FreePool(CurFullPath);
> > + }
> > +
> > + //
> > + // Free BootOption Buffer
> > + //
> > + for (Index = 0; Index < BootOptionNum; Index++) {
> > + if (BootOptionBuf[Index].Description != NULL) {
> > + FreePool(BootOptionBuf[Index].Description);
> > + }
> > +
> > + if (BootOptionBuf[Index].FilePath != NULL) {
> > + FreePool(BootOptionBuf[Index].FilePath);
> > + }
> > +
> > + if (BootOptionBuf[Index].OptionalData != NULL) {
> > + FreePool(BootOptionBuf[Index].OptionalData);
> > + }
> > + }
> > +
> > + FreePool(BootOptionBuf);
> > +
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + This routine is called to get all file infos with in a given dir & with given file
> > attribute, the file info is listed in
> > + alphabetical order described in UEFI spec.
> > +
> > + @param[in] Dir Directory file handler
> > + @param[in] FileAttr Attribute of file to be red from directory
> > + @param[out] FileInfoList File images info list red from directory
> > + @param[out] FileNum File images number red from directory
> > +
> > + @retval EFI_SUCCESS File FileInfo list in the given
> > +
> > +**/
> > +EFI_STATUS
> > +GetFileInfoListInAlphabetFromDir(
> > + IN EFI_FILE_HANDLE Dir,
> > + IN UINT64 FileAttr,
> > + OUT LIST_ENTRY *FileInfoList,
> > + OUT UINTN *FileNum
> > + )
> > +{
> > + EFI_STATUS Status;
> > + FILE_INFO_ENTRY *NewFileInfoEntry;
> > + FILE_INFO_ENTRY *TempFileInfoEntry;
> > + EFI_FILE_INFO *FileInfo;
> > + CHAR16 *NewFileName;
> > + CHAR16 *ListedFileName;
> > + CHAR16 *NewFileNameExtension;
> > + CHAR16 *ListedFileNameExtension;
> > + CHAR16 *TempNewSubStr;
> > + CHAR16 *TempListedSubStr;
> > + LIST_ENTRY *Link;
> > + BOOLEAN NoFile;
> > + UINTN FileCount;
> > + UINTN IndexNew;
> > + UINTN IndexListed;
> > + UINTN NewSubStrLen;
> > + UINTN ListedSubStrLen;
> > + INTN SubStrCmpResult;
> > +
> > + Status = EFI_SUCCESS;
> > + NewFileName = NULL;
> > + ListedFileName = NULL;
> > + NewFileNameExtension = NULL;
> > + ListedFileNameExtension = NULL;
> > + TempNewSubStr = NULL;
> > + TempListedSubStr = NULL;
> > + NoFile = FALSE;
> > + FileCount = 0;
> > +
> > + InitializeListHead(FileInfoList);
> > +
> > + TempNewSubStr = (CHAR16 *)
> > AllocateZeroPool(MAX_FILE_NAME_SIZE);
> > + TempListedSubStr = (CHAR16 *)
> > AllocateZeroPool(MAX_FILE_NAME_SIZE);
> > +
> > + if (TempNewSubStr == NULL || TempListedSubStr == NULL ) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > +
> > + for ( Status = FileHandleFindFirstFile(Dir, &FileInfo)
> > + ; !EFI_ERROR(Status) && !NoFile
> > + ; Status = FileHandleFindNextFile(Dir, FileInfo, &NoFile)
> > + ){
> > +
> > + //
> > + // Skip file with mismatching File attribute
> > + //
> > + if ((FileInfo->Attribute & (FileAttr)) == 0) {
> > + continue;
> > + }
> > +
> > + NewFileInfoEntry = NULL;
> > + NewFileInfoEntry =
> > (FILE_INFO_ENTRY*)AllocateZeroPool(sizeof(FILE_INFO_ENTRY));
> > + if (NewFileInfoEntry == NULL) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > + NewFileInfoEntry->Signature = FILE_INFO_SIGNATURE;
> > + NewFileInfoEntry->FileInfo = AllocateCopyPool((UINTN) FileInfo->Size,
> > FileInfo);
> > + if (NewFileInfoEntry->FileInfo == NULL) {
> > + FreePool(NewFileInfoEntry);
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > +
> > + NewFileInfoEntry->FileNameFirstPart = (CHAR16 *)
> > AllocateZeroPool(MAX_FILE_NAME_SIZE);
> > + if (NewFileInfoEntry->FileNameFirstPart == NULL) {
> > + FreePool(NewFileInfoEntry->FileInfo);
> > + FreePool(NewFileInfoEntry);
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > + NewFileInfoEntry->FileNameSecondPart = (CHAR16 *)
> > AllocateZeroPool(MAX_FILE_NAME_SIZE);
> > + if (NewFileInfoEntry->FileNameSecondPart == NULL) {
> > + FreePool(NewFileInfoEntry->FileInfo);
> > + FreePool(NewFileInfoEntry->FileNameFirstPart);
> > + FreePool(NewFileInfoEntry);
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Splitter the whole New file name into 2 parts between the last period
> > L'.' into NewFileName NewFileExtension
> > + // If no period in the whole file name. NewFileExtension is set to L'\0'
> > + //
> > + NewFileName = NewFileInfoEntry->FileNameFirstPart;
> > + NewFileNameExtension = NewFileInfoEntry->FileNameSecondPart;
> > + SplitFileNameExtension(FileInfo->FileName, NewFileName,
> > NewFileNameExtension);
> > + UpperCaseString(NewFileName);
> > + UpperCaseString(NewFileNameExtension);
> > +
> > + //
> > + // Insert capsule file in alphabetical ordered list
> > + //
> > + for (Link = FileInfoList->ForwardLink; Link != FileInfoList; Link = Link-
> > >ForwardLink) {
> > + //
> > + // Get the FileInfo from the link list
> > + //
> > + TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> > FILE_INFO_SIGNATURE);
> > + ListedFileName = TempFileInfoEntry->FileNameFirstPart;
> > + ListedFileNameExtension = TempFileInfoEntry->FileNameSecondPart;
> > +
> > + //
> > + // Follow rule in UEFI spec 8.5.5 to compare file name
> > + //
> > + IndexListed = 0;
> > + IndexNew = 0;
> > + while (TRUE){
> > + //
> > + // First compare each substrings in NewFileName & ListedFileName
> > between periods
> > + //
> > + GetSubStringBeforePeriod(&NewFileName[IndexNew],
> > TempNewSubStr, &NewSubStrLen);
> > + GetSubStringBeforePeriod(&ListedFileName[IndexListed],
> > TempListedSubStr, &ListedSubStrLen);
> > + if (NewSubStrLen > ListedSubStrLen) {
> > + //
> > + // Substr in NewFileName is longer. Pad tail with SPACE
> > + //
> > + PadStrInTail(TempListedSubStr, NewSubStrLen - ListedSubStrLen, L'
> ');
> > + } else if (NewSubStrLen < ListedSubStrLen){
> > + //
> > + // Substr in ListedFileName is longer. Pad tail with SPACE
> > + //
> > + PadStrInTail(TempNewSubStr, ListedSubStrLen - NewSubStrLen, L' ');
> > + }
> > +
> > + SubStrCmpResult = StrnCmp(TempNewSubStr, TempListedSubStr,
> > MAX_FILE_NAME_LEN);
> > + if (SubStrCmpResult != 0) {
> > + break;
> > + }
> > +
> > + //
> > + // Move to skip this substring
> > + //
> > + IndexNew += NewSubStrLen;
> > + IndexListed += ListedSubStrLen;
> > + //
> > + // Reach File First Name end
> > + //
> > + if (NewFileName[IndexNew] == L'\0' || ListedFileName[IndexListed]
> ==
> > L'\0') {
> > + break;
> > + }
> > +
> > + //
> > + // Skip the period L'.'
> > + //
> > + IndexNew++;
> > + IndexListed++;
> > + }
> > +
> > + if (SubStrCmpResult < 0) {
> > + //
> > + // NewFileName is smaller. Find the right place to insert New file
> > + //
> > + break;
> > + } else if (SubStrCmpResult == 0) {
> > + //
> > + // 2 cases whole NewFileName is smaller than ListedFileName
> > + // 1. if NewFileName == ListedFileName. Continue to compare
> > FileNameExtension
> > + // 2. if NewFileName is shorter than ListedFileName
> > + //
> > + if (NewFileName[IndexNew] == L'\0') {
> > + if (ListedFileName[IndexListed] != L'\0' ||
> > (StrnCmp(NewFileNameExtension, ListedFileNameExtension,
> > MAX_FILE_NAME_LEN) < 0)) {
> > + break;
> > + }
> > + }
> > + }
> > +
> > + //
> > + // Other case, ListedFileName is smaller. Continue to compare the next
> > file in the list
> > + //
> > + }
> > +
> > + //
> > + // If Find an entry in the list whose name is bigger than new FileInfo in
> > alphabet order
> > + // Insert it before this entry
> > + // else
> > + // Insert at the tail of this list (Link = FileInfoList)
> > + //
> > + InsertTailList(Link, &NewFileInfoEntry->Link);
> > +
> > + FileCount++;
> > + }
> > +
> > + *FileNum = FileCount;
> > +
> > +EXIT:
> > +
> > + if (TempNewSubStr != NULL) {
> > + FreePool(TempNewSubStr);
> > + }
> > +
> > + if (TempListedSubStr != NULL) {
> > + FreePool(TempListedSubStr);
> > + }
> > +
> > + if (EFI_ERROR(Status)) {
> > + while(!IsListEmpty(FileInfoList)) {
> > + Link = FileInfoList->ForwardLink;
> > + RemoveEntryList(Link);
> > +
> > + TempFileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> > FILE_INFO_SIGNATURE);
> > +
> > + FreePool(TempFileInfoEntry->FileInfo);
> > + FreePool(TempFileInfoEntry->FileNameFirstPart);
> > + FreePool(TempFileInfoEntry->FileNameSecondPart);
> > + FreePool(TempFileInfoEntry);
> > + }
> > + *FileNum = 0;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +
> > +/**
> > + This routine is called to get all qualified image from file from an given
> > directory
> > + in alphabetic order. All the file image is copied to allocated boottime
> > memory.
> > + Caller should free these memory
> > +
> > + @param[in] Dir Directory file handler
> > + @param[in] FileAttr Attribute of file to be red from directory
> > + @param[out] FilePtr File images Info buffer red from directory
> > + @param[out] FileNum File images number red from directory
> > +
> > + @retval EFI_SUCCESS Succeed to get all capsules in alphabetic order.
> > +
> > +**/
> > +EFI_STATUS
> > +GetFileImageInAlphabetFromDir(
> > + IN EFI_FILE_HANDLE Dir,
> > + IN UINT64 FileAttr,
> > + OUT IMAGE_INFO **FilePtr,
> > + OUT UINTN *FileNum
> > + )
> > +{
> > + EFI_STATUS Status;
> > + LIST_ENTRY *Link;
> > + EFI_FILE_HANDLE FileHandle;
> > + FILE_INFO_ENTRY *FileInfoEntry;
> > + EFI_FILE_INFO *FileInfo;
> > + UINTN FileCount;
> > + IMAGE_INFO *TempFilePtrBuf;
> > + UINTN Size;
> > + LIST_ENTRY FileInfoList;
> > +
> > + FileHandle = NULL;
> > + FileCount = 0;
> > + TempFilePtrBuf = NULL;
> > + *FilePtr = NULL;
> > +
> > + //
> > + // Get file list in Dir in alphabetical order
> > + //
> > + Status = GetFileInfoListInAlphabetFromDir(
> > + Dir,
> > + FileAttr,
> > + &FileInfoList,
> > + &FileCount
> > + );
> > + if (EFI_ERROR(Status)) {
> > + DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir
> Failed!\n"));
> > + goto EXIT;
> > + }
> > +
> > + if (FileCount == 0) {
> > + DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
> > + Status = EFI_NOT_FOUND;
> > + goto EXIT;
> > + }
> > +
> > + TempFilePtrBuf = (IMAGE_INFO *)AllocateZeroPool(sizeof(IMAGE_INFO)
> > * FileCount);
> > + if (TempFilePtrBuf == NULL) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Read all files from FileInfoList to BS memory
> > + //
> > + FileCount = 0;
> > + for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link-
> > >ForwardLink) {
> > + //
> > + // Get FileInfo from the link list
> > + //
> > + FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> FILE_INFO_SIGNATURE);
> > + FileInfo = FileInfoEntry->FileInfo;
> > +
> > + Status = Dir->Open(
> > + Dir,
> > + &FileHandle,
> > + FileInfo->FileName,
> > + EFI_FILE_MODE_READ,
> > + 0
> > + );
> > + if (EFI_ERROR(Status)){
> > + continue;
> > + }
> > +
> > + Size = (UINTN)FileInfo->FileSize;
> > + TempFilePtrBuf[FileCount].ImageAddress = AllocateZeroPool(Size);
> > + if (TempFilePtrBuf[FileCount].ImageAddress == NULL) {
> > + DEBUG((DEBUG_ERROR, "Fail to allocate memory for capsule. Stop
> > processing the rest.\n"));
> > + break;
> > + }
> > +
> > + Status = FileHandle->Read(
> > + FileHandle,
> > + &Size,
> > + TempFilePtrBuf[FileCount].ImageAddress
> > + );
> > +
> > + FileHandle->Close(FileHandle);
> > +
> > + //
> > + // Skip read error file
> > + //
> > + if (EFI_ERROR(Status) || Size != (UINTN)FileInfo->FileSize) {
> > + //
> > + // Remove this error file info accordingly
> > + // & move Link to BackLink
> > + //
> > + Link = RemoveEntryList(Link);
> > + Link = Link->BackLink;
> > +
> > + FreePool(FileInfoEntry->FileInfo);
> > + FreePool(FileInfoEntry->FileNameFirstPart);
> > + FreePool(FileInfoEntry->FileNameSecondPart);
> > + FreePool(FileInfoEntry);
> > +
> > + FreePool(TempFilePtrBuf[FileCount].ImageAddress);
> > + TempFilePtrBuf[FileCount].ImageAddress = NULL;
> > + TempFilePtrBuf[FileCount].FileInfo = NULL;
> > +
> > + continue;
> > + }
> > + TempFilePtrBuf[FileCount].FileInfo = FileInfo;
> > + FileCount++;
> > + }
> > +
> > + DEBUG_CODE (
> > + for (Link = FileInfoList.ForwardLink; Link != &FileInfoList; Link = Link-
> > >ForwardLink) {
> > + FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> FILE_INFO_SIGNATURE);
> > + FileInfo = FileInfoEntry->FileInfo;
> > + DEBUG((DEBUG_INFO, "Successfully read capsule file %s from disk.\n",
> > FileInfo->FileName));
> > + }
> > + );
> > +
> > +EXIT:
> > +
> > + *FilePtr = TempFilePtrBuf;
> > + *FileNum = FileCount;
> > +
> > + //
> > + // FileInfo will be freed by Calller
> > + //
> > + while(!IsListEmpty(&FileInfoList)) {
> > + Link = FileInfoList.ForwardLink;
> > + RemoveEntryList(Link);
> > +
> > + FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> FILE_INFO_SIGNATURE);
> > +
> > + FreePool(FileInfoEntry->FileNameFirstPart);
> > + FreePool(FileInfoEntry->FileNameSecondPart);
> > + FreePool(FileInfoEntry);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This routine is called to remove all qualified image from file from an given
> > directory.
> > +
> > + @param[in] Dir Directory file handler
> > + @param[in] FileAttr Attribute of files to be deleted
> > +
> > + @retval EFI_SUCCESS Succeed to remove all files from an given directory.
> > +
> > +**/
> > +EFI_STATUS
> > +RemoveFileFromDir(
> > + IN EFI_FILE_HANDLE Dir,
> > + IN UINT64 FileAttr
> > + )
> > +{
> > + EFI_STATUS Status;
> > + LIST_ENTRY *Link;
> > + LIST_ENTRY FileInfoList;
> > + EFI_FILE_HANDLE FileHandle;
> > + FILE_INFO_ENTRY *FileInfoEntry;
> > + EFI_FILE_INFO *FileInfo;
> > + UINTN FileCount;
> > +
> > + FileHandle = NULL;
> > +
> > + //
> > + // Get file list in Dir in alphabetical order
> > + //
> > + Status = GetFileInfoListInAlphabetFromDir(
> > + Dir,
> > + FileAttr,
> > + &FileInfoList,
> > + &FileCount
> > + );
> > + if (EFI_ERROR(Status)) {
> > + DEBUG ((DEBUG_ERROR, "GetFileInfoListInAlphabetFromDir
> Failed!\n"));
> > + goto EXIT;
> > + }
> > +
> > + if (FileCount == 0) {
> > + DEBUG ((DEBUG_ERROR, "No file found in Dir!\n"));
> > + Status = EFI_NOT_FOUND;
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Delete all files with given attribute in Dir
> > + //
> > + for (Link = FileInfoList.ForwardLink; Link != &(FileInfoList); Link = Link-
> > >ForwardLink) {
> > + //
> > + // Get FileInfo from the link list
> > + //
> > + FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> FILE_INFO_SIGNATURE);
> > + FileInfo = FileInfoEntry->FileInfo;
> > +
> > + Status = Dir->Open(
> > + Dir,
> > + &FileHandle,
> > + FileInfo->FileName,
> > + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
> > + 0
> > + );
> > + if (EFI_ERROR(Status)){
> > + continue;
> > + }
> > +
> > + Status = FileHandle->Delete(FileHandle);
> > + }
> > +
> > +EXIT:
> > +
> > + while(!IsListEmpty(&FileInfoList)) {
> > + Link = FileInfoList.ForwardLink;
> > + RemoveEntryList(Link);
> > +
> > + FileInfoEntry = CR (Link, FILE_INFO_ENTRY, Link,
> FILE_INFO_SIGNATURE);
> > +
> > + FreePool(FileInfoEntry->FileInfo);
> > + FreePool(FileInfoEntry);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This routine is called to get all caspules from file. The capsule file image is
> > + copied to BS memory. Caller is responsible to free them.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > + @param[out] CapsulePtr Copied Capsule file Image Info buffer
> > + @param[out] CapsuleNum CapsuleNumber
> > + @param[out] FsHandle File system handle
> > + @param[out] LoadOptionNumber OptionNumber of boot option
> > +
> > + @retval EFI_SUCCESS Succeed to get all capsules.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
>
>
> Please help to remove the keyword 'EFIAPI' for internal function.
>
>
> > +GetAllCapsuleOnDisk(
> > + IN UINTN MaxRetry,
> > + OUT IMAGE_INFO **CapsulePtr,
> > + OUT UINTN *CapsuleNum,
> > + OUT EFI_HANDLE *FsHandle,
> > + OUT UINT16 *LoadOptionNumber
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
> > + EFI_FILE_HANDLE RootDir;
> > + EFI_FILE_HANDLE FileDir;
> > + UINT16 *TempOptionNumber;
> > +
> > + Fs = NULL;
> > + RootDir = NULL;
> > + FileDir = NULL;
> > + TempOptionNumber = NULL;
> > + *CapsuleNum = 0;
> > +
> > + Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry,
> > &TempOptionNumber, FsHandle);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->HandleProtocol(*FsHandle,
> > &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + Status = Fs->OpenVolume(Fs, &RootDir);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + Status = RootDir->Open(
> > + RootDir,
> > + &FileDir,
> > + EFI_CAPSULE_FILE_DIRECTORY,
> > + EFI_FILE_MODE_READ,
> > + 0
> > + );
> > + if (EFI_ERROR(Status)) {
> > + DEBUG((DEBUG_ERROR, "CodLibGetAllCapsuleOnDisk fail to open
> > RootDir!\n"));
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Only Load files with EFI_FILE_SYSTEM or EFI_FILE_ARCHIVE attribute
> > + // ignore EFI_FILE_READ_ONLY, EFI_FILE_HIDDEN, EFI_FILE_RESERVED,
> > EFI_FILE_DIRECTORY
> > + //
> > + Status = GetFileImageInAlphabetFromDir(
> > + FileDir,
> > + EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE,
> > + CapsulePtr,
> > + CapsuleNum
> > + );
> > + DEBUG((DEBUG_INFO, "GetFileImageInAlphabetFromDir status %x\n",
> > Status));
> > +
> > + //
> > + // Always remove file to avoid deadloop in capsule process
> > + //
> > + Status = RemoveFileFromDir(FileDir, EFI_FILE_SYSTEM |
> > EFI_FILE_ARCHIVE);
> > + DEBUG((DEBUG_INFO, "RemoveFileFromDir status %x\n", Status));
> > +
> > + if (LoadOptionNumber != NULL) {
> > + *LoadOptionNumber = *TempOptionNumber;
> > + }
> > +
> > +EXIT:
> > +
> > + if (FileDir != NULL) {
> > + FileDir->Close (FileDir);
> > + }
> > +
> > + if (RootDir != NULL) {
> > + RootDir->Close (RootDir);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Build Gather list for a list of capsule images.
> > +
> > + @param[in] CapsuleBuffer An array of pointer to capsule images
> > + @param[in] CapsuleSize 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 *CapsuleSize,
> > + IN UINTN CapsuleNum,
> > + OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;
> > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;
> > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;
> > + UINTN Index;
> > +
> > + BlockDescriptors1 = NULL;
> > + BlockDescriptorPre = NULL;
> > + BlockDescriptorsHeader = NULL;
> > +
> > + for (Index = 0; Index < CapsuleNum; Index++) {
> > + //
> > + // Allocate memory for the descriptors.
> > + //
> > + BlockDescriptors1 = AllocateZeroPool (2 * sizeof
> > (EFI_CAPSULE_BLOCK_DESCRIPTOR));
> > + if (BlockDescriptors1 == NULL) {
> > + DEBUG ((DEBUG_ERROR, "BuildGatherList: failed to allocate memory
> for
> > descriptors\n"));
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto ERREXIT;
> > + } else {
> > + DEBUG ((DEBUG_INFO, "BuildGatherList: creating capsule descriptors
> at
> > 0x%X\n", (UINTN) BlockDescriptors1));
> > + }
> > +
> > + //
> > + // Record descirptor header
> > + //
> > + if (Index == 0) {
> > + BlockDescriptorsHeader = BlockDescriptors1;
> > + }
> > +
> > + if (BlockDescriptorPre != NULL) {
> > + BlockDescriptorPre->Union.ContinuationPointer = (UINTN)
> > BlockDescriptors1;
> > + BlockDescriptorPre->Length = 0;
> > + }
> > +
> > + BlockDescriptors1->Union.DataBlock = (UINTN) CapsuleBuffer[Index];
> > + BlockDescriptors1->Length = CapsuleSize[Index];
> > +
> > + BlockDescriptorPre = BlockDescriptors1 + 1;
> > + BlockDescriptors1 = NULL;
> > + }
> > +
> > + //
> > + // Null-terminate.
> > + //
> > + if (BlockDescriptorPre != NULL) {
> > + BlockDescriptorPre->Union.ContinuationPointer = (UINTN)NULL;
> > + BlockDescriptorPre->Length = 0;
> > + *BlockDescriptors = BlockDescriptorsHeader;
> > + }
> > +
> > + return EFI_SUCCESS;
> > +
> > +ERREXIT:
> > + if (BlockDescriptors1 != NULL) {
> > + FreePool (BlockDescriptors1);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This routine is called to check if CapsuleOnDisk flag in OsIndications
> > Variable
> > + is enabled.
> > +
> > + @retval TRUE Flag is enabled
> > + @retval FALSE Flag is not enabled
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +CoDCheckCapsuleOnDiskFlag(
> > + VOID
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT64 OsIndication;
> > + UINTN DataSize;
> > +
> > + //
> > + // Check File Capsule Delivery Supported Flag in OsIndication variable
> > + //
> > + OsIndication = 0;
> > + DataSize = sizeof(UINT64);
> > + Status = gRT->GetVariable (
> > + EFI_OS_INDICATIONS_VARIABLE_NAME,
> > + &gEfiGlobalVariableGuid,
> > + NULL,
> > + &DataSize,
> > + &OsIndication
> > + );
> > + if (!EFI_ERROR(Status) &&
> > + (OsIndication &
> > EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
> > + return TRUE;
> > + }
> > +
> > + return FALSE;
> > +}
> > +
> > +
> > +/**
> > + This routine is called to clear CapsuleOnDisk flags including OsIndications
> > and BootNext variable.
> > +
> > + @retval EFI_SUCCESS All Capsule On Disk flags are cleared
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDClearCapsuleOnDiskFlag(
> > + VOID
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINT64 OsIndication;
> > + UINTN DataSize;
> > +
> > + //
> > + // Reset File Capsule Delivery Supported Flag in OsIndication variable
> > + //
> > + OsIndication = 0;
> > + DataSize = sizeof(UINT64);
> > + Status = gRT->GetVariable (
> > + EFI_OS_INDICATIONS_VARIABLE_NAME,
> > + &gEfiGlobalVariableGuid,
> > + NULL,
> > + &DataSize,
> > + &OsIndication
> > + );
> > + if (EFI_ERROR(Status) ||
> > + (OsIndication &
> > EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) == 0) {
> > + return Status;
> > + }
> > +
> > + OsIndication &=
> > ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
> > + Status = gRT->SetVariable (
> > + EFI_OS_INDICATIONS_VARIABLE_NAME,
> > + &gEfiGlobalVariableGuid,
> > + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
> > + sizeof(UINT64),
> > + &OsIndication
> > + );
> > + ASSERT(!EFI_ERROR(Status));
> > +
> > + //
> > + // Delete BootNext variable. Capsule Process may reset system, so can't
> > rely on Bds to clear this variable
> > + //
> > + Status = gRT->SetVariable (
> > + EFI_BOOT_NEXT_VARIABLE_NAME,
> > + &gEfiGlobalVariableGuid,
> > + 0,
> > + 0,
> > + NULL
> > + );
> > + ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
> > +
> > + return EFI_SUCCESS;
> > +}
> > +
> > +/**
> > + This routine is called to clear Capsule On Disk Relocation flag
> > + The flag is the total size of capsules being relocated. It is saved
> > + in CapsuleOnDisk Relocation Info varible in form of UINT64
> > +
> > + @param[out] CapsuleRelocInfo The value of "CapsuleRelocInfo" variable
> > +
> > + @retval EFI_SUCCESS Capsule Relocation flag is cleared
> > +
> > +**/
> > +EFI_STATUS
> > +CoDCheckCapsuleRelocationInfo(
> > + OUT BOOLEAN *CapsuleRelocInfo
> > + )
>
>
> I do not see the above function being used internally/externally.
> Please help to check and remove it.
>
>
> > +{
> > + EFI_STATUS Status;
> > + UINTN DataSize;
> > +
> > + DataSize = sizeof(BOOLEAN);
> > +
> > + Status= gRT->GetVariable (
> > + COD_RELOCATION_INFO_VAR_NAME,
> > + &gEfiCapsuleVendorGuid,
> > + NULL,
> > + &DataSize,
> > + CapsuleRelocInfo
> > + );
> > +
> > + if (DataSize != sizeof(BOOLEAN)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + This routine is called to clear CapsuleOnDisk Relocation Info variable.
> > + Total Capsule On Disk length is recorded in this variable
> > +
> > + @retval EFI_SUCCESS Capsule On Disk flags are cleared
> > +
> > +**/
> > +EFI_STATUS
> > +CoDClearCapsuleRelocationInfo(
> > + VOID
> > + )
> > +{
> > + return gRT->SetVariable (
> > + COD_RELOCATION_INFO_VAR_NAME,
> > + &gEfiCapsuleVendorGuid,
> > + 0,
> > + 0,
> > + NULL
> > + );
> > +}
> > +
> > +/**
> > + Relocate Capsule on Disk from EFI system partition to a platform-specific
> > NV storage device
> > + with BlockIo protocol. Relocation device path, identified by
> > PcdCodRelocationDevPath, must
> > + be a full device path.
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + Side Effects:
> > + Content corruption. Block IO write directly touches low level write.
> Orignal
> > partitions, file systems
> > + of the relocation device will be corrupted.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated
> to
> > the platform-specific device.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
>
>
> Please help to remove 'EFIAPI' for this internal function.
>
>
> > +RelocateCapsuleToDisk(
> > + UINTN MaxRetry
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN CapsuleOnDiskNum;
> > + UINTN Index;
> > + UINTN DataSize;
> > + UINT64 TotalImageSize;
> > + UINT64 TotalImageNameSize;
> > + IMAGE_INFO *CapsuleOnDiskBuf;
> > + EFI_HANDLE Handle;
> > + EFI_HANDLE TempHandle;
> > + EFI_HANDLE *HandleBuffer;
> > + UINTN NumberOfHandles;
> > + EFI_BLOCK_IO_PROTOCOL *BlockIo;
> > + UINT8 *CapsuleDataBuf;
> > + UINT8 *CapsulePtr;
> > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
> > + EFI_FILE_HANDLE RootDir;
> > + EFI_FILE_HANDLE TempCodFile;
> > + UINT64 TempCodFileSize;
> > + EFI_DEVICE_PATH *TempDevicePath;
> > + BOOLEAN RelocationInfo;
> > + UINT16 LoadOptionNumber;
> > + EFI_CAPSULE_HEADER FileNameCapsuleHeader;
> > +
> > + RootDir = NULL;
> > + TempCodFile = NULL;
> > + HandleBuffer = NULL;
> > + CapsuleDataBuf = NULL;
> > + CapsuleOnDiskBuf = NULL;
> > + NumberOfHandles = 0;
> > +
> > + DEBUG ((DEBUG_INFO, "CapsuleOnDisk RelocateCapsule Enter\n"));
> > +
> > + //
> > + // 1. Load all Capsule On Disks in to memory
> > + //
> > + Status = GetAllCapsuleOnDisk(MaxRetry, &CapsuleOnDiskBuf,
> > &CapsuleOnDiskNum, &Handle, &LoadOptionNumber);
> > + if (EFI_ERROR(Status) || CapsuleOnDiskNum == 0) {
> > + DEBUG ((DEBUG_INFO, "RelocateCapsule: GetAllCapsuleOnDisk Status -
> > 0x%x\n", Status));
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + //
> > + // 2. Connect platform special dev path or Use EFI System Partition as
> > relocation device
> > + //
> > + if (PcdGetSize(PcdCodRelocationDevPath) >
> > sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
>
>
> Do we need a validity check for the device path specified by
> 'PcdCodRelocationDevPath'? Since it is from external input (by configuring
> the PCD).
>
> Also, should we consider an error when the above 'if' statement is not met?
>
> For the implementation in the patch, when:
> if (PcdGetSize(PcdCodRelocationDevPath) >
> sizeof(EFI_DEVICE_PATH_PROTOCOL)) {
> evaluates to false, 'Handle' will still carry the value for the device where
> the capsules are placed. And then, the function may continue to write
> content
> on this media device. I think this should not happen, right?
>
No, that's how it is designed.
PcdCodRelocationDevPath is used by platform to specify a device to store temp Cod relocation file.
If this PCD is not available, it means that platform doesn't have a requirement to store the file to a specific place.
Then save the file to the device where the capsules are placed.
>
> > + Status = EfiBootManagerConnectDevicePath ((EFI_DEVICE_PATH
> > *)PcdGetPtr(PcdCodRelocationDevPath), &TempHandle);
> > + if (EFI_ERROR(Status)) {
> > + DEBUG ((DEBUG_ERROR, "RelocateCapsule:
> > EfiBootManagerConnectDevicePath Status - 0x%x\n", Status));
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Connect all the child handle. Partition & FAT drivers are allowed in this
> > case
> > + //
> > + gBS->ConnectController (TempHandle, NULL, NULL, TRUE);
> > + Status = gBS->LocateHandleBuffer(
> > + ByProtocol,
> > + &gEfiSimpleFileSystemProtocolGuid,
> > + NULL,
> > + &NumberOfHandles,
> > + &HandleBuffer
> > + );
> > + if (EFI_ERROR(Status)) {
> > + DEBUG ((DEBUG_ERROR, "RelocateCapsule: LocateHandleBuffer
> Status -
> > 0x%x\n", Status));
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Find first Simple File System Handle which can match
> > PcdCodRelocationDevPath
> > + //
> > + for (Index = 0; Index < NumberOfHandles; Index++) {
> > + Status = gBS->HandleProtocol(HandleBuffer[Index],
> > &gEfiDevicePathProtocolGuid, (VOID **)&TempDevicePath);
> > + if (EFI_ERROR(Status)) {
> > + continue;
> > + }
> > +
> > + DataSize = GetDevicePathSize((EFI_DEVICE_PATH
> > *)PcdGetPtr(PcdCodRelocationDevPath)) - sizeof(EFI_DEVICE_PATH);
> > + if (0 == CompareMem((EFI_DEVICE_PATH
> > *)PcdGetPtr(PcdCodRelocationDevPath), TempDevicePath, DataSize)) {
> > + Handle = HandleBuffer[Index];
> > + break;
> > + }
> > + }
> > +
> > + FreePool(HandleBuffer);
> > +
> > + if (Index == NumberOfHandles) {
> > + DEBUG ((DEBUG_ERROR, "RelocateCapsule: No simple file system
> > protocol found.\n"));
> > + Status = EFI_NOT_FOUND;
> > + }
> > + }
> > +
> > + Status = gBS->HandleProtocol(Handle, &gEfiBlockIoProtocolGuid, (VOID
> > **)&BlockIo);
> > + if (EFI_ERROR(Status) || BlockIo->Media->ReadOnly) {
> > + DEBUG((DEBUG_ERROR, "Fail to find Capsule on Disk relocation BlockIo
> > device or device is ReadOnly!\n"));
> > + return Status;
> > + }
> > +
> > + Status = gBS->HandleProtocol(Handle,
> &gEfiSimpleFileSystemProtocolGuid,
> > (VOID **)&Fs);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Check if device used to relocate Capsule On Disk is big enough
> > + //
> > + TotalImageSize = 0;
> > + TotalImageNameSize = 0;
> > + for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
> > + //
> > + // Overflow check
> > + //
> > + if (MAX_ADDRESS - (UINTN)TotalImageSize <=
> > CapsuleOnDiskBuf[Index].FileInfo->FileSize) {
> > + return EFI_INVALID_PARAMETER;
>
>
> Will memory leak happen in this error handling?
>
>
> > + }
> > +
> > + if (MAX_ADDRESS - (UINTN)TotalImageNameSize <=
> > StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName)) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + TotalImageSize += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
> > + TotalImageNameSize += StrSize(CapsuleOnDiskBuf[Index].FileInfo-
> > >FileName);
> > + DEBUG((DEBUG_INFO, "RelocateCapsule: %x
> > Size %x\n",CapsuleOnDiskBuf[Index].FileInfo->FileName,
> > CapsuleOnDiskBuf[Index].FileInfo->FileSize));
> > + }
> > +
> > + DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageSize %x\n",
> > TotalImageSize));
> > + DEBUG((DEBUG_INFO, "RelocateCapsule: TotalImageNameSize %x\n",
> > TotalImageNameSize));
> > +
> > + if (MAX_ADDRESS - (UINTN)TotalImageNameSize <= sizeof(UINT64) * 2
> ||
> > + MAX_ADDRESS - (UINTN)TotalImageSize <=
> > (UINTN)TotalImageNameSize + sizeof(UINT64) * 2) {
> > + return EFI_INVALID_PARAMETER;
> > + }
> > +
> > + TempCodFileSize = sizeof(UINT64) + TotalImageSize +
> > sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;
> > +
> > + //
> > + // Check if CapsuleTotalSize. There could be reminder, so use LastBlock
> > number directly
> > + //
> > + if (DivU64x32(TempCodFileSize, BlockIo->Media->BlockSize) > BlockIo-
> > >Media->LastBlock) {
> > + DEBUG((DEBUG_ERROR, "RelocateCapsule: Relocation device isn't big
> > enough to hold all Capsule on Disk!\n"));
> > + DEBUG((DEBUG_ERROR, "TotalImageSize = %x\n", TotalImageSize));
> > + DEBUG((DEBUG_ERROR, "TotalImageNameSize = %x\n",
> > TotalImageNameSize));
> > + DEBUG((DEBUG_ERROR, "RelocationDev BlockSize = %x LastBlock
> = %x\n",
> > BlockIo->Media->BlockSize, BlockIo->Media->LastBlock));
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > +
> > + CapsuleDataBuf = AllocatePool((UINTN) TempCodFileSize);
> > + if (CapsuleDataBuf == NULL) {
> > + Status = EFI_OUT_OF_RESOURCES;
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // First UINT64 reserved for total image size, including capsule name
> > capsule.
> > + //
> > + *(UINT64 *) CapsuleDataBuf = TotalImageSize +
> > sizeof(EFI_CAPSULE_HEADER) + TotalImageNameSize;
> > +
> > + //
> > + // Line up all the Capsule on Disk and write to relocation disk at one time.
> It
> > could save some time in disk write
> > + //
> > + for (Index = 0, CapsulePtr = CapsuleDataBuf + sizeof(UINT64); Index <
> > CapsuleOnDiskNum; Index++) {
> > + CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].ImageAddress,
> (UINTN)
> > CapsuleOnDiskBuf[Index].FileInfo->FileSize);
> > + CapsulePtr += CapsuleOnDiskBuf[Index].FileInfo->FileSize;
> > + }
> > +
> > + //
> > + // Line the capsule header for capsule name capsule.
> > + //
> > + CopyGuid(&FileNameCapsuleHeader.CapsuleGuid,
> > &gEdkiiCapsuleOnDiskNameGuid);
> > + FileNameCapsuleHeader.CapsuleImageSize = (UINT32)
> > TotalImageNameSize + sizeof(EFI_CAPSULE_HEADER);
> > + FileNameCapsuleHeader.Flags =
> > CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
> > + FileNameCapsuleHeader.HeaderSize = sizeof(EFI_CAPSULE_HEADER);
> > + CopyMem(CapsulePtr, &FileNameCapsuleHeader,
> > FileNameCapsuleHeader.HeaderSize);
> > + CapsulePtr += FileNameCapsuleHeader.HeaderSize;
> > +
> > + //
> > + // Line up all the Capsule file names.
> > + //
> > + for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
> > + CopyMem(CapsulePtr, CapsuleOnDiskBuf[Index].FileInfo->FileName,
> > StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName));
> > + CapsulePtr += StrSize(CapsuleOnDiskBuf[Index].FileInfo->FileName);
> > + }
> > +
> > + //
> > + // 5. Flash all Capsules on Disk to TempCoD.tmp under RootDir
> > + //
> > + Status = Fs->OpenVolume(Fs, &RootDir);
> > + if (EFI_ERROR(Status)) {
> > + DEBUG((DEBUG_ERROR, "RelocateCapsule: OpenVolume error. %x\n",
> > Status));
> > + goto EXIT;
> > + }
> > +
> > + Status = RootDir->Open(
> > + RootDir,
> > + &TempCodFile,
> > + (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
> > + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
> > + 0
> > + );
> > + if (!EFI_ERROR(Status)) {
> > + //
> > + // Error handling code to prevent malicious code to hold this file to block
> > capsule on disk
> > + //
> > + TempCodFile->Delete(TempCodFile);
> > + }
> > + Status = RootDir->Open(
> > + RootDir,
> > + &TempCodFile,
> > + (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
> > + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
> > EFI_FILE_MODE_CREATE,
> > + 0
> > + );
> > + if (EFI_ERROR(Status)) {
> > + DEBUG((DEBUG_ERROR, "RelocateCapsule: Open TemCoD.tmp
> > error. %x\n", Status));
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Always write at the begining of TempCap file
> > + //
> > + DataSize = (UINTN) TempCodFileSize;
> > + Status = TempCodFile->Write(
> > + TempCodFile,
> > + &DataSize,
> > + CapsuleDataBuf
> > + );
> > + if (EFI_ERROR(Status)) {
> > + DEBUG((DEBUG_ERROR, "RelocateCapsule: Write TemCoD.tmp
> > error. %x\n", Status));
> > + goto EXIT;
> > + }
> > +
> > + if (DataSize != TempCodFileSize) {
> > + Status = EFI_DEVICE_ERROR;
> > + goto EXIT;
> > + }
> > +
> > + //
> > + // Save Capsule On Disk relocation info to "CodRelocationInfo" Var
> > + // It is used in next reboot by TCB
> > + //
> > + RelocationInfo = TRUE;
> > + Status = gRT->SetVariable(
> > + COD_RELOCATION_INFO_VAR_NAME,
> > + &gEfiCapsuleVendorGuid,
> > + EFI_VARIABLE_NON_VOLATILE |
> > EFI_VARIABLE_BOOTSERVICE_ACCESS,
> > + sizeof (BOOLEAN),
> > + &RelocationInfo
> > + );
> > + //
> > + // Save the LoadOptionNumber of the boot option, where the capsule is
> > relocated,
> > + // into "CodRelocationLoadOption" var. It is used in next reboot after
> > capsule is
> > + // updated out of TCB to remove the TempCoDFile.
> > + //
> > + Status = gRT->SetVariable(
> > + COD_RELOCATION_LOAD_OPTION_VAR_NAME,
> > + &gEfiCapsuleVendorGuid,
> > + EFI_VARIABLE_NON_VOLATILE |
> > EFI_VARIABLE_BOOTSERVICE_ACCESS,
> > + sizeof (UINT16),
> > + &LoadOptionNumber
> > + );
> > +
> > +EXIT:
> > +
> > + if (CapsuleDataBuf != NULL) {
> > + FreePool(CapsuleDataBuf);
> > + }
> > +
> > + if (CapsuleOnDiskBuf != NULL) {
> > + //
> > + // Free resources allocated by CodLibGetAllCapsuleOnDisk
> > + //
> > + for (Index = 0; Index < CapsuleOnDiskNum; Index++ ) {
> > + FreePool(CapsuleOnDiskBuf[Index].ImageAddress);
> > + FreePool(CapsuleOnDiskBuf[Index].FileInfo);
> > + }
> > + FreePool(CapsuleOnDiskBuf);
> > + }
> > +
> > + if (TempCodFile != NULL) {
> > + if (EFI_ERROR(Status)) {
> > + TempCodFile->Delete (TempCodFile);
> > + } else {
> > + TempCodFile->Close (TempCodFile);
> > + }
> > + }
> > +
> > + if (RootDir != NULL) {
> > + RootDir->Close (RootDir);
> > + }
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + For the platforms that support Capsule In Ram, reuse the Capsule In Ram
> > to deliver capsule.
> > + Relocate Capsule On Disk to memory and call UpdateCapsule().
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Deliver capsule through Capsule In Ram
> successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
>
> Please help to remove 'EFIAPI' for this internal function.
>
>
> > +RelocateCapsuleToRam (
> > + UINTN MaxRetry
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN CapsuleOnDiskNum;
> > + IMAGE_INFO *CapsuleOnDiskBuf;
> > + EFI_HANDLE Handle;
> > + EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;
> > + VOID **CapsuleBuffer;
> > + UINTN *CapsuleSize;
> > + EFI_CAPSULE_HEADER *FileNameCapsule;
> > + UINTN Index;
> > + UINT8 *StringBuf;
> > + UINTN StringSize;
> > + UINTN TotalStringSize;
> > +
> > + CapsuleOnDiskBuf = NULL;
> > + BlockDescriptors = NULL;
> > + CapsuleBuffer = NULL;
> > + CapsuleSize = NULL;
> > + FileNameCapsule = NULL;
> > + TotalStringSize = 0;
> > +
> > + //
> > + // 1. Load all Capsule On Disks into memory
> > + //
> > + Status = GetAllCapsuleOnDisk (MaxRetry, &CapsuleOnDiskBuf,
> > &CapsuleOnDiskNum, &Handle, NULL);
> > + if (EFI_ERROR (Status) || CapsuleOnDiskNum == 0) {
> > + DEBUG ((DEBUG_ERROR, "GetAllCapsuleOnDisk Status - 0x%x\n",
> > Status));
> > + return EFI_NOT_FOUND;
> > + }
> > +
> > + //
> > + // 2. Add a capsule for Capsule file name strings
> > + //
> > + CapsuleBuffer = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof
> (VOID
> > *));
> > + if (CapsuleBuffer == NULL) {
> > + DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + CapsuleSize = AllocateZeroPool ((CapsuleOnDiskNum + 1) * sizeof
> > (UINTN));
> > + if (CapsuleSize == NULL) {
> > + DEBUG ((DEBUG_ERROR, "Fail to allocate memory for capsules.\n"));
> > + return EFI_OUT_OF_RESOURCES;
>
>
> Potential memory leaks in some error handling paths, please help to
> address them.
>
>
> > + }
> > +
> > + for (Index = 0; Index < CapsuleOnDiskNum; Index++) {
> > + CapsuleBuffer[Index] = (VOID *)(UINTN)
> > CapsuleOnDiskBuf[Index].ImageAddress;
> > + CapsuleSize[Index] = (UINTN) CapsuleOnDiskBuf[Index].FileInfo-
> >FileSize;
> > + TotalStringSize += StrSize (CapsuleOnDiskBuf[Index].FileInfo-
> >FileName);
> > + }
> > +
> > + FileNameCapsule = AllocateZeroPool (sizeof (EFI_CAPSULE_HEADER) +
> > TotalStringSize);
> > + if (FileNameCapsule == NULL) {
> > + DEBUG ((DEBUG_ERROR, "Fail to allocate memory for name
> capsule.\n"));
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + FileNameCapsule->CapsuleImageSize = (UINT32) (sizeof
> > (EFI_CAPSULE_HEADER) + TotalStringSize);
> > + FileNameCapsule->Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
> > + FileNameCapsule->HeaderSize = sizeof (EFI_CAPSULE_HEADER);
> > + CopyGuid (&(FileNameCapsule->CapsuleGuid),
> > &gEdkiiCapsuleOnDiskNameGuid);
> > +
> > + StringBuf = (UINT8 *)FileNameCapsule + FileNameCapsule->HeaderSize;
> > + for (Index = 0; Index < CapsuleOnDiskNum; Index ++) {
> > + StringSize = StrSize (CapsuleOnDiskBuf[Index].FileInfo->FileName);
> > + CopyMem (StringBuf, CapsuleOnDiskBuf[Index].FileInfo->FileName,
> > StringSize);
> > + StringBuf += StringSize;
> > + }
> > +
> > + CapsuleBuffer[CapsuleOnDiskNum] = FileNameCapsule;
> > + CapsuleSize[CapsuleOnDiskNum] = TotalStringSize + sizeof
> > (EFI_CAPSULE_HEADER);
> > +
> > + //
> > + // 3. Build Gather list for the capsules
> > + //
> > + Status = BuildGatherList (CapsuleBuffer, CapsuleSize,
> CapsuleOnDiskNum
> > + 1, &BlockDescriptors);
> > + if (EFI_ERROR (Status) || BlockDescriptors == NULL) {
> > + return EFI_OUT_OF_RESOURCES;
> > + }
> > +
> > + //
> > + // 4. Call UpdateCapsule() service
> > + //
> > + Status = gRT->UpdateCapsule((EFI_CAPSULE_HEADER **) CapsuleBuffer,
> > CapsuleOnDiskNum + 1, (UINTN) BlockDescriptors);
> > +
> > + return Status;
> > +}
> > +
> > +/**
> > + Relocate Capsule on Disk from EFI system partition.
> > +
> > + Two solution to deliver Capsule On Disk:
> > + Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On
> > Disk to memory and call UpdateCapsule().
> > + Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On
> > Disk to a platform-specific NV storage
> > + device with BlockIo protocol.
> > +
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + Side Effects:
> > + Capsule Delivery Supported Flag in OsIndication variable and BootNext
> > variable will be cleared.
> > + Solution B: Content corruption. Block IO write directly touches low level
> > write. Orignal partitions, file
> > + systems of the relocation device will be corrupted.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDRelocateCapsule(
> > + UINTN MaxRetry
> > + )
> > +{
> > + if (!PcdGetBool (PcdCapsuleOnDiskSupport)) {
> > + return EFI_UNSUPPORTED;
> > + }
> > +
> > + //
> > + // Clear CapsuleOnDisk Flag firstly.
> > + //
> > + CoDClearCapsuleOnDiskFlag ();
> > +
> > + //
> > + // If Capsule In Ram is supported, delivery capsules through memory
> > + //
> > + if (PcdGetBool (PcdCapsuleInRamSupport)) {
> > + DEBUG ((DEBUG_INFO, "Capsule In Ram is supported, call gRT-
> > >UpdateCapsule().\n"));
> > + return RelocateCapsuleToRam (MaxRetry);
> > + } else {
> > + DEBUG ((DEBUG_INFO, "Reallcoate all Capsule on Disks to %s in
> > RootDir.\n", (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName)));
> > + return RelocateCapsuleToDisk (MaxRetry);
> > + }
> > +}
> > +
> > +/**
> > + Remove the temp file from the root of EFI System Partition.
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Remove the temp file successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDRemoveTempFile (
> > + UINTN MaxRetry
> > + )
> > +{
> > + EFI_STATUS Status;
> > + UINTN DataSize;
> > + UINT16 *LoadOptionNumber;
> > + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
> > + EFI_HANDLE FsHandle;
> > + EFI_FILE_HANDLE RootDir;
> > + EFI_FILE_HANDLE TempCodFile;
> > +
> > + RootDir = NULL;
> > + TempCodFile = NULL;
> > +
> > + LoadOptionNumber = AllocatePool (sizeof(UINT16));
> > + DataSize = sizeof(UINT16);
> > +
> > + //
> > + // Check if capsule files are relocated
> > + //
> > + Status = gRT->GetVariable (
> > + COD_RELOCATION_LOAD_OPTION_VAR_NAME,
> > + &gEfiCapsuleVendorGuid,
> > + NULL,
> > + &DataSize,
> > + (VOID *)LoadOptionNumber
> > + );
> > + if (EFI_ERROR(Status) || DataSize != sizeof(UINT16)) {
> > + return Status;
>
>
> Please handle possible memory leak in error handlings for this function.
>
>
> > + }
> > +
> > + //
> > + // Get the EFI file system from the boot option where the capsules are
> > relocated
> > + //
> > + Status = GetEfiSysPartitionFromActiveBootOption(MaxRetry,
> > &LoadOptionNumber, &FsHandle);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + Status = gBS->HandleProtocol(FsHandle,
> > &gEfiSimpleFileSystemProtocolGuid, (VOID **)&Fs);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + Status = Fs->OpenVolume(Fs, &RootDir);
> > + if (EFI_ERROR(Status)) {
> > + return Status;
> > + }
> > +
> > + //
> > + // Delete the TempCoDFile
> > + //
> > + Status = RootDir->Open(
> > + RootDir,
> > + &TempCodFile,
> > + (CHAR16 *)PcdGetPtr(PcdCoDRelocationFileName),
> > + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE,
> > + 0
> > + );
> > + if (!EFI_ERROR(Status)) {
> > + TempCodFile->Delete(TempCodFile);
> > + }
> > +
> > + if (RootDir != NULL) {
> > + RootDir->Close(RootDir);
> > + }
> > +
> > + //
> > + // Clear "CoDRelocationLoadOption" variable
> > + //
> > + Status = gRT->SetVariable (
> > + COD_RELOCATION_LOAD_OPTION_VAR_NAME,
> > + &gEfiCapsuleVendorGuid,
> > + 0,
> > + 0,
> > + NULL
> > + );
> > +
> > + return EFI_SUCCESS;
> > +}
> > diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
> > new file mode 100644
> > index 0000000000..064dc791b8
> > --- /dev/null
> > +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/CapsuleOnDisk.h
> > @@ -0,0 +1,63 @@
> > +/** @file
> > + Defines several datastructures used by Capsule On Disk feature.
> > + They are mainly used for FAT files.
> > +
> > + Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
> > + SPDX-License-Identifier: BSD-2-Clause-Patent
> > +
> > +**/
> > +
> > +#ifndef _CAPSULES_ON_DISK_H_
> > +#define _CAPSULES_ON_DISK_H_
> > +
> > +#include <Uefi.h>
> > +#include <Pi/PiMultiPhase.h>
> > +
> > +#include <Library/UefiLib.h>
> > +#include <Library/DebugLib.h>
> > +#include <Library/BaseLib.h>
> > +#include <Library/UefiBootServicesTableLib.h>
> > +#include <Library/UefiRuntimeServicesTableLib.h>
> > +#include <Library/UefiRuntimeLib.h>
> > +#include <Library/BaseMemoryLib.h>
> > +#include <Library/MemoryAllocationLib.h>
> > +#include <Library/FileHandleLib.h>
> > +#include <Library/CapsuleLib.h>
> > +#include <Library/DevicePathLib.h>
> > +#include <Library/PrintLib.h>
> > +#include <Library/UefiBootManagerLib.h>
> > +
> > +#include <Protocol/SimpleFileSystem.h>
> > +#include <Protocol/DiskIo.h>
> > +#include <Protocol/BlockIo.h>
> > +
> > +#include <Guid/CapsuleVendor.h>
> > +#include <Guid/GlobalVariable.h>
> > +
> > +//
> > +// This data structure is the part of FILE_INFO_ENTRY
> > +//
> > +#define FILE_INFO_SIGNATURE SIGNATURE_32 ('F', 'L', 'I', 'F')
> > +
> > +//
> > +// LoadOptionNumber of the boot option where the capsules is relocated.
> > +//
> > +#define COD_RELOCATION_LOAD_OPTION_VAR_NAME
> > L"CodRelocationLoadOption"
> > +
> > +typedef struct {
> > + UINTN Signature;
> > + LIST_ENTRY Link; /// Linked list members.
> > + EFI_FILE_INFO *FileInfo; /// Pointer to the FileInfo struct for this
> > file or NULL.
> > + CHAR16 *FileNameFirstPart; /// Text to the left of right-most
> period
> > in the file name. String is capitialized
> > + CHAR16 *FileNameSecondPart; /// Text to the right of right-most
> > period in the file name.String is capitialized. Maybe NULL
> > +} FILE_INFO_ENTRY;
> > +
> > +//
> > +// (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))
> > +
> > +#define MAX_FILE_INFO_LEN (OFFSET_OF(EFI_FILE_INFO, FileName) +
> > MAX_FILE_NAME_LEN)
> > +
> > +#endif // _CAPSULES_ON_DISK_H_
> > diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
> > index f38ab69e38..4254cc8270 100644
> > --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
> > +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
> > @@ -8,11 +8,11 @@
> >
> > SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
> > ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted
> input
> > and
> > performs basic validation.
> >
> > - Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
> > SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > **/
> >
> > #include <PiDxe.h>
> > @@ -88,11 +88,12 @@ EFI_STATUS
> > RecordFmpCapsuleStatusVariable (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > IN EFI_STATUS CapsuleStatus,
> > IN UINTN PayloadIndex,
> > IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
> > *ImageHeader,
> > - IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL
> > + IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL
> > + IN CHAR16 *CapFileName OPTIONAL
>
>
> Please help to update the function description comments for adding a new
> parameter.
>
> Also, the implementations of this function in file DxeCapsuleReportLib.c &
> DxeCapsuleReportLibNull.c are with different interface definitions. Could
> you help to double confirm on this?
>
It is a mistake, will fix it.
>
> > );
> >
> > /**
> > Function indicate the current completion progress of the firmware
> > update. Platform may override with own specific progress function.
> > @@ -107,10 +108,26 @@ EFI_STATUS
> > EFIAPI
> > UpdateImageProgress (
> > IN UINTN Completion
> > );
> >
> > +/**
> > + Return if this capsule is a capsule name capsule, based upon
> > CapsuleHeader.
> > +
> > + @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
> > +
> > + @retval TRUE It is a capsule name capsule.
> > + @retval FALSE It is not a capsule name capsule.
> > +**/
> > +BOOLEAN
> > +IsCapsuleNameCapsule (
> > + IN EFI_CAPSULE_HEADER *CapsuleHeader
> > + )
> > +{
> > + return CompareGuid (&CapsuleHeader->CapsuleGuid,
> > &gEdkiiCapsuleOnDiskNameGuid);
> > +}
> > +
> > /**
> > Return if this CapsuleGuid is a FMP capsule GUID or not.
> >
> > @param[in] CapsuleGuid A pointer to EFI_GUID
> >
> > @@ -1032,23 +1049,25 @@ StartFmpImage (
> > }
> >
> > /**
> > Record FMP capsule status.
> >
> > - @param[in] Handle A FMP handle.
> > + @param[in] Handle A FMP handle.
> > @param[in] CapsuleHeader The capsule image header
> > @param[in] CapsuleStatus The capsule process stauts
> > @param[in] PayloadIndex FMP payload index
> > @param[in] ImageHeader FMP image header
> > + @param[in] CapFileName Capsule file name
> > **/
> > VOID
> > RecordFmpCapsuleStatus (
> > IN EFI_HANDLE Handle, OPTIONAL
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > IN EFI_STATUS CapsuleStatus,
> > IN UINTN PayloadIndex,
> > - IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
> > *ImageHeader
> > + IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
> > *ImageHeader,
> > + IN CHAR16 *CapFileName OPTIONAL
> > )
> > {
> > EFI_STATUS Status;
> > EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
> > UINT32 FmpImageInfoDescriptorVer;
> > @@ -1068,11 +1087,12 @@ RecordFmpCapsuleStatus (
> > RecordFmpCapsuleStatusVariable (
> > CapsuleHeader,
> > CapsuleStatus,
> > PayloadIndex,
> > ImageHeader,
> > - FmpDevicePath
> > + FmpDevicePath,
> > + CapFileName
> > );
> >
> > //
> > // Update corresponding ESRT entry LastAttemp Status
> > //
> > @@ -1113,10 +1133,11 @@ RecordFmpCapsuleStatus (
> > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
> >
> > This function need support nested FMP capsule.
> >
> > @param[in] CapsuleHeader Points to a capsule header.
> > + @param[in] CapFileName Capsule file name.
> > @param[out] ResetRequired Indicates whether reset is required or
> not.
> >
> > @retval EFI_SUCESS Process Capsule Image successfully.
> > @retval EFI_UNSUPPORTED Capsule image is not supported by the
> > firmware.
> > @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
> > @@ -1124,10 +1145,11 @@ RecordFmpCapsuleStatus (
> > @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
> > **/
> > EFI_STATUS
> > ProcessFmpCapsuleImage (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > + IN CHAR16 *CapFileName, OPTIONAL
> > OUT BOOLEAN *ResetRequired OPTIONAL
> > )
> > {
> > EFI_STATUS Status;
> > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
> > *FmpCapsuleHeader;
> > @@ -1143,11 +1165,11 @@ ProcessFmpCapsuleImage (
> > UINTN Index2;
> > BOOLEAN NotReady;
> > BOOLEAN Abort;
> >
> > if (!IsFmpCapsuleGuid(&CapsuleHeader->CapsuleGuid)) {
> > - return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER
> > *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), ResetRequired);
> > + return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER
> > *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName,
> > ResetRequired);
> > }
> >
> > NotReady = FALSE;
> > Abort = FALSE;
> >
> > @@ -1225,11 +1247,12 @@ ProcessFmpCapsuleImage (
> > RecordFmpCapsuleStatus (
> > NULL,
> > CapsuleHeader,
> > EFI_NOT_READY,
> > Index - FmpCapsuleHeader->EmbeddedDriverCount,
> > - ImageHeader
> > + ImageHeader,
> > + CapFileName
> > );
> > continue;
> > }
> >
> > for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
> > @@ -1237,11 +1260,12 @@ ProcessFmpCapsuleImage (
> > RecordFmpCapsuleStatus (
> > HandleBuffer[Index2],
> > CapsuleHeader,
> > EFI_ABORTED,
> > Index - FmpCapsuleHeader->EmbeddedDriverCount,
> > - ImageHeader
> > + ImageHeader,
> > + CapFileName
> > );
> > continue;
> > }
> >
> > Status = SetFmpImageData (
> > @@ -1260,11 +1284,12 @@ ProcessFmpCapsuleImage (
> > RecordFmpCapsuleStatus (
> > HandleBuffer[Index2],
> > CapsuleHeader,
> > Status,
> > Index - FmpCapsuleHeader->EmbeddedDriverCount,
> > - ImageHeader
> > + ImageHeader,
> > + CapFileName
> > );
> > }
> > if (HandleBuffer != NULL) {
> > FreePool(HandleBuffer);
> > }
> > @@ -1412,10 +1437,17 @@ SupportCapsuleImage (
> > //
> > if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader-
> > >CapsuleGuid)) {
> > return EFI_SUCCESS;
> > }
> >
> > + //
> > + // Check capsule file name capsule
> > + //
> > + if (IsCapsuleNameCapsule(CapsuleHeader)) {
> > + return EFI_SUCCESS;
> > + }
> > +
> > if (IsFmpCapsule(CapsuleHeader)) {
> > //
> > // Fake capsule header is valid case in QueryCapsuleCpapbilities().
> > //
> > if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
> > @@ -1434,10 +1466,11 @@ SupportCapsuleImage (
> > The firmware implements to process the capsule image.
> >
> > Caution: This function may receive untrusted input.
> >
> > @param[in] CapsuleHeader Points to a capsule header.
> > + @param[in] CapFileName Capsule file name.
> > @param[out] ResetRequired Indicates whether reset is required or
> not.
> >
> > @retval EFI_SUCESS Process Capsule Image successfully.
> > @retval EFI_UNSUPPORTED Capsule image is not supported by the
> > firmware.
> > @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
> > @@ -1445,10 +1478,11 @@ SupportCapsuleImage (
> > **/
> > EFI_STATUS
> > EFIAPI
> > ProcessThisCapsuleImage (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > + IN CHAR16 *CapFileName, OPTIONAL
> > OUT BOOLEAN *ResetRequired OPTIONAL
> > )
> > {
> > EFI_STATUS Status;
> >
> > @@ -1482,11 +1516,11 @@ ProcessThisCapsuleImage (
> >
> > //
> > // Process EFI FMP Capsule
> > //
> > DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
> > - Status = ProcessFmpCapsuleImage(CapsuleHeader, ResetRequired);
> > + Status = ProcessFmpCapsuleImage(CapsuleHeader, CapFileName,
> > ResetRequired);
> > DEBUG((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
> >
> > return Status;
> > }
> >
> > @@ -1509,11 +1543,11 @@ EFI_STATUS
> > EFIAPI
> > ProcessCapsuleImage (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader
> > )
> > {
> > - return ProcessThisCapsuleImage (CapsuleHeader, NULL);
> > + return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
> > }
> >
> > /**
> > Callback function executed when the EndOfDxe event group is signaled.
> >
> > diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
> > index 14c3d19bc3..05de4299fb 100644
> > --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
> > +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
> > @@ -1,11 +1,11 @@
> > ## @file
> > # Capsule library instance for DXE_DRIVER.
> > #
> > # Capsule library instance for DXE_DRIVER module types.
> > #
> > -# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
> > # SPDX-License-Identifier: BSD-2-Clause-Patent
> > #
> > ##
> >
> > [Defines]
> > @@ -27,10 +27,12 @@
> >
> > [Sources]
> > DxeCapsuleLib.c
> > DxeCapsuleProcessLib.c
> > DxeCapsuleReportLib.c
> > + CapsuleOnDisk.c
> > + CapsuleOnDisk.h
> >
> > [Packages]
> > MdePkg/MdePkg.dec
> > MdeModulePkg/MdeModulePkg.dec
> >
> > @@ -45,10 +47,12 @@
> > ReportStatusCodeLib
> > PrintLib
> > HobLib
> > BmpSupportLib
> > DisplayUpdateProgressLib
> > + FileHandleLib
> > + UefiBootManagerLib
> >
> > [Pcd]
> > gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleMax ##
> > CONSUMES
> >
> >
> gEfiMdeModulePkgTokenSpaceGuid.PcdSystemRebootAfterCapsuleProcess
> > Flag ## CONSUMES
> >
> > @@ -57,23 +61,38 @@
> >
> >
> gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeProcessCapsules
> > End ## CONSUMES
> >
> >
> gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdatingFirmwa
> > re ## CONSUMES
> >
> >
> gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwar
> > eSuccess ## CONSUMES
> >
> >
> gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeUpdateFirmwar
> > eFailed ## CONSUMES
> >
> > gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleStatusCodeResettingSyste
> > m ## CONSUMES
> > + gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleInRamSupport
> > ## CONSUMES
> > + gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport
> > ## CONSUMES
> > + gEfiMdeModulePkgTokenSpaceGuid.PcdCodRelocationDevPath
> > ## SOMETIMES_CONSUMES
> > + gEfiMdeModulePkgTokenSpaceGuid.PcdCoDRelocationFileName
> > ## CONSUMES
> >
> > [Protocols]
> > gEsrtManagementProtocolGuid ## CONSUMES
> > gEfiFirmwareManagementProtocolGuid ## CONSUMES
> > gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
> > gEdkiiFirmwareManagementProgressProtocolGuid ##
> > SOMETIMES_CONSUMES
> > + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
> > + gEfiBlockIoProtocolGuid ## CONSUMES
> > + gEfiDiskIoProtocolGuid ## CONSUMES
> >
> > [Guids]
> > gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
> > gWindowsUxCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
> > ## SOMETIMES_CONSUMES ## Variable:L"CapsuleMax"
> > ## SOMETIMES_PRODUCES ## Variable:L"CapsuleMax"
> > gEfiCapsuleReportGuid
> > gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ##
> > Variable:L"CapsuleUpdateData"
> > gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
> > + gEfiPartTypeSystemPartGuid ## SOMETIMES_CONSUMES
> > + gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ##
> > Variable:L"CodRelocationInfo"
> > + ## SOMETIMES_CONSUMES ## Variable:L"OsIndications"
> > + ## SOMETIMES_PRODUCES ## Variable:L"OsIndications"
> > + ## SOMETIMES_CONSUMES ## Variable:L"BootNext"
> > + ## SOMETIMES_PRODUCES ## Variable:L"BootNext"
> > + gEfiGlobalVariableGuid
> > + gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ##
> > GUID
> >
> > [Depex]
> > gEfiVariableWriteArchProtocolGuid
> > diff --git
> > a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
> > index 5e2d2b87a8..e07dd7986e 100644
> > --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
> > +++
> b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
> > @@ -7,11 +7,11 @@
> > buffer overflow, integer overflow.
> >
> > ProcessCapsules(), ProcessTheseCapsules() will receive untrusted
> > input and do basic validation.
> >
> > - Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
> > SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > **/
> >
> > #include <PiDxe.h>
> > @@ -90,14 +90,45 @@ BOOLEAN
> > IsValidCapsuleHeader (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > IN UINT64 CapsuleSize
> > );
> >
> > +/**
> > + Return if this capsule is a capsule name capsule, based upon
> > CapsuleHeader.
> > +
> > + @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
> > +
> > + @retval TRUE It is a capsule name capsule.
> > + @retval FALSE It is not a capsule name capsule.
> > +**/
> > +BOOLEAN
> > +IsCapsuleNameCapsule (
> > + IN EFI_CAPSULE_HEADER *CapsuleHeader
> > + );
> > +
> > +/**
> > + Check the integrity of the capsule name capsule.
> > + If the capsule is vaild, return the physical address of each capsule name
> > string.
> > +
> > + @param[in] CapsuleHeader Pointer to the capsule header of a capsule
> > name capsule.
> > + @param[out] CapsuleNameNum Number of capsule name.
> > +
> > + @retval NULL Capsule name capsule is not valid.
> > + @retval CapsuleNameBuf Array of capsule name physical address.
> > +
> > +**/
> > +EFI_PHYSICAL_ADDRESS *
> > +ValidateCapsuleNameCapsuleIntegrity (
> > + IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > + OUT UINTN *CapsuleNameNum
> > + );
> > +
> > extern BOOLEAN mDxeCapsuleLibEndOfDxe;
> > BOOLEAN mNeedReset = FALSE;
> >
> > VOID **mCapsulePtr;
> > +CHAR16 **mCapsuleNamePtr;
> > EFI_STATUS *mCapsuleStatusArray;
> > UINT32 mCapsuleTotalNumber;
> >
> > /**
> > The firmware implements to process the capsule image.
> > @@ -114,10 +145,11 @@ UINT32 mCapsuleTotalNumber;
> > **/
> > EFI_STATUS
> > EFIAPI
> > ProcessThisCapsuleImage (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > + IN CHAR16 *CapFileName, OPTIONAL
> > OUT BOOLEAN *ResetRequired OPTIONAL
> > );
> >
> > /**
> > Function indicate the current completion progress of the firmware
> > @@ -183,20 +215,36 @@ InitCapsulePtr (
> > VOID
> > )
> > {
> > EFI_PEI_HOB_POINTERS HobPointer;
> > UINTN Index;
> > + UINTN Index2;
> > + UINTN Index3;
> > + UINTN CapsuleNameNumber;
> > + UINTN CapsuleNameTotalNumber;
> > + UINTN CapsuleNameCapsuleTotalNumber;
> > + VOID **CapsuleNameCapsulePtr;
> > + EFI_PHYSICAL_ADDRESS *CapsuleNameAddress;
> > +
> > + CapsuleNameNumber = 0;
> > + CapsuleNameTotalNumber = 0;
> > + CapsuleNameCapsuleTotalNumber = 0;
> > + CapsuleNameCapsulePtr = NULL;
> >
> > //
> > // Find all capsule images from hob
> > //
> > HobPointer.Raw = GetHobList ();
> > while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE,
> > HobPointer.Raw)) != NULL) {
> > if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule-
> > >BaseAddress, HobPointer.Capsule->Length)) {
> > HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this
> > hob as invalid
> > } else {
> > - mCapsuleTotalNumber++;
> > + if (IsCapsuleNameCapsule((VOID *)(UINTN)HobPointer.Capsule-
> > >BaseAddress)) {
> > + CapsuleNameCapsuleTotalNumber++;
> > + } else {
> > + mCapsuleTotalNumber++;
> > + }
> > }
> > HobPointer.Raw = GET_NEXT_HOB (HobPointer);
> > }
> >
> > DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n",
> > mCapsuleTotalNumber));
> > @@ -222,19 +270,76 @@ InitCapsulePtr (
> > mCapsuleTotalNumber = 0;
> > return ;
> > }
> > SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) *
> > mCapsuleTotalNumber, EFI_NOT_READY);
> >
> > + if (CapsuleNameCapsuleTotalNumber != 0) {
> > + CapsuleNameCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *)
> *
> > CapsuleNameCapsuleTotalNumber);
> > + if (CapsuleNameCapsulePtr == NULL) {
> > + DEBUG ((DEBUG_ERROR, "Allocate CapsuleNameCapsulePtr fail!\n"));
> > + FreePool (mCapsulePtr);
> > + FreePool (mCapsuleStatusArray);
> > + mCapsulePtr = NULL;
> > + mCapsuleStatusArray = NULL;
> > + mCapsuleTotalNumber = 0;
> > + return ;
> > + }
> > + }
> > +
> > //
> > // Find all capsule images from hob
> > //
> > HobPointer.Raw = GetHobList ();
> > - Index = 0;
> > + Index = 0;
> > + Index2 = 0;
> > while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE,
> > HobPointer.Raw)) != NULL) {
> > - mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule-
> > >BaseAddress;
> > + if (!IsCapsuleNameCapsule ((VOID *) (UINTN) HobPointer.Capsule-
> > >BaseAddress)) {
> > + mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule-
> > >BaseAddress;
> > + } else {
> > + CapsuleNameCapsulePtr [Index2++] = (VOID *) (UINTN)
> > HobPointer.Capsule->BaseAddress;
> > + }
> > HobPointer.Raw = GET_NEXT_HOB (HobPointer);
> > }
> > +
> > + //
> > + // Find Capsule On Disk Names
> > + //
> > + for (Index = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {
> > + CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity
> > (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);
> > + if (CapsuleNameAddress != NULL ) {
> > + CapsuleNameTotalNumber += CapsuleNameNumber;
> > + }
> > + }
> > +
> > + if (CapsuleNameTotalNumber == mCapsuleTotalNumber) {
> > + mCapsuleNamePtr = (CHAR16 **) AllocateZeroPool (sizeof (CHAR16 *)
> *
> > mCapsuleTotalNumber);
> > + if (mCapsuleNamePtr == NULL) {
> > + DEBUG ((DEBUG_ERROR, "Allocate mCapsuleNamePtr fail!\n"));
> > + FreePool (mCapsulePtr);
> > + FreePool (mCapsuleStatusArray);
> > + FreePool (CapsuleNameCapsulePtr);
> > + mCapsulePtr = NULL;
> > + mCapsuleStatusArray = NULL;
> > + mCapsuleTotalNumber = 0;
> > + return ;
> > + }
> > +
> > + for (Index = 0, Index3 = 0; Index < CapsuleNameCapsuleTotalNumber;
> > Index ++) {
> > + CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity
> > (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);
> > + if (CapsuleNameAddress != NULL ) {
> > + for (Index2 = 0; Index2 < CapsuleNameNumber; Index2 ++) {
> > + mCapsuleNamePtr[Index3 ++] = (CHAR16 *)(UINTN)
> > CapsuleNameAddress[Index2];
> > + }
> > + }
> > + }
> > + } else {
> > + mCapsuleNamePtr = NULL;
> > + }
> > +
> > + if (CapsuleNameCapsulePtr != NULL) {
> > + FreePool (CapsuleNameCapsulePtr);
> > + }
> > }
> >
> > /**
> > This function returns if all capsule images are processed.
> >
> > @@ -394,10 +499,11 @@ ProcessTheseCapsules (
> > EFI_CAPSULE_HEADER *CapsuleHeader;
> > UINT32 Index;
> > ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;
> > UINT16 EmbeddedDriverCount;
> > BOOLEAN ResetRequired;
> > + CHAR16 *CapsuleName;
> >
> > REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE |
> > PcdGet32(PcdStatusCodeSubClassCapsule) |
> > PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));
> >
> > if (FirstRound) {
> > InitCapsulePtr ();
> > @@ -406,10 +512,11 @@ ProcessTheseCapsules (
> > if (mCapsuleTotalNumber == 0) {
> > //
> > // We didn't find a hob, so had no errors.
> > //
> > DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule
> update
> > boot mode.\n"));
> > + mNeedReset = TRUE;
>
>
> According to the API description of ProcessCapsules():
>
> '''
> If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
> '''
>
> After the above change (I assume mCapsuleTotalNumber == 0 means no
> Capsule
> Hob), a system reset will be triggered. May I know the purpose for such
> change?
>
For Capsule On Disk, no capsule hob means the Cod temp relocations file is corrupted, which also means current boot is insecure.
Then force reset to re-apply normal boot platform secure policy.
I will update the description. Do you have comments for it?
BR,
Wei Xu
> Best Regards,
> Hao Wu
>
>
> > return EFI_SUCCESS;
> > }
> >
> > if (AreAllImagesProcessed ()) {
> > return EFI_SUCCESS;
> > @@ -428,14 +535,15 @@ ProcessTheseCapsules (
> > //
> > // If Windows UX capsule exist, process it first
> > //
> > for (Index = 0; Index < mCapsuleTotalNumber; Index++) {
> > CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
> > + CapsuleName = (mCapsuleNamePtr == NULL) ? NULL :
> > mCapsuleNamePtr[Index];
> > if (CompareGuid (&CapsuleHeader->CapsuleGuid,
> > &gWindowsUxCapsuleGuid)) {
> > DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - 0x%x\n",
> > CapsuleHeader));
> > DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));
> > - Status = ProcessThisCapsuleImage (CapsuleHeader, NULL);
> > + Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName,
> > NULL);
> > mCapsuleStatusArray [Index] = EFI_SUCCESS;
> > DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - %r\n",
> Status));
> > break;
> > }
> > }
> > @@ -449,10 +557,11 @@ ProcessTheseCapsules (
> > if (mCapsuleStatusArray [Index] != EFI_NOT_READY) {
> > // already processed
> > continue;
> > }
> > CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];
> > + CapsuleName = (mCapsuleNamePtr == NULL) ? NULL :
> > mCapsuleNamePtr[Index];
> > if (!CompareGuid (&CapsuleHeader->CapsuleGuid,
> > &gWindowsUxCapsuleGuid)) {
> > //
> > // Call capsule library to process capsule image.
> > //
> > EmbeddedDriverCount = 0;
> > @@ -469,11 +578,11 @@ ProcessTheseCapsules (
> > }
> >
> > if ((!FirstRound) || (EmbeddedDriverCount == 0)) {
> > DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - 0x%x\n",
> > CapsuleHeader));
> > ResetRequired = FALSE;
> > - Status = ProcessThisCapsuleImage (CapsuleHeader, &ResetRequired);
> > + Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName,
> > &ResetRequired);
> > mCapsuleStatusArray [Index] = Status;
> > DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - %r\n", Status));
> >
> > if (Status != EFI_NOT_READY) {
> > if (EFI_ERROR(Status)) {
> > diff --git
> > a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
> > index 6ad766d65a..0ec5f20676 100644
> > --- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
> > +++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
> > @@ -1,9 +1,9 @@
> > /** @file
> > DXE capsule report related function.
> >
> > - Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
> > + Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
> > SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > **/
> >
> > #include <PiDxe.h>
> > @@ -27,10 +27,22 @@
> > #include <Library/DevicePathLib.h>
> > #include <Library/CapsuleLib.h>
> >
> > #include <IndustryStandard/WindowsUxCapsule.h>
> >
> > +/**
> > + This routine is called to clear CapsuleOnDisk Relocation Info variable.
> > + Total Capsule On Disk length is recorded in this variable
> > +
> > + @retval EFI_SUCCESS Capsule On Disk flags are cleared
> > +
> > +**/
> > +EFI_STATUS
> > +CoDClearCapsuleRelocationInfo(
> > + VOID
> > + );
> > +
> > /**
> > Get current capsule last variable index.
> >
> > @return Current capsule last variable index.
> > @retval -1 No current capsule last variable.
> > @@ -172,44 +184,55 @@ RecordCapsuleStatusVariable (
> > @param[in] CapsuleHeader The capsule image header
> > @param[in] CapsuleStatus The capsule process stauts
> > @param[in] PayloadIndex FMP payload index
> > @param[in] ImageHeader FMP image header
> > @param[in] FmpDevicePath DevicePath associated with the FMP
> producer
> > + @param[in] CapFileName Capsule file name
> >
> > @retval EFI_SUCCESS The capsule status variable is recorded.
> > @retval EFI_OUT_OF_RESOURCES No resource to record the capsule
> status
> > variable.
> > **/
> > EFI_STATUS
> > RecordFmpCapsuleStatusVariable (
> > IN EFI_CAPSULE_HEADER *CapsuleHeader,
> > IN EFI_STATUS CapsuleStatus,
> > IN UINTN PayloadIndex,
> > IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
> > *ImageHeader,
> > - IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL
> > + IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL
> > + IN CHAR16 *CapFileName OPTIONAL
> > )
> > {
> > EFI_CAPSULE_RESULT_VARIABLE_HEADER
> *CapsuleResultVariableHeader;
> > EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;
> > EFI_STATUS Status;
> > UINT8 *CapsuleResultVariable;
> > UINTN CapsuleResultVariableSize;
> > CHAR16 *DevicePathStr;
> > UINTN DevicePathStrSize;
> > + UINTN CapFileNameSize;
> > +
> > + DevicePathStr = NULL;
> > + CapFileNameSize = sizeof(CHAR16);
> >
> > - DevicePathStr = NULL;
> > if (FmpDevicePath != NULL) {
> > DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE,
> FALSE);
> > }
> > if (DevicePathStr != NULL) {
> > DevicePathStrSize = StrSize(DevicePathStr);
> > } else {
> > DevicePathStrSize = sizeof(CHAR16);
> > }
> > +
> > + if (CapFileName != NULL) {
> > + CapFileNameSize = StrSize(CapFileName);
> > + }
> > +
> > //
> > - // Allocate zero CHAR16 for CapsuleFileName.
> > + // Allocate room for CapsuleFileName.
> > //
> > - CapsuleResultVariableSize =
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) +
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) +
> > DevicePathStrSize;
> > + CapsuleResultVariableSize =
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) +
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize +
> > DevicePathStrSize;
> > +
> > CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);
> > if (CapsuleResultVariable == NULL) {
> > return EFI_OUT_OF_RESOURCES;
> > }
> > CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;
> > @@ -223,12 +246,17 @@ RecordFmpCapsuleStatusVariable (
> > CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable +
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));
> > CapsuleResultVariableFmp->Version = 0x1;
> > CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;
> > CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader-
> > >UpdateImageIndex;
> > CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId,
> > &ImageHeader->UpdateImageTypeId);
> > +
> > + if (CapFileName != NULL) {
> > + CopyMem((UINT8 *)CapsuleResultVariableFmp +
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName,
> > CapFileNameSize);
> > + }
> > +
> > if (DevicePathStr != NULL) {
> > - CopyMem ((UINT8 *)CapsuleResultVariableFmp +
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16),
> > DevicePathStr, DevicePathStrSize);
> > + CopyMem ((UINT8 *)CapsuleResultVariableFmp +
> > sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize,
> > DevicePathStr, DevicePathStrSize);
> > FreePool (DevicePathStr);
> > DevicePathStr = NULL;
> > }
> >
> > Status = EFI_SUCCESS;
> > @@ -398,10 +426,35 @@ InitCapsuleUpdateVariable (
> > }
> > Index++;
> > }
> > }
> >
> > +/**
> > + Initialize capsule relocation info variable.
> > +**/
> > +VOID
> > +InitCapsuleRelocationInfo (
> > + VOID
> > + )
> > +{
> > + EFI_STATUS Status;
> > + EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
> > +
> > + CoDClearCapsuleRelocationInfo();
> > +
> > + //
> > + // Unlock Capsule On Disk relocation Info variable only when Capsule On
> > Disk flag is enabled
> > + //
> > + if (!CoDCheckCapsuleOnDiskFlag()) {
> > + Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL,
> > (VOID **) &VariableLock);
> > + if (!EFI_ERROR (Status)) {
> > + Status = VariableLock->RequestToLock (VariableLock,
> > COD_RELOCATION_INFO_VAR_NAME, &gEfiCapsuleVendorGuid);
> > + ASSERT_EFI_ERROR (Status);
> > + }
> > + }
> > +}
> > +
> > /**
> > Initialize capsule related variables.
> > **/
> > VOID
> > InitCapsuleVariable (
> > @@ -409,10 +462,12 @@ InitCapsuleVariable (
> > )
> > {
> > InitCapsuleUpdateVariable();
> > InitCapsuleMaxVariable();
> > InitCapsuleLastVariable();
> > + InitCapsuleRelocationInfo();
> > +
> > //
> > // No need to clear L"Capsule####", because OS/APP should refer
> > L"CapsuleLast"
> > // to check status and delete them.
> > //
> > }
> > diff --git
> > a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
> > index 2c93e68700..bf56f4623f 100644
> > ---
> a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
> > +++
> > b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
> > @@ -1,11 +1,11 @@
> > ## @file
> > # Capsule library instance for DXE_RUNTIME_DRIVER.
> > #
> > # Capsule library instance for DXE_RUNTIME_DRIVER module types.
> > #
> > -# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
> > +# Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
> > # SPDX-License-Identifier: BSD-2-Clause-Patent
> > #
> > ##
> >
> > [Defines]
> > @@ -66,8 +66,9 @@
> > gEfiCapsuleReportGuid
> > gEfiCapsuleVendorGuid ## SOMETIMES_CONSUMES ##
> > Variable:L"CapsuleUpdateData"
> > gEfiEndOfDxeEventGroupGuid ## CONSUMES ## Event
> > gEfiEventReadyToBootGuid ## CONSUMES ## Event
> > gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
> > + gEdkiiCapsuleOnDiskNameGuid ## SOMETIMES_CONSUMES ##
> > GUID
> >
> > [Depex]
> > gEfiVariableWriteArchProtocolGuid
> > diff --git a/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
> > b/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
> > index 06a1abe16b..39e37cffcd 100644
> > --- a/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
> > +++ b/MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.c
> > @@ -1,9 +1,9 @@
> > /** @file
> > Null Dxe Capsule Library instance does nothing and returns unsupport
> > status.
> >
> > -Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
> > +Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
> > SPDX-License-Identifier: BSD-2-Clause-Patent
> >
> > **/
> > #include <Uefi.h>
> > #include <Library/CapsuleLib.h>
> > @@ -83,5 +83,88 @@ ProcessCapsules (
> > )
> > {
> > return EFI_UNSUPPORTED;
> > }
> >
> > +
> > +/**
> > + This routine is called to check if CapsuleOnDisk flag in OsIndications
> > Variable
> > + is enabled.
> > +
> > + @retval TRUE Flag is enabled
> > + @retval FALSE Flag is not enabled
> > +
> > +**/
> > +BOOLEAN
> > +EFIAPI
> > +CoDCheckCapsuleOnDiskFlag(
> > + VOID
> > + )
> > +{
> > + return FALSE;
> > +}
> > +
> > +/**
> > + This routine is called to clear CapsuleOnDisk flags including OsIndications
> > and BootNext variable.
> > +
> > + @retval EFI_SUCCESS All Capsule On Disk flags are cleared
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDClearCapsuleOnDiskFlag(
> > + VOID
> > + )
> > +{
> > + return EFI_UNSUPPORTED;
> > +}
> > +
> > +/**
> > + Relocate Capsule on Disk from EFI system partition.
> > +
> > + Two solution to deliver Capsule On Disk:
> > + Solution A: If PcdCapsuleInRamSupport is enabled, relocate Capsule On
> > Disk to memory and call UpdateCapsule().
> > + Solution B: If PcdCapsuleInRamSupport is disabled, relocate Capsule On
> > Disk to a platform-specific NV storage
> > + device with BlockIo protocol.
> > +
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + Side Effects:
> > + Capsule Delivery Supported Flag in OsIndication variable and BootNext
> > variable will be cleared.
> > + Solution B: Content corruption. Block IO write directly touches low level
> > write. Orignal partitions, file
> > + systems of the relocation device will be corrupted.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Capsule on Disk images are sucessfully relocated.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDRelocateCapsule(
> > + UINTN MaxRetry
> > + )
> > +{
> > + return EFI_UNSUPPORTED;
> > +}
> > +
> > +/**
> > + Remove the temp file from the root of EFI System Partition.
> > + Device enumeration like USB costs time, user can input MaxRetry to tell
> > function to retry.
> > + Function will stall 100ms between each retry.
> > +
> > + @param[in] MaxRetry Max Connection Retry. Stall 100ms
> between
> > each connection try to ensure
> > + devices like USB can get enumerated.
> > +
> > + @retval EFI_SUCCESS Remove the temp file successfully.
> > +
> > +**/
> > +EFI_STATUS
> > +EFIAPI
> > +CoDRemoveTempFile (
> > + UINTN MaxRetry
> > + )
> > +{
> > + return EFI_UNSUPPORTED;
> > +}
> > --
> > 2.16.2.windows.1
> >
> >
> >
next prev parent reply other threads:[~2019-06-19 7:55 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-05 15:41 [edk2-devel][Patch v2 0/7] Implement Capsule On Disk Xu, Wei6
2019-06-05 15:41 ` [edk2-devel][Patch v2 1/7] MdePkg: Add Pei Boot In CapsuleOnDisk Mode Ppi definition Xu, Wei6
2019-06-05 21:42 ` Felix Polyudov
2019-06-12 7:48 ` Wu, Hao A
2019-06-12 8:28 ` Liming Gao
2019-06-05 15:41 ` [edk2-devel][Patch v2 2/7] MdeModulePkg: Add Capsule On Disk related definition Xu, Wei6
2019-06-12 7:48 ` Wu, Hao A
2019-06-12 8:43 ` Xu, Wei6
2019-06-05 15:41 ` [edk2-devel][Patch v2 3/7] MdeModulePkg: Add CapsuleOnDiskLoadPei PEIM Xu, Wei6
2019-06-12 7:49 ` Wu, Hao A
2019-06-19 8:40 ` Xu, Wei6
2019-06-19 8:59 ` Ni, Ray
2019-06-20 0:59 ` Wu, Hao A
2019-06-05 15:42 ` [edk2-devel][Patch v2 4/7] MdeModulePkg/BdsDxe: Support Capsule On Disk Xu, Wei6
2019-06-05 15:42 ` [edk2-devel][Patch v2 5/7] MdeModulePkg/CapsuleRuntimeDxe: Introduce PCD to control this feature Xu, Wei6
2019-06-12 7:49 ` Wu, Hao A
2019-06-19 0:41 ` Zhang, Chao B
2019-06-19 0:59 ` Wu, Hao A
2019-06-19 1:13 ` Zhang, Chao B
2019-06-19 2:22 ` Wu, Hao A
2019-06-05 15:42 ` [edk2-devel][Patch v2 6/7] MdeModulePkg/DxeIpl: Support Capsule On Disk Xu, Wei6
2019-06-12 7:49 ` Wu, Hao A
2019-06-05 15:42 ` [edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On Disk APIs into CapsuleLib Xu, Wei6
2019-06-12 7:49 ` Wu, Hao A
2019-06-19 7:55 ` Xu, Wei6 [this message]
2019-06-19 8:16 ` Wu, Hao A
2019-06-19 8:19 ` Wu, Hao A
2019-06-19 8:23 ` Xu, Wei6
2019-06-05 21:53 ` [edk2-devel][Patch v2 0/7] Implement Capsule On Disk Felix Polyudov
2019-06-05 22:36 ` Michael D Kinney
2019-06-06 1:23 ` Zhang, Chao B
2019-06-12 7:47 ` Wu, Hao A
2019-06-12 8:13 ` Zhang, Chao B
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=59B8EAB3797CDB4091332F0685A110ED50D9746F@SHSMSX104.ccr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox