[edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On Disk APIs into CapsuleLib.

Xu, Wei6 wei6.xu at intel.com
Wed Jun 19 07:55:02 UTC 2019


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 at edk2.groups.io; Xu, Wei6 <wei6.xu at intel.com>
> Cc: Wang, Jian J <jian.j.wang at intel.com>; Zhang, Chao B
> <chao.b.zhang at intel.com>
> Subject: RE: [edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On
> Disk APIs into CapsuleLib.
> 
> > -----Original Message-----
> > From: devel at edk2.groups.io [mailto:devel at edk2.groups.io] On Behalf Of
> Xu,
> > Wei6
> > Sent: Wednesday, June 05, 2019 11:42 PM
> > To: devel at edk2.groups.io
> > Cc: Wang, Jian J; Wu, Hao A; Zhang, Chao B; Xu, Wei6
> > Subject: [edk2-devel][Patch v2 7/7] MdeModulePkg: Add Capsule On Disk
> > APIs into CapsuleLib.
> 
> 
> Not directly related with this patch, I saw many function declarations
> within .C file for this library. Could you help to propose another series
> to add header files to address this (Maybe like the case in
> MdeModulePkg/Universal/Variable/RuntimeDxe to handle multi-phases).
> 

Sure, I will work on it after this patch is done.

> 
> Some general level comments:
> 
> I saw some of the new functions whose scope is limited within a single
> file have been decorated with keyword 'STATIC'. Could you help to make it
> consistent for all the newly added global variables/functions? Also, could
> you help to use keyword 'static' (lower case) instead?
> 

I will update all 'STATIC' to 'static'.

> 
> >
> > BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1852
> >
> > CoDCheckCapsuleOnDiskFlag() is to check if CapsuleOnDisk flag in
> > "OsIndications" Variable is enabled. It is used to indicate whether
> > capsule on disk is provisioned in normal boot path.
> >
> > CoDClearCapsuleOnDiskFlag() is to to clear CapsuleOnDisk flags,
> > including "OsIndications" and "BootNext" variable.
> >
> > CoDRelocateCapsule() is to relocate the capsules from EFI system
> > partition. Depends on PcdCapsuleInRamSupport, there are two solutions
> > to relocate the capsule on disk images:
> > When Capsule In Ram is supported, the Capsule On Disk images are
> > relocated into memory, and call UpdateCapsule() service to deliver
> > the capsules.
> > When Capsule In Ram is not supported, the Capsule On Disk images are
> > relocated into a temp file which will be stored in root directory on
> > a platform specific storage device. CapsuleOnDiskLoadPei PEIM will
> > retrieve the capsules from the relocation temp file and report
> > capsule hobs for them.
> >
> > CoDRemoveTempFile() is to remove the relocation temp file in the next
> > boot after capsules are processed.
> >
> > Cc: Jian J Wang <jian.j.wang at intel.com>
> > Cc: Hao A Wu <hao.a.wu at intel.com>
> > Cc: Chao B Zhang <chao.b.zhang at intel.com>
> > Signed-off-by: Wei6 Xu <wei6.xu at 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/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list