public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Wang, Jian J" <jian.j.wang@intel.com>
To: "Chen, Chen A" <chen.a.chen@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Wu, Hao A" <hao.a.wu@intel.com>,
	"Zhang, Chao B" <chao.b.zhang@intel.com>
Subject: Re: [PATCH v2 2/2] MdeModulePkg/CapsuleApp: Enhance CapsuleApp to support Capsule-on-Disk.
Date: Mon, 28 Jan 2019 02:57:44 +0000	[thread overview]
Message-ID: <D827630B58408649ACB04F44C5100036258A7395@SHSMSX107.ccr.corp.intel.com> (raw)
In-Reply-To: <20190128012115.11124-1-chen.a.chen@intel.com>

Chen,

Did you just sent this patch for v2? If yes, I think you should send all patches in series even the one with title [PATCH 0/2]. It'd be better to add change description since last version.

Regards,
Jian


> -----Original Message-----
> From: Chen, Chen A
> Sent: Monday, January 28, 2019 9:21 AM
> To: edk2-devel@lists.01.org
> Cc: Chen, Chen A <chen.a.chen@intel.com>; Wang, Jian J
> <jian.j.wang@intel.com>; Wu, Hao A <hao.a.wu@intel.com>; Zhang, Chao B
> <chao.b.zhang@intel.com>
> Subject: [PATCH v2 2/2] MdeModulePkg/CapsuleApp: Enhance CapsuleApp to
> support Capsule-on-Disk.
> 
> BZ:https://bugzilla.tianocore.org/show_bug.cgi?id=1482
> 
> CapsuleApp is used for trigger capsule update.
> Add -OD option in CapsuleApp to support doing capsule update via storage.
> Add -F and -L options to support dumping information feature.
> 
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Hao Wu <hao.a.wu@intel.com>
> Cc: Zhang Chao B <chao.b.zhang@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Chen A Chen <chen.a.chen@intel.com>
> ---
>  MdeModulePkg/Application/CapsuleApp/CapsuleApp.c   | 153 +++-
>  MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf |   8 +
>  MdeModulePkg/Application/CapsuleApp/CapsuleDump.c  | 535
> +++++++++++++-
>  .../Application/CapsuleApp/CapsuleOnDisk.c         | 802
> +++++++++++++++++++++
>  MdeModulePkg/Include/Library/UefiBootManagerLib.h  |  19 +
>  MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c   |  22 +
>  6 files changed, 1524 insertions(+), 15 deletions(-)
>  create mode 100644 MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
> 
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> index 4d907242f3..ca9baa0a6a 100644
> --- a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
> @@ -23,6 +23,7 @@
>  #include <Library/PrintLib.h>
>  #include <Library/BmpSupportLib.h>
>  #include <Protocol/GraphicsOutput.h>
> +#include <Guid/GlobalVariable.h>
>  #include <Guid/CapsuleReport.h>
>  #include <Guid/SystemResourceTable.h>
>  #include <Guid/FmpCapsule.h>
> @@ -105,6 +106,44 @@ DumpEsrtData (
>    VOID
>    );
> 
> +/**
> +  Dump Provisioned Capsule.
> +
> +  @param[in]  DumpCapsuleInfo  The flag to indicate whether to dump the
> capsule inforomation.
> +**/
> +VOID
> +DumpProvisionedCapsule (
> +  IN BOOLEAN                      DumpCapsuleInfo
> +  );
> +
> +/**
> +  Dump all EFI System Parition.
> +**/
> +VOID
> +DumpAllEfiSysPartition (
> +  VOID
> +  );
> +
> +/**
> +  Process Capsule On Disk.
> +
> +  @param[in]  CapsuleBuffer    An array of pointer to capsule images
> +  @param[in]  FileSize         An array of UINTN to capsule images size
> +  @param[in]  OrgFileName      An array of orginal capsule images name
> +  @param[in]  NewFileName      An array of new capsule images name
> +  @param[in]  CapsuleNum       The count of capsule images
> +
> +  @retval EFI_SUCCESS       Capsule on disk secceed.
> +**/
> +EFI_STATUS
> +ProcessCapsuleOnDisk (
> +  IN VOID                          **CapsuleBuffer,
> +  IN UINTN                         *CapsuleBufferSize,
> +  IN CHAR16                        **FilePath,
> +  IN CHAR16                        *Map,
> +  IN UINTN                         CapsuleNum
> +  );
> +
>  /**
>    Read a file.
> 
> @@ -799,19 +838,22 @@ PrintUsage (
>    )
>  {
>    Print(L"CapsuleApp:  usage\n");
> -  Print(L"  CapsuleApp <Capsule...> [-NR]\n");
> +  Print(L"  CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");
>    Print(L"  CapsuleApp -S\n");
>    Print(L"  CapsuleApp -C\n");
>    Print(L"  CapsuleApp -P\n");
>    Print(L"  CapsuleApp -E\n");
> +  Print(L"  CapsuleApp -L\n");
> +  Print(L"  CapsuleApp -L INFO\n");
> +  Print(L"  CapsuleApp -F\n");
>    Print(L"  CapsuleApp -G <BMP> -O <Capsule>\n");
>    Print(L"  CapsuleApp -N <Capsule> -O <NestedCapsule>\n");
>    Print(L"  CapsuleApp -D <Capsule>\n");
>    Print(L"  CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");
>    Print(L"Parameter:\n");
> -  Print(L"  -NR: No reset will be triggered for the capsule with\n");
> -  Print(L"       CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without\n");
> -  Print(L"       CAPSULE_FLAGS_INITIATE_RESET.\n");
> +  Print(L"  -NR: No reset will be triggered for the capsule\n");
> +  Print(L"       with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without
> CAPSULE_FLAGS_INITIATE_RESET.\n");
> +  Print(L"  -OD: Delivery of Capsules via file on Mass Storage device.");
>    Print(L"  -S:  Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
>    Print(L"       which is defined in UEFI specification.\n");
>    Print(L"  -C:  Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");
> @@ -820,6 +862,8 @@ PrintUsage (
>    Print(L"       ImageTypeId and Index (decimal format) to a file if 'GET'\n");
>    Print(L"       option is used.\n");
>    Print(L"  -E:  Dump UEFI ESRT table info.\n");
> +  Print(L"  -L:  Dump provisioned capsule image information.\n");
> +  Print(L"  -F:  Dump all EFI System Partition.\n");
>    Print(L"  -G:  Convert a BMP file to be an UX capsule,\n");
>    Print(L"       according to Windows Firmware Update document\n");
>    Print(L"  -N:  Append a Capsule Header to an existing FMP capsule image\n");
> @@ -851,7 +895,7 @@ UefiMain (
>  {
>    EFI_STATUS                    Status;
>    RETURN_STATUS                 RStatus;
> -  UINTN                         FileSize[MAX_CAPSULE_NUM];
> +  UINTN                         CapsuleBufferSize[MAX_CAPSULE_NUM];
>    VOID                          *CapsuleBuffer[MAX_CAPSULE_NUM];
>    EFI_CAPSULE_BLOCK_DESCRIPTOR  *BlockDescriptors;
>    EFI_CAPSULE_HEADER            *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];
> @@ -859,9 +903,14 @@ UefiMain (
>    EFI_RESET_TYPE                ResetType;
>    BOOLEAN                       NeedReset;
>    BOOLEAN                       NoReset;
> +  BOOLEAN                       CapsuleOnDisk;
>    CHAR16                        *CapsuleName;
> +  CHAR16                        *CapsuleNames[MAX_CAPSULE_NUM];
> +  CHAR16                        *MapFsStr;
>    UINTN                         CapsuleNum;
>    UINTN                         Index;
> +  UINTN                         ParaOdIndex;
> +  UINTN                         ParaNrIndex;
>    EFI_GUID                      ImageTypeId;
>    UINTN                         ImageIndex;
> 
> @@ -936,6 +985,20 @@ UefiMain (
>      return EFI_SUCCESS;
>    }
> 
> +  if (StrCmp(Argv[1], L"-L") == 0) {
> +    if (Argc >= 3 && StrCmp(Argv[2], L"INFO") == 0) {
> +      DumpProvisionedCapsule(TRUE);
> +    } else {
> +      DumpProvisionedCapsule(FALSE);
> +    }
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (StrCmp(Argv[1], L"-F") == 0) {
> +    DumpAllEfiSysPartition();
> +    return EFI_SUCCESS;
> +  }
> +
>    if (Argv[1][0] == L'-') {
>      Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);
>      return EFI_UNSUPPORTED;
> @@ -943,12 +1006,56 @@ UefiMain (
> 
>    CapsuleFirstIndex = 1;
>    NoReset = FALSE;
> -  if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) {
> -    NoReset = TRUE;
> -    CapsuleLastIndex = Argc - 2;
> +  CapsuleOnDisk = FALSE;
> +  ParaOdIndex = 0;
> +  ParaNrIndex = 0;
> +
> +  for (Index = 1; Index < Argc; Index ++) {
> +    if (StrCmp(Argv[Index], L"-OD") == 0) {
> +      ParaOdIndex = Index;
> +      CapsuleOnDisk = TRUE;
> +    } else if (StrCmp(Argv[Index], L"-NR") == 0) {
> +      ParaNrIndex = Index;
> +      NoReset = TRUE;
> +    }
> +  }
> +
> +  if (ParaOdIndex != 0) {
> +    if (ParaOdIndex == Argc - 1) {
> +      MapFsStr = NULL;
> +    } else if (ParaOdIndex == Argc - 2) {
> +      MapFsStr = Argv[Argc-1];
> +    } else {
> +      Print (L"CapsuleApp: Invalid Position for -OD Options\n");
> +      Status = EFI_INVALID_PARAMETER;
> +      goto Done;
> +    }
> +
> +    if (ParaNrIndex != 0) {
> +      if (ParaNrIndex + 1 == ParaOdIndex) {
> +        CapsuleLastIndex = ParaNrIndex - 1;
> +      } else {
> +        Print (L"CapsuleApp: Invalid Position for -NR Options\n");
> +        Status = EFI_INVALID_PARAMETER;
> +        goto Done;
> +      }
> +    } else {
> +      CapsuleLastIndex = ParaOdIndex - 1;
> +    }
>    } else {
> -    CapsuleLastIndex = Argc - 1;
> +    if (ParaNrIndex != 0) {
> +      if (ParaNrIndex == Argc -1) {
> +        CapsuleLastIndex = ParaNrIndex - 1;
> +      } else {
> +        Print (L"CapsuleApp: Invalid Position for -NR Options\n");
> +        Status = EFI_INVALID_PARAMETER;
> +        goto Done;
> +      }
> +    } else {
> +      CapsuleLastIndex = Argc - 1;
> +    }
>    }
> +
>    CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;
> 
>    if (CapsuleFirstIndex > CapsuleLastIndex) {
> @@ -961,26 +1068,27 @@ UefiMain (
>    }
> 
>    ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer));
> -  ZeroMem(&FileSize, sizeof(FileSize));
> +  ZeroMem(&CapsuleBufferSize, sizeof(CapsuleBufferSize));
>    BlockDescriptors = NULL;
> 
>    for (Index = 0; Index < CapsuleNum; Index++) {
>      CapsuleName = Argv[CapsuleFirstIndex + Index];
> -    Status = ReadFileToBuffer(CapsuleName, &FileSize[Index],
> &CapsuleBuffer[Index]);
> +    Status = ReadFileToBuffer(CapsuleName, &CapsuleBufferSize[Index],
> &CapsuleBuffer[Index]);
>      if (EFI_ERROR(Status)) {
>        Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);
>        goto Done;
>      }
> -    if (!IsValidCapsuleHeader (CapsuleBuffer[Index], FileSize[Index])) {
> +    if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {
>        Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n",
> CapsuleName);
>        return EFI_INVALID_PARAMETER;
>      }
> +    CapsuleNames[Index] = CapsuleName;
>    }
> 
>    //
>    // Every capsule use 2 descriptor 1 for data 1 for end
>    //
> -  Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum,
> &BlockDescriptors);
> +  Status = BuildGatherList(CapsuleBuffer, CapsuleBufferSize, CapsuleNum,
> &BlockDescriptors);
>    if (EFI_ERROR(Status)) {
>      goto Done;
>    }
> @@ -1007,13 +1115,30 @@ UefiMain (
>    }
> 
>    for (Index = 0; Index < CapsuleNum; Index++) {
> -    if (FileSize[Index] > MaxCapsuleSize) {
> +    if (CapsuleBufferSize[Index] > MaxCapsuleSize) {
>        Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n",
> MaxCapsuleSize);
>        Status = EFI_UNSUPPORTED;
>        goto Done;
>      }
>    }
> 
> +  //
> +  // Check whether is capsule on disk.
> +  //
> +  if (CapsuleOnDisk) {
> +    Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize,
> CapsuleNames, MapFsStr, CapsuleNum);
> +    if (Status != EFI_SUCCESS) {
> +      Print (L"CapsuleApp: failed to update capsule - %r\n", Status);
> +      goto Done;
> +    } else {
> +      if (!NoReset) {
> +        gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);
> +      } else {
> +        goto Done;
> +      }
> +    }
> +  }
> +
>    //
>    // Check whether the input capsule image has the flag of persist across system
> reset.
>    //
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> index 8a21875286..0334e0caaf 100644
> --- a/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf
> @@ -33,6 +33,7 @@
>  [Sources]
>    CapsuleApp.c
>    CapsuleDump.c
> +  CapsuleOnDisk.c
>    AppSupport.c
> 
>  [Packages]
> @@ -40,16 +41,20 @@
>    MdeModulePkg/MdeModulePkg.dec
> 
>  [Guids]
> +  gEfiGlobalVariableGuid                 ## CONSUMES   ## GUID
>    gEfiCapsuleReportGuid                  ## CONSUMES   ## GUID
>    gEfiFmpCapsuleGuid                     ## CONSUMES   ## GUID
>    gWindowsUxCapsuleGuid                  ## CONSUMES   ## GUID
>    gEfiSystemResourceTableGuid            ## CONSUMES   ## GUID
> +  gEfiCapsuleVendorGuid                  ## SOMETIMES_CONSUMES ##
> Variable:L"CapsuleUpdateData"
> +  gEfiPartTypeSystemPartGuid             ## SOMETIMES_CONSUMES ## GUID
> 
>  [Protocols]
>    gEfiGraphicsOutputProtocolGuid         ## CONSUMES
>    gEfiFirmwareManagementProtocolGuid     ## CONSUMES
>    gEfiShellParametersProtocolGuid        ## CONSUMES
>    gEfiShellProtocolGuid                  ## CONSUMES
> +  gEfiSimpleFileSystemProtocolGuid       ## SOMETIMES_CONSUMES
> 
>  [LibraryClasses]
>    BaseLib
> @@ -61,6 +66,9 @@
>    UefiLib
>    PrintLib
>    BmpSupportLib
> +  FileHandleLib
> +  UefiBootManagerLib
> +  SortLib
> 
>  [UserExtensions.TianoCore."ExtraFiles"]
>    CapsuleAppExtra.uni
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> index 7a3eb94362..2af28d711c 100644
> --- a/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c
> @@ -21,13 +21,26 @@
>  #include <Library/UefiRuntimeServicesTableLib.h>
>  #include <Library/UefiLib.h>
>  #include <Library/PrintLib.h>
> +#include <Library/FileHandleLib.h>
> +#include <Library/SortLib.h>
> +#include <Library/UefiBootManagerLib.h>
> +#include <Library/DevicePathLib.h>
>  #include <Protocol/FirmwareManagement.h>
> +#include <Protocol/SimpleFileSystem.h>
> +#include <Protocol/Shell.h>
>  #include <Guid/ImageAuthentication.h>
>  #include <Guid/CapsuleReport.h>
>  #include <Guid/SystemResourceTable.h>
>  #include <Guid/FmpCapsule.h>
> +#include <Guid/CapsuleVendor.h>
>  #include <IndustryStandard/WindowsUxCapsule.h>
> 
> +//
> +// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)
> +//
> +#define MAX_FILE_NAME_SIZE   522
> +#define MAX_FILE_NAME_LEN    (MAX_FILE_NAME_SIZE / sizeof(CHAR16))
> +
>  /**
>    Read a file.
> 
> @@ -61,6 +74,37 @@ WriteFileFromBuffer (
>    IN  VOID                                 *Buffer
>    );
> 
> +/**
> +  Get shell protocol.
> +
> +  @return Pointer to shell protocol.
> +
> +**/
> +EFI_SHELL_PROTOCOL *
> +GetShellProtocol (
> +  VOID
> +  );
> +
> +/**
> +  Get SimpleFileSystem from boot option file path
> +
> +  @param[in]  DevicePath     The file path of boot option
> +  @param[out] FullPath       The full device path of boot device
> +  @param[out] Fs             The file system within EfiSysPartition
> +
> +  @retval EFI_SUCCESS    Get file system successfully
> +  @retval EFI_NOT_FOUND  No valid file system found
> +  @retval others         Get file system failed
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetEfiSysPartitionFromBootOptionFilePath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL         *DevicePath,
> +  OUT EFI_DEVICE_PATH_PROTOCOL         **FullPath,
> +  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs
> +  );
> +
>  /**
>    Validate if it is valid capsule header
> 
> @@ -123,7 +167,7 @@ DumpFmpCapsule (
>    UINTN                                         Count;
>    EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
> *FmpImageHeader;
> 
> -  Print(L"[FmpCapusule]\n");
> +  Print(L"[FmpCapsule]\n");
>    Print(L"CapsuleHeader:\n");
>    Print(L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);
>    Print(L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);
> @@ -504,6 +548,495 @@ DumpEsrtData (
>    Print(L"\n");
>  }
> 
> +
> +/**
> +  Dump capsule information from CapsuleHeader
> +
> +  @param[in] CapsuleHeader       The CapsuleHeader of the capsule image.
> +
> +  @retval EFI_SUCCESS            The capsule information is dumped.
> +
> +**/
> +EFI_STATUS
> +DumpCapsuleFromBuffer (
> +  IN EFI_CAPSULE_HEADER                         *CapsuleHeader
> +  )
> +{
> +  if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid))
> {
> +    DumpUxCapsule (CapsuleHeader);
> +    return EFI_SUCCESS;
> +  }
> +
> +  if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {
> +    DumpFmpCapsule (CapsuleHeader);
> +  }
> +  if (IsNestedFmpCapsule (CapsuleHeader)) {
> +    Print (L"[NestedCapusule]\n");
> +    Print (L"CapsuleHeader:\n");
> +    Print (L"  CapsuleGuid      - %g\n", &CapsuleHeader->CapsuleGuid);
> +    Print (L"  HeaderSize       - 0x%x\n", CapsuleHeader->HeaderSize);
> +    Print (L"  Flags            - 0x%x\n", CapsuleHeader->Flags);
> +    Print (L"  CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);
> +    DumpFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader +
> CapsuleHeader->HeaderSize));
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  This routine is called to upper case given unicode string
> +
> +  @param[in]   Str              String to upper case
> +
> +  @retval upper cased string after process
> +
> +**/
> +STATIC
> +CHAR16 *
> +UpperCaseString (
> +  IN CHAR16 *Str
> +  )
> +{
> +  CHAR16  *Cptr;
> +
> +  for (Cptr = Str; *Cptr; Cptr++) {
> +    if (L'a' <= *Cptr && *Cptr <= L'z') {
> +      *Cptr = *Cptr - L'a' + L'A';
> +    }
> +  }
> +
> +  return Str;
> +}
> +
> +/**
> +  This routine is used to return substring before period '.' or '\0'
> +  Caller should respsonsible of substr space allocation & free
> +
> +  @param[in]   Str              String to check
> +  @param[out]  SubStr           First part of string before period or '\0'
> +  @param[out]  SubStrLen        Length of first part of string
> +
> +**/
> +STATIC
> +VOID
> +GetSubStringBeforePeriod (
> +  IN  CHAR16 *Str,
> +  OUT CHAR16 *SubStr,
> +  OUT UINTN  *SubStrLen
> +  )
> +{
> +  UINTN Index;
> +  for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {
> +    SubStr[Index] = Str[Index];
> +  }
> +
> +  SubStr[Index] = L'\0';
> +  *SubStrLen = Index;
> +}
> +
> +/**
> +  This routine pad the string in tail with input character.
> +
> +  @param[in]   StrBuf            Str buffer to be padded, should be enough room for
> +  @param[in]   PadLen            Expected padding length
> +  @param[in]   Character         Character used to pad
> +
> +**/
> +STATIC
> +VOID
> +PadStrInTail (
> +  IN CHAR16   *StrBuf,
> +  IN UINTN    PadLen,
> +  IN CHAR16   Character
> +  )
> +{
> +  UINTN Index;
> +
> +  for (Index = 0; StrBuf[Index] != L'\0'; Index++);
> +
> +  while(PadLen != 0) {
> +    StrBuf[Index] = Character;
> +    Index++;
> +    PadLen--;
> +  }
> +
> +  StrBuf[Index] = L'\0';
> + }
> +
> +/**
> +  This routine find the offset of the last period '.' of string. if No period exists
> +  function FileNameExtension is set to L'\0'
> +
> +  @param[in]   FileName          File name to split between last period
> +  @param[out]  FileNameFirst      First FileName before last period
> +  @param[out]  FileNameExtension  FileName after last period
> +
> +**/
> +STATIC
> +VOID
> +SplitFileNameExtension (
> +  IN  CHAR16  *FileName,
> +  OUT CHAR16  *FileNameFirst,
> +  OUT CHAR16  *FileNameExtension
> +  )
> +{
> +  UINTN Index;
> +  UINTN StringLen;
> +
> +  StringLen = StrLen(FileName);
> +  for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);
> +
> +  //
> +  // No period exists. No FileName Extension
> +  //
> +  if (Index == 0 && FileName[Index] != L'.') {
> +    FileNameExtension[0] = L'\0';
> +    Index = StringLen;
> +  } else {
> +    StrCpyS (FileNameExtension, MAX_FILE_NAME_LEN, &FileName[Index+1]);
> +  }
> +
> +  //
> +  // Copy First file name
> +  //
> +  StrnCpyS (FileNameFirst, MAX_FILE_NAME_LEN, FileName, Index);
> +  FileNameFirst[Index] = L'\0';
> +}
> +
> +/**
> +  The function is called by PerformQuickSort to sort file name in alphabet.
> +
> +  @param[in] Left            The pointer to first buffer.
> +  @param[in] Right           The pointer to second buffer.
> +
> +  @retval 0                  Buffer1 equal to Buffer2.
> +  @return <0                 Buffer1 is less than Buffer2.
> +  @return >0                 Buffer1 is greater than Buffer2.
> +
> +**/
> +INTN
> +EFIAPI
> +CompareFileNameInAlphabet (
> +  IN EFI_PHYSICAL_ADDRESS  *Left,
> +  IN EFI_PHYSICAL_ADDRESS  *Right
> +  ) {
> +  EFI_FILE_INFO  *FileInfo1;
> +  EFI_FILE_INFO  *FileInfo2;
> +  CHAR16         FileName1[MAX_FILE_NAME_SIZE];
> +  CHAR16         FileExtension1[MAX_FILE_NAME_SIZE];
> +  CHAR16         FileName2[MAX_FILE_NAME_SIZE];
> +  CHAR16         FileExtension2[MAX_FILE_NAME_SIZE];
> +  CHAR16         TempSubStr1[MAX_FILE_NAME_SIZE];
> +  CHAR16         TempSubStr2[MAX_FILE_NAME_SIZE];
> +  UINTN          SubStrLen1;
> +  UINTN          SubStrLen2;
> +  INTN           SubStrCmpResult;
> +
> +  FileInfo1 = (EFI_FILE_INFO *) *Left;
> +  FileInfo2 = (EFI_FILE_INFO *) *Right;
> +
> +  SplitFileNameExtension (FileInfo1->FileName, FileName1, FileExtension1);
> +  SplitFileNameExtension (FileInfo2->FileName, FileName2, FileExtension2);
> +
> +  UpperCaseString (FileName1);
> +  UpperCaseString (FileName2);
> +
> +  GetSubStringBeforePeriod (FileName1, TempSubStr1, &SubStrLen1);
> +  GetSubStringBeforePeriod (FileName2, TempSubStr2, &SubStrLen2);
> +
> +  if (SubStrLen1 > SubStrLen2) {
> +    //
> +    // Substr in NewFileName is longer.  Pad tail with SPACE
> +    //
> +    PadStrInTail (TempSubStr2, SubStrLen1 - SubStrLen2, L' ');
> +  } else if (SubStrLen1 < SubStrLen2){
> +    //
> +    // Substr in ListedFileName is longer. Pad tail with SPACE
> +    //
> +    PadStrInTail (TempSubStr1, SubStrLen2 - SubStrLen1, L' ');
> +  }
> +
> +  SubStrCmpResult = StrnCmp (TempSubStr1, TempSubStr2,
> MAX_FILE_NAME_LEN);
> +  if (SubStrCmpResult != 0) {
> +    return SubStrCmpResult;
> +  }
> +
> +  UpperCaseString (FileExtension1);
> +  UpperCaseString (FileExtension2);
> +
> +  return StrnCmp (FileExtension1, FileExtension2, MAX_FILE_NAME_LEN);
> +}
> +
> +/**
> +  Dump capsule information from disk
> +
> +  @param[in] DevicePath          The device path of disk.
> +  @param[in] DumpCapsuleInfo     The flag to indicate whether to dump the
> capsule inforomation.
> +
> +  @retval EFI_SUCCESS            The capsule information is dumped.
> +
> +**/
> +EFI_STATUS
> +DumpCapsuleFromDisk (
> +  IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL            *Fs,
> +  IN BOOLEAN                                    DumpCapsuleInfo
> +  )
> +{
> +  EFI_STATUS                                    Status;
> +  EFI_FILE                                      *Root;
> +  EFI_FILE                                      *DirHandle;
> +  EFI_FILE                                      *FileHandle;
> +  UINTN                                         Index;
> +  UINTN                                         FileSize;
> +  VOID                                          *FileBuffer;
> +  EFI_FILE_INFO                                 **FileInfoBuffer;
> +  EFI_FILE_INFO                                 *FileInfo;
> +  UINTN                                         FileCount;
> +  BOOLEAN                                       NoFile;
> +
> +  DirHandle  = NULL;
> +  FileHandle = NULL;
> +  Index      = 0;
> +  FileCount  = 0;
> +  NoFile     = FALSE;
> +
> +  Status = Fs->OpenVolume (Fs, &Root);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"Cannot open volume. Status = %r\n", Status);
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FROM_FILE_DIR,
> EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FROM_FILE_DIR,
> Status);
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Get file count first
> +  //
> +  for ( Status = FileHandleFindFirstFile (DirHandle, &FileInfo)
> +      ; !EFI_ERROR(Status) && !NoFile
> +      ; Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile)
> +     ){
> +    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) == 0) {
> +      continue;
> +    }
> +    FileCount ++;
> +  }
> +
> +  if (FileCount == 0) {
> +    Print (L"Error: No capsule file found!\n");
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  FileInfoBuffer = AllocatePool (sizeof(FileInfo) * FileCount);
> +  NoFile = FALSE;
> +
> +  //
> +  // Get all file info
> +  //
> +  for ( Status = FileHandleFindFirstFile (DirHandle, &FileInfo)
> +      ; !EFI_ERROR (Status) && !NoFile
> +      ; Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile)
> +     ){
> +    if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) == 0) {
> +      continue;
> +    }
> +    FileInfoBuffer[Index ++] = AllocateCopyPool (FileInfo->Size, FileInfo);
> +  }
> +
> +  //
> +  // Sort FileInfoBuffer by alphabet order
> +  //
> +  PerformQuickSort (
> +    FileInfoBuffer,
> +    FileCount,
> +    sizeof (FileInfo),
> +    (SORT_COMPARE) CompareFileNameInAlphabet
> +    );
> +
> +  Print (L"The capsules will be performed by following order:\n");
> +
> +  for (Index = 0; Index < FileCount; Index ++) {
> +    Print (L"  %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName);
> +  }
> +
> +  if (!DumpCapsuleInfo) {
> +    return EFI_SUCCESS;
> +  }
> +
> +  Print(L"The infomation of the capsules:\n");
> +
> +  for (Index = 0; Index < FileCount; Index ++) {
> +    FileHandle = NULL;
> +    Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]-
> >FileName, EFI_FILE_MODE_READ, 0);
> +    if (EFI_ERROR (Status)) {
> +      break;
> +    }
> +
> +    Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]-
> >FileName, Status);
> +      FileHandleClose (FileHandle);
> +      return Status;
> +    }
> +
> +    FileBuffer = AllocatePool (FileSize);
> +    if (FileBuffer == NULL) {
> +      return RETURN_OUT_OF_RESOURCES;
> +    }
> +
> +    Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]-
> >FileName, Status);
> +      FreePool (FileBuffer);
> +      FileHandleClose (FileHandle);
> +      return Status;
> +    }
> +
> +    Print (L"**************************\n");
> +    Print (L"  %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName);
> +    Print (L"**************************\n");
> +    DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer);
> +    FileHandleClose (FileHandle);
> +    FreePool (FileBuffer);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Dump capsule inforomation form Gather list.
> +
> +  @param[in]  BlockDescriptors The block descriptors for the capsule images
> +  @param[in]  DumpCapsuleInfo  The flag to indicate whether to dump the
> capsule inforomation.
> +
> +**/
> +VOID
> +DumpBlockDescriptors (
> +  IN EFI_CAPSULE_BLOCK_DESCRIPTOR   *BlockDescriptors,
> +  IN BOOLEAN                        DumpCapsuleInfo
> +  )
> +{
> +  EFI_CAPSULE_BLOCK_DESCRIPTOR      *TempBlockPtr;
> +
> +  TempBlockPtr = BlockDescriptors;
> +
> +  while (TRUE) {
> +    if (TempBlockPtr->Length != 0) {
> +      if (DumpCapsuleInfo) {
> +
> Print(L"******************************************************\n");
> +      }
> +      Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlockPtr-
> >Union.DataBlock, TempBlockPtr->Length);
> +      if (DumpCapsuleInfo) {
> +
> Print(L"******************************************************\n");
> +        DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN)
> TempBlockPtr->Union.DataBlock);
> +      }
> +      TempBlockPtr += 1;
> +    } else {
> +      if (TempBlockPtr->Union.ContinuationPointer == (UINTN)NULL) {
> +        break;
> +      } else {
> +        TempBlockPtr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN)
> TempBlockPtr->Union.ContinuationPointer;
> +      }
> +    }
> +  }
> +}
> +
> +/**
> +  Dump Provisioned Capsule.
> +
> +  @param[in]  DumpCapsuleInfo  The flag to indicate whether to dump the
> capsule inforomation.
> +
> +**/
> +VOID
> +DumpProvisionedCapsule (
> +  IN BOOLEAN                      DumpCapsuleInfo
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  CHAR16                          CapsuleVarName[30];
> +  CHAR16                          *TempVarName;
> +  UINTN                           Index;
> +  EFI_PHYSICAL_ADDRESS            *CapsuleDataPtr64;
> +  UINT16                          *BootNext;
> +  CHAR16                          BootOptionName[20];
> +  EFI_BOOT_MANAGER_LOAD_OPTION    BootNextOptionEntry;
> +  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
> +  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
> +  EFI_SHELL_PROTOCOL              *ShellProtocol;
> +
> +  ShellProtocol = GetShellProtocol ();
> +
> +  Index = 0;
> +
> +  //
> +  // Dump capsule provisioned on Memory
> +  //
> +  Print (L"#########################\n");
> +  Print (L"### Capsule on Memory ###\n");
> +  Print (L"#########################\n");
> +  StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16),
> EFI_CAPSULE_VARIABLE_NAME);
> +  TempVarName = CapsuleVarName + StrLen (CapsuleVarName);
> +  while (TRUE) {
> +    if (Index > 0) {
> +      UnicodeValueToStringS (
> +        TempVarName,
> +        sizeof (CapsuleVarName) - ((UINTN)TempVarName -
> (UINTN)CapsuleVarName),
> +        0,
> +        Index,
> +        0
> +        );
> +    }
> +
> +    Status = GetVariable2 (
> +              CapsuleVarName,
> +              &gEfiCapsuleVendorGuid,
> +              (VOID **) &CapsuleDataPtr64,
> +              NULL
> +              );
> +    if (EFI_ERROR (Status)) {
> +      if (Index == 0) {
> +        Print (L"No data.\n");
> +      }
> +      break;
> +    } else {
> +      Index ++;
> +      Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64);
> +      DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN)
> *CapsuleDataPtr64, DumpCapsuleInfo);
> +    }
> +  }
> +
> +  //
> +  // Dump capsule provisioned on Disk
> +  //
> +  Print (L"#########################\n");
> +  Print (L"### Capsule on Disk #####\n");
> +  Print (L"#########################\n");
> +  Status = GetVariable2 (
> +             L"BootNext",
> +             &gEfiGlobalVariableGuid,
> +             (VOID **) &BootNext,
> +             NULL
> +            );
> +  if (!EFI_ERROR (Status)) {
> +    UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x",
> *BootNext);
> +    Status = EfiBootManagerVariableToLoadOption (BootOptionName,
> &BootNextOptionEntry);
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Display description and device path
> +      //
> +      GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath,
> &DevicePath, &Fs);
> +      if(!EFI_ERROR (Status)) {
> +        Print (L"Capsules are provisioned on BootOption: %s\n",
> BootNextOptionEntry.Description);
> +        Print (L"    %s %s\n", ShellProtocol->GetMapFromDevicePath
> (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE));
> +        DumpCapsuleFromDisk (Fs, DumpCapsuleInfo);
> +      }
> +    }
> +  }
> +}
> +
>  /**
>    Dump FMP information.
> 
> diff --git a/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
> b/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
> new file mode 100644
> index 0000000000..ad9ad9ba87
> --- /dev/null
> +++ b/MdeModulePkg/Application/CapsuleApp/CapsuleOnDisk.c
> @@ -0,0 +1,802 @@
> +/** @file
> +  Process Capsule On Disk.
> +
> +  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
> +  This program and the accompanying materials
> +  are licensed and made available under the terms and conditions of the BSD
> License
> +  which accompanies this distribution.  The full text of the license may be found
> at
> +  http://opensource.org/licenses/bsd-license.php
> +
> +  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
> +  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER
> EXPRESS OR IMPLIED.
> +
> +**/
> +#include <Uefi.h>
> +#include <Library/BaseLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <Library/UefiLib.h>
> +#include <Library/PrintLib.h>
> +#include <Library/DevicePathLib.h>
> +#include <Library/FileHandleLib.h>
> +#include <Library/UefiBootManagerLib.h>
> +#include <Protocol/SimpleFileSystem.h>
> +#include <Protocol/Shell.h>
> +#include <Guid/FileInfo.h>
> +#include <Guid/GlobalVariable.h>
> +#include <Guid/Gpt.h>
> +
> +EFI_GUID mCapsuleOnDiskBootOptionGuid = { 0x4CC29BB7, 0x2413, 0x40A2,
> { 0xB0, 0x6D, 0x25, 0x3E, 0x37, 0x10, 0xF5, 0x32 } };
> +
> +/**
> +  Get shell protocol.
> +
> +  @return Pointer to shell protocol.
> +
> +**/
> +EFI_SHELL_PROTOCOL *
> +GetShellProtocol (
> +  VOID
> +  );
> +
> +/**
> +  Get file name from file path
> +
> +  @return Pointer to file name.
> +
> +**/
> +CHAR16 *
> +GetFileNameFromPath (
> +  CHAR16                            *FilePath
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_SHELL_PROTOCOL                *ShellProtocol;
> +  SHELL_FILE_HANDLE                 Handle;
> +  EFI_FILE_INFO                     *FileInfo;
> +
> +  ShellProtocol = GetShellProtocol ();
> +  if (ShellProtocol == NULL) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Open file by FileName.
> +  //
> +  Status = ShellProtocol->OpenFileByName (
> +                            FilePath,
> +                            &Handle,
> +                            EFI_FILE_MODE_READ
> +                            );
> +  if (EFI_ERROR (Status)) {
> +    return NULL;
> +  }
> +
> +  //
> +  // Get file name from EFI_FILE_INFO.
> +  //
> +  FileInfo = ShellProtocol->GetFileInfo (Handle);
> +  ShellProtocol->CloseFile (Handle);
> +  if (FileInfo == NULL) {
> +    return NULL;
> +  }
> +
> +  return FileInfo->FileName;
> +}
> +
> +/**
> +  Check if the device path is EFI system parition.
> +
> +  @retval TRUE    DevicePath is a device path for ESP.
> +  @retval FALSE   DevicePath is not a device path for ESP.
> +
> +**/
> +BOOLEAN
> +IsEfiSysPartitionDevicePath (
> +  EFI_DEVICE_PATH_PROTOCOL   *DevicePath
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  EFI_DEVICE_PATH_PROTOCOL   *TempDevicePath;
> +  HARDDRIVE_DEVICE_PATH      *Hd;
> +  EFI_HANDLE                 Handle;
> +
> +  //
> +  // 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);
> +    return EFI_ERROR (Status) ? FALSE : TRUE;
> +  } else {
> +    return FALSE;
> +  }
> +}
> +
> +/**
> +  Dump all EFI System Parition.
> +
> +**/
> +VOID
> +DumpAllEfiSysPartition (
> +  VOID
> +  )
> +{
> +  EFI_HANDLE                 *SimpleFileSystemHandles;
> +  UINTN                      NumberSimpleFileSystemHandles;
> +  UINTN                      Index;
> +  EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
> +  UINTN                      NumberEfiSystemPartitions;
> +  EFI_SHELL_PROTOCOL         *ShellProtocol;
> +
> +  ShellProtocol = GetShellProtocol ();
> +  NumberEfiSystemPartitions = 0;
> +
> +  Print (L"EFI System Partition list:\n");
> +
> +  gBS->LocateHandleBuffer (
> +         ByProtocol,
> +         &gEfiSimpleFileSystemProtocolGuid,
> +         NULL,
> +         &NumberSimpleFileSystemHandles,
> +         &SimpleFileSystemHandles
> +         );
> +
> +  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index ++) {
> +    DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
> +    if (IsEfiSysPartitionDevicePath (DevicePath)) {
> +      NumberEfiSystemPartitions ++;
> +      Print(L"    %s\n        %s\n", ShellProtocol->GetMapFromDevicePath
> (&DevicePath), ConvertDevicePathToText (DevicePath, TRUE, TRUE));
> +    }
> +  }
> +
> +  if (NumberEfiSystemPartitions == 0) {
> +    Print(L"    No ESP found.\n");
> +  }
> +}
> +
> +/**
> +  Check if capsule is provisioned.
> +
> +  @retval TRUE    Capsule is provisioned previously.
> +  @retval FALSE   No capsule is provisioned.
> +
> +**/
> +BOOLEAN
> +IsCapsuleProvisioned (
> +  VOID
> +  )
> +{
> +  EFI_STATUS            Status;
> +  UINT64                OsIndication;
> +  UINTN                 DataSize;
> +
> +  OsIndication = 0;
> +  DataSize = sizeof(UINT64);
> +  Status = gRT->GetVariable (
> +                  L"OsIndications",
> +                  &gEfiGlobalVariableGuid,
> +                  NULL,
> +                  &DataSize,
> +                  &OsIndication
> +                  );
> +  if (!EFI_ERROR (Status) &&
> +      (OsIndication &
> EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) != 0) {
> +    return TRUE;
> +  }
> +
> +  return FALSE;
> +}
> +
> +/**
> +  Get one active Efi System Partition
> +
> +  @param[out] FsDevicePath   The device path of Fs
> +  @param[out] Fs             The file system within EfiSysPartition
> +
> +  @retval EFI_SUCCESS     Get file system successfully
> +  @retval EFI_NOT_FOUND   No valid file system found
> +
> +**/
> +EFI_STATUS
> +GetEfiSysPartition (
> +  OUT EFI_DEVICE_PATH_PROTOCOL         **FsDevicePath,
> +  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs
> +  )
> +{
> +  EFI_HANDLE                 *SimpleFileSystemHandles;
> +  UINTN                      NumberSimpleFileSystemHandles;
> +  UINTN                      Index;
> +  EFI_DEVICE_PATH_PROTOCOL   *DevicePath;
> +  EFI_STATUS                 Status;
> +
> +  Status = gBS->LocateHandleBuffer (
> +                  ByProtocol,
> +                  &gEfiSimpleFileSystemProtocolGuid,
> +                  NULL,
> +                  &NumberSimpleFileSystemHandles,
> +                  &SimpleFileSystemHandles
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  for (Index = 0; Index < NumberSimpleFileSystemHandles; Index ++) {
> +    DevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
> +    if (IsEfiSysPartitionDevicePath (DevicePath)) {
> +      Status = gBS->HandleProtocol (SimpleFileSystemHandles[Index],
> &gEfiSimpleFileSystemProtocolGuid, Fs);
> +      if (!EFI_ERROR (Status)) {
> +        *FsDevicePath = DevicePath;
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Check if Active Efi System Partition within GPT is in the device path
> +
> +  @param[in]  DevicePath     The device path
> +  @param[out] FullPath       The device path of Fs
> +  @param[out] Fs             The file system within EfiSysPartition
> +
> +  @retval EFI_SUCCESS    Get file system successfully
> +  @retval EFI_NOT_FOUND  No valid file system found
> +  @retval others         Get file system failed
> +
> +**/
> +EFI_STATUS
> +GetEfiSysPartitionFromDevPath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL        *DevicePath,
> +  OUT EFI_DEVICE_PATH_PROTOCOL        **FsDevicePath,
> +  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs
> +  )
> +{
> +  EFI_STATUS                 Status;
> +  EFI_DEVICE_PATH_PROTOCOL   *TempDevicePath;
> +  HARDDRIVE_DEVICE_PATH      *Hd;
> +  EFI_HANDLE                 Handle;
> +
> +  //
> +  // 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,
> Fs);
> +      if (!EFI_ERROR (Status)) {
> +        *FsDevicePath = DevicePathFromHandle (Handle);
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Get SimpleFileSystem from boot option file path
> +
> +  @param[in]  DevicePath     The file path of boot option
> +  @param[out] FullPath       The full device path of boot device
> +  @param[out] Fs             The file system within EfiSysPartition
> +
> +  @retval EFI_SUCCESS    Get file system successfully
> +  @retval EFI_NOT_FOUND  No valid file system found
> +  @retval others         Get file system failed
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetEfiSysPartitionFromBootOptionFilePath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL         *DevicePath,
> +  OUT EFI_DEVICE_PATH_PROTOCOL         **FullPath,
> +  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs
> +  )
> +{
> +  EFI_STATUS                        Status;
> +  EFI_DEVICE_PATH_PROTOCOL          *CurFullPath;
> +  EFI_DEVICE_PATH_PROTOCOL          *PreFullPath;
> +  EFI_DEVICE_PATH_PROTOCOL          *FsFullPath;
> +
> +  CurFullPath = NULL;
> +  FsFullPath = NULL;
> +  //
> +  // Try every full device Path generated from bootoption
> +  //
> +  do {
> +    PreFullPath = CurFullPath;
> +    CurFullPath = EfiBootManagerGetNextFullDevicePath (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 *DevicePathStr;
> +
> +      DevicePathStr = ConvertDevicePathToText (CurFullPath, TRUE, TRUE);
> +      if (DevicePathStr != NULL){
> +        DEBUG ((DEBUG_INFO, "Full device path %s\n", DevicePathStr));
> +        FreePool (DevicePathStr);
> +      }
> +    );
> +
> +    Status = GetEfiSysPartitionFromDevPath (CurFullPath, &FsFullPath, Fs);
> +  } while (EFI_ERROR (Status));
> +
> +  if (*Fs != NULL) {
> +    *FullPath = FsFullPath;
> +    return EFI_SUCCESS;
> +  } else {
> +    return EFI_NOT_FOUND;
> +  }
> +}
> +
> +/**
> +  Get a valid SimpleFileSystem within EFI system partition
> +
> +  @param[In]  Map             The FS mapping capsule write to
> +  @param[out] BootNext        The value of BootNext Variable
> +  @param[out] Handle          The file system handle
> +  @param[out] UpdateBootNext  The flag to indicate whether update
> BootNext Variable
> +
> +  @retval EFI_SUCCESS    Get FS successfully
> +  @retval EFI_NOT_FOUND  No valid FS found
> +  @retval others         Get FS failed
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +GetUpdateFileSystem (
> +  IN  CHAR16                           *Map,
> +  OUT UINT16                           *BootNext,
> +  OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  **Fs,
> +  OUT BOOLEAN                          *UpdateBootNext
> +)
> +{
> +  EFI_STATUS                      Status;
> +  CHAR16                          BootOptionName[20];
> +  UINTN                           Index;
> +  CONST EFI_DEVICE_PATH_PROTOCOL  *MappedDevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL        *DevicePath;
> +  EFI_DEVICE_PATH_PROTOCOL        *FullPath;
> +  UINT16                          *BootNextData;
> +  EFI_BOOT_MANAGER_LOAD_OPTION    BootNextOption;
> +  EFI_BOOT_MANAGER_LOAD_OPTION    *BootOptionBuffer;
> +  UINTN                           BootOptionCount;
> +  EFI_SHELL_PROTOCOL              *ShellProtocol;
> +  EFI_BOOT_MANAGER_LOAD_OPTION    NewOption;
> +
> +  MappedDevicePath = NULL;
> +  ShellProtocol = GetShellProtocol ();
> +
> +  //
> +  // 1. If Fs is not assigned and there are capsule provisioned before,
> +  // Get EFI system partition from BootNext.
> +  //
> +  if (IsCapsuleProvisioned () && Map == NULL) {
> +    Status = GetVariable2 (
> +               L"BootNext",
> +               &gEfiGlobalVariableGuid,
> +               &BootNextData,
> +               NULL
> +               );
> +    if (!EFI_ERROR (Status)) {
> +      UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x",
> *BootNextData);
> +      Status = EfiBootManagerVariableToLoadOption (BootOptionName,
> &BootNextOption);
> +      if (!EFI_ERROR (Status)) {
> +        DevicePath = BootNextOption.FilePath;
> +        Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath,
> Fs);
> +        if (!EFI_ERROR (Status)) {
> +          *UpdateBootNext = FALSE;
> +          Print(L"Get EFI system partition from BootNext : %s\n",
> BootNextOption.Description);
> +          Print(L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath),
> ConvertDevicePathToText (FullPath, TRUE, TRUE));
> +          return EFI_SUCCESS;
> +        }
> +      }
> +    }
> +  }
> +
> +  //
> +  // Check if Map is valid.
> +  //
> +  if (Map != NULL) {
> +    MappedDevicePath = ShellProtocol->GetDevicePathFromMap (Map);
> +    if (MappedDevicePath == NULL) {
> +      Print(L"'%s' is not a valid mapping.\n", Map);
> +      return EFI_INVALID_PARAMETER;
> +    } else if (!IsEfiSysPartitionDevicePath (DuplicateDevicePath
> (MappedDevicePath))) {
> +      Print(L"'%s' is not a EFI System Partition.\n", Map);
> +      return EFI_INVALID_PARAMETER;
> +    }
> +  }
> +
> +  //
> +  // 2. Get EFI system partition form boot options.
> +  //
> +  BootOptionBuffer = EfiBootManagerGetLoadOptions (&BootOptionCount,
> LoadOptionTypeBoot);
> +  if (BootOptionCount == 0 && Map == NULL) {
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  for (Index = 0; Index < BootOptionCount; Index ++) {
> +    //
> +    // Get the boot option from the link list
> +    //
> +    DevicePath  = BootOptionBuffer[Index].FilePath;
> +
> +    //
> +    // Skip inactive or legacy boot options
> +    //
> +    if ((BootOptionBuffer[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"));
> +      }
> +    );
> +
> +    Status = GetEfiSysPartitionFromBootOptionFilePath (DevicePath, &FullPath,
> Fs);
> +    if (!EFI_ERROR (Status)) {
> +      if (Map == NULL) {
> +        *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
> +        *UpdateBootNext = TRUE;
> +        Print (L"Found EFI system partition on Boot%04x: %s\n", *BootNext,
> BootOptionBuffer[Index].Description);
> +        Print (L"%s %s\n", ShellProtocol->GetMapFromDevicePath (&FullPath),
> ConvertDevicePathToText (FullPath, TRUE, TRUE));
> +        return EFI_SUCCESS;
> +      }
> +
> +      if (StrnCmp (Map, ShellProtocol->GetMapFromDevicePath (&FullPath),
> StrLen (Map)) == 0) {
> +        *BootNext = (UINT16) BootOptionBuffer[Index].OptionNumber;
> +        *UpdateBootNext = TRUE;
> +        Print (L"Found Boot Option on %s : %s\n", Map,
> BootOptionBuffer[Index].Description);
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  //
> +  // 3. If no ESP is found on boot option, try to find a ESP and create boot
> option for it.
> +  //
> +  if (Map != NULL) {
> +    //
> +    // If map is assigned, try to get ESP from mapped Fs.
> +    //
> +    DevicePath = DuplicateDevicePath (MappedDevicePath);
> +    Status = GetEfiSysPartitionFromDevPath (DevicePath, &FullPath, Fs);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Error: Cannot get EFI system partiion from '%s' - %r\n", Map,
> Status);
> +      return EFI_NOT_FOUND;
> +    }
> +    Print (L"Warning: Cannot find Boot Option on '%s'!\n", Map);
> +  } else {
> +    Status = GetEfiSysPartition (&DevicePath, Fs);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Error: Cannot find a EFI system partition!\n");
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  Print (L"Create Boot option for capsule on disk:\n");
> +  Status = EfiBootManagerInitializeLoadOption (
> +             &NewOption,
> +             LoadOptionNumberUnassigned,
> +             LoadOptionTypeBoot,
> +             LOAD_OPTION_ACTIVE,
> +             L"UEFI Capsule On Disk",
> +             DevicePath,
> +             (UINT8 *) &mCapsuleOnDiskBootOptionGuid,
> +             sizeof(EFI_GUID)
> +             );
> +  if (!EFI_ERROR (Status)) {
> +    Status = EfiBootManagerAddLoadOptionVariable (&NewOption, (UINTN) -1);
> {
> +      if (!EFI_ERROR (Status)) {
> +        *UpdateBootNext = TRUE;
> +        *BootNext = (UINT16) NewOption.OptionNumber;
> +        Print (L"  Boot%04x: %s\n", *BootNext,
> ConvertDevicePathToText(DevicePath, TRUE, TRUE));
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  Print (L"ERROR: Cannot create boot option! - %r\n", Status);
> +
> +  return EFI_NOT_FOUND;
> +}
> +
> +/**
> +  Write files to a given SimpleFileSystem.
> +
> +  @param[in] Buffer          The file buffer array
> +  @param[in] BufferSize      The file buffer size array
> +  @param[in] FileName        The file file name array
> +  @param[in] BufferNum       The file buffer number
> +  @param[in] Fs              The SimpleFileSystem handle to be written
> +
> +  @retval EFI_SUCCESS    Write file successfully
> +  @retval EFI_NOT_FOUND  SFS protocol not found
> +  @retval others         Write file failed
> +
> +**/
> +EFI_STATUS
> +WriteUpdateFile (
> +  IN  VOID                                 **Buffer,
> +  IN  UINTN                                *BufferSize,
> +  IN  CHAR16                               **FileName,
> +  IN  UINTN                                BufferNum,
> +  IN  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL      *Fs
> +)
> +{
> +  EFI_STATUS                          Status;
> +  EFI_FILE                            *Root;
> +  CHAR16                              *mDirName = L"\\EFI\\UpdateCapsule";
> +  CHAR16                              *mDirName1 = L"\\EFI";
> +  EFI_FILE_PROTOCOL                   *DirHandle = NULL;
> +  EFI_FILE                            *FileHandle = NULL;
> +  UINT64                              FileInfo;
> +  UINTN                               Index = 0;
> +  VOID                                *Filebuffer;
> +  UINTN                               FileSize;
> +
> +  //
> +  // Open Root from SFS
> +  //
> +  Status = Fs->OpenVolume (Fs, &Root);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"Cannot open volume. Status = %r\n", Status);
> +    return EFI_NOT_FOUND;
> +  }
> +
> +  //
> +  // Ensure that efi and updatecapsule directories exist
> +  //
> +  Status = Root->Open (Root, &DirHandle, mDirName1, EFI_FILE_MODE_READ
> | EFI_FILE_MODE_WRITE , 0);
> +  if (EFI_ERROR (Status)) {
> +    Status = Root->Open (Root, &DirHandle, mDirName1, EFI_FILE_MODE_READ
> | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
> +    if (EFI_ERROR (Status)) {
> +      Print(L"Unable to create %s directory\n", mDirName1);
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +  Status = Root->Open (Root, &DirHandle, mDirName, EFI_FILE_MODE_READ |
> EFI_FILE_MODE_WRITE , 0);
> +  if (EFI_ERROR (Status)) {
> +    Status = Root->Open (Root, &DirHandle, mDirName, EFI_FILE_MODE_READ
> | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, EFI_FILE_DIRECTORY);
> +    if (EFI_ERROR (Status)) {
> +      Print(L"Unable to create %s directory\n", mDirName);
> +      return EFI_NOT_FOUND;
> +    }
> +  }
> +
> +  for (Index = 0; Index < BufferNum; Index ++) {
> +    FileHandle = NULL;
> +
> +    //
> +    // Open UpdateCapsule file
> +    //
> +    Status = DirHandle->Open (DirHandle, &FileHandle, FileName[Index],
> EFI_FILE_MODE_CREATE | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ, 0);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Unable to create %s file\n", FileName[Index]);
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    //
> +    // Empty the file contents
> +    //
> +    Status = FileHandleGetSize (FileHandle, &FileInfo);
> +    if (EFI_ERROR (Status)) {
> +      FileHandleClose (FileHandle);
> +      Print (L"Error Reading %s\n", FileName[Index]);
> +      return EFI_DEVICE_ERROR;
> +    }
> +
> +    //
> +    // If the file size is already 0, then it has been empty.
> +    //
> +    if (FileInfo != 0) {
> +      //
> +      // Set the file size to 0.
> +      //
> +      FileInfo = 0;
> +      Status = FileHandleSetSize (FileHandle, FileInfo);
> +      if (EFI_ERROR (Status)) {
> +        Print (L"Error Deleting %s\n", FileName[Index]);
> +        FileHandleClose (FileHandle);
> +        return Status;
> +      }
> +    }
> +
> +    //
> +    // Write Filebuffer to file
> +    //
> +    Filebuffer = Buffer[Index];
> +    FileSize = BufferSize[Index];
> +    Status = FileHandleWrite (FileHandle, &FileSize, Filebuffer);
> +    if (EFI_ERROR (Status)) {
> +      Print (L"Unable to write Capsule Update to %s, Status = %r\n",
> FileName[Index], Status);
> +      return EFI_NOT_FOUND;
> +    }
> +
> +    Print (L"Succeed to write %s\n", FileName[Index]);
> +    FileHandleClose (FileHandle);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Set capsule status variable.
> +
> +  @param[in] SetCap     Set or clear the capsule flag.
> +
> +  @retval EFI_SUCCESS   Succeed to set SetCap variable.
> +  @retval others        Fail to set the variable.
> +
> +**/
> +EFI_STATUS
> +SetCapsuleStatusVariable (
> +  BOOLEAN                       SetCap
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  UINT64                        OsIndication;
> +  UINTN                         DataSize;
> +
> +  OsIndication = 0;
> +  DataSize = sizeof(UINT64);
> +  Status = gRT->GetVariable (
> +                  L"OsIndications",
> +                  &gEfiGlobalVariableGuid,
> +                  NULL,
> +                  &DataSize,
> +                  &OsIndication
> +                  );
> +  if (EFI_ERROR (Status)) {
> +    OsIndication = 0;
> +  }
> +  if (SetCap) {
> +    OsIndication |=
> ((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
> +  }
> +  else {
> +    OsIndication &=
> ~((UINT64)EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED);
> +  }
> +  Status = gRT->SetVariable (
> +                  L"OsIndications",
> +                  &gEfiGlobalVariableGuid,
> +                  EFI_VARIABLE_BOOTSERVICE_ACCESS |
> EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
> +                  sizeof(UINT64),
> +                  &OsIndication
> +                  );
> +
> +  return Status;
> +}
> +
> +/**
> +  Process Capsule On Disk.
> +
> +  @param[in]  CapsuleBuffer    An array of pointer to capsule images
> +  @param[in]  FileSize         An array of UINTN to capsule images size
> +  @param[in]  FilePath         An array of capsule images file path
> +  @param[in]  NewFileName      An array of new capsule images name
> +  @param[in]  CapsuleNum       The count of capsule images
> +
> +  @retval EFI_SUCCESS       Capsule on disk secceed.
> +  @retval others            Capsule on disk fail.
> +
> +**/
> +EFI_STATUS
> +ProcessCapsuleOnDisk (
> +  IN VOID                          **CapsuleBuffer,
> +  IN UINTN                         *CapsuleBufferSize,
> +  IN CHAR16                        **FilePath,
> +  IN CHAR16                        *Map,
> +  IN UINTN                         CapsuleNum
> +  )
> +{
> +  EFI_STATUS                      Status;
> +  UINT16                          BootNext;
> +  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;
> +  BOOLEAN                         UpdateBootNext;
> +
> +  //
> +  // Get a valid file system from boot path
> +  //
> +  Fs = NULL;
> +
> +  Status = GetUpdateFileSystem (Map, &BootNext, &Fs, &UpdateBootNext);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"CapsuleApp: cannot find a valid file system on boot devies. Status
> = %r\n", Status);
> +    return Status;
> +  }
> +
> +  //
> +  // Copy capsule image to '\efi\UpdateCapsule\'
> +  //
> +  Status = WriteUpdateFile (CapsuleBuffer, CapsuleBufferSize, FilePath,
> CapsuleNum, Fs);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"CapsuleApp: capsule image could not be copied for update.\n");
> +    return Status;
> +  }
> +
> +  //
> +  // Set variable then reset
> +  //
> +  Status = SetCapsuleStatusVariable (TRUE);
> +  if (EFI_ERROR (Status)) {
> +    Print (L"CapsuleApp: unable to set OSIndication variable.\n");
> +    return Status;
> +  }
> +
> +  if (UpdateBootNext) {
> +    Status = gRT->SetVariable (
> +      L"BootNext",
> +      &gEfiGlobalVariableGuid,
> +      EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS
> | EFI_VARIABLE_NON_VOLATILE,
> +      sizeof(UINT16),
> +      &BootNext
> +      );
> +    if (EFI_ERROR (Status)){
> +      Print (L"CapsuleApp: unable to set BootNext variable.\n");
> +      return Status;
> +    }
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> \ No newline at end of file
> diff --git a/MdeModulePkg/Include/Library/UefiBootManagerLib.h
> b/MdeModulePkg/Include/Library/UefiBootManagerLib.h
> index bfc0cb86f8..9302398936 100644
> --- a/MdeModulePkg/Include/Library/UefiBootManagerLib.h
> +++ b/MdeModulePkg/Include/Library/UefiBootManagerLib.h
> @@ -445,6 +445,25 @@ EfiBootManagerGetBootManagerMenu (
>    EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
>    );
> 
> +/**
> +  Get the next possible full path pointing to the load option.
> +  The routine doesn't guarantee the returned full path points to an existing
> +  file, and it also doesn't guarantee the existing file is a valid load option.
> +  BmGetNextLoadOptionBuffer() guarantees.
> +
> +  @param FilePath  The device path pointing to a load option.
> +                   It could be a short-form device path.
> +  @param FullPath  The full path returned by the routine in last call.
> +                   Set to NULL in first call.
> +
> +  @return The next possible full path pointing to the load option.
> +          Caller is responsible to free the memory.
> +**/
> +EFI_DEVICE_PATH_PROTOCOL *
> +EfiBootManagerGetNextFullDevicePath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
> +  IN  EFI_DEVICE_PATH_PROTOCOL          *FullPath
> +  );
> 
>  /**
>    Get the load option by its device path.
> diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
> b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
> index 6a23477eb8..3b9195ba50 100644
> --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
> +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c
> @@ -2461,3 +2461,25 @@ EfiBootManagerGetBootManagerMenu (
>    }
>  }
> 
> +/**
> +  Get the next possible full path pointing to the load option.
> +  The routine doesn't guarantee the returned full path points to an existing
> +  file, and it also doesn't guarantee the existing file is a valid load option.
> +  BmGetNextLoadOptionBuffer() guarantees.
> +
> +  @param FilePath  The device path pointing to a load option.
> +                   It could be a short-form device path.
> +  @param FullPath  The full path returned by the routine in last call.
> +                   Set to NULL in first call.
> +
> +  @return The next possible full path pointing to the load option.
> +          Caller is responsible to free the memory.
> +**/
> +EFI_DEVICE_PATH_PROTOCOL *
> +EfiBootManagerGetNextFullDevicePath (
> +  IN  EFI_DEVICE_PATH_PROTOCOL          *FilePath,
> +  IN  EFI_DEVICE_PATH_PROTOCOL          *FullPath
> +  )
> +{
> +  return BmGetNextLoadOptionDevicePath(FilePath, FullPath);
> +}
> --
> 2.16.2.windows.1



  reply	other threads:[~2019-01-28  2:57 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-28  1:21 [PATCH v2 2/2] MdeModulePkg/CapsuleApp: Enhance CapsuleApp to support Capsule-on-Disk Chen A Chen
2019-01-28  2:57 ` Wang, Jian J [this message]
2019-01-29  3:24 ` Wang, Jian J

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=D827630B58408649ACB04F44C5100036258A7395@SHSMSX107.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox