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.c...@intel.com>; Wang, Jian J > <jian.j.w...@intel.com>; Wu, Hao A <hao.a...@intel.com>; Zhang, Chao B > <chao.b.zh...@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.w...@intel.com> > Cc: Hao Wu <hao.a...@intel.com> > Cc: Zhang Chao B <chao.b.zh...@intel.com> > Contributed-under: TianoCore Contribution Agreement 1.1 > Signed-off-by: Chen A Chen <chen.a.c...@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 _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel