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...@intel.com> > Cc: Wang, Jian J <jian.j.w...@intel.com>; Zhang, Chao B > <chao.b.zh...@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.w...@intel.com> > > Cc: Hao A Wu <hao.a...@intel.com> > > Cc: Chao B Zhang <chao.b.zh...@intel.com> > > Signed-off-by: Wei6 Xu <wei6...@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 > > > > > > -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#42578): https://edk2.groups.io/g/devel/message/42578 Mute This Topic: https://groups.io/mt/31938582/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-