/** @file\r
Dump Capsule image information.\r
\r
- Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include <Library/UefiRuntimeServicesTableLib.h>\r
#include <Library/UefiLib.h>\r
#include <Library/PrintLib.h>\r
+#include <Library/FileHandleLib.h>\r
+#include <Library/SortLib.h>\r
+#include <Library/UefiBootManagerLib.h>\r
+#include <Library/DevicePathLib.h>\r
#include <Protocol/FirmwareManagement.h>\r
+#include <Protocol/SimpleFileSystem.h>\r
+#include <Protocol/Shell.h>\r
#include <Guid/ImageAuthentication.h>\r
#include <Guid/CapsuleReport.h>\r
#include <Guid/SystemResourceTable.h>\r
#include <Guid/FmpCapsule.h>\r
+#include <Guid/CapsuleVendor.h>\r
#include <IndustryStandard/WindowsUxCapsule.h>\r
\r
+//\r
+// (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)\r
+//\r
+#define MAX_FILE_NAME_SIZE 522\r
+#define MAX_FILE_NAME_LEN (MAX_FILE_NAME_SIZE / sizeof(CHAR16))\r
+\r
/**\r
Read a file.\r
\r
- @param[in] FileName The file to be read.\r
- @param[in] BufferSize The file buffer size\r
- @param[in] Buffer The file buffer\r
+ @param[in] FileName The file to be read.\r
+ @param[out] BufferSize The file buffer size\r
+ @param[out] Buffer The file buffer\r
\r
@retval EFI_SUCCESS Read file successfully\r
@retval EFI_NOT_FOUND File not found\r
OUT VOID **Buffer\r
);\r
\r
+/**\r
+ Write a file.\r
+\r
+ @param[in] FileName The file to be written.\r
+ @param[in] BufferSize The file buffer size\r
+ @param[in] Buffer The file buffer\r
+\r
+ @retval EFI_SUCCESS Write file successfully\r
+**/\r
+EFI_STATUS\r
+WriteFileFromBuffer (\r
+ IN CHAR16 *FileName,\r
+ IN UINTN BufferSize,\r
+ IN VOID *Buffer\r
+ );\r
+\r
+/**\r
+ Get shell protocol.\r
+\r
+ @return Pointer to shell protocol.\r
+\r
+**/\r
+EFI_SHELL_PROTOCOL *\r
+GetShellProtocol (\r
+ VOID\r
+ );\r
+\r
+/**\r
+ Get SimpleFileSystem from boot option file path.\r
+\r
+ @param[in] DevicePath The file path of boot option\r
+ @param[out] FullPath The full device path of boot device\r
+ @param[out] Fs The file system within EfiSysPartition\r
+\r
+ @retval EFI_SUCCESS Get file system successfully\r
+ @retval EFI_NOT_FOUND No valid file system found\r
+ @retval others Get file system failed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetEfiSysPartitionFromBootOptionFilePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r
+ OUT EFI_DEVICE_PATH_PROTOCOL **FullPath,\r
+ OUT EFI_SIMPLE_FILE_SYSTEM_PROTOCOL **Fs\r
+ );\r
+\r
+/**\r
+ Validate if it is valid capsule header\r
+\r
+ This function assumes the caller provided correct CapsuleHeader pointer\r
+ and CapsuleSize.\r
+\r
+ This function validates the fields in EFI_CAPSULE_HEADER.\r
+\r
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[in] CapsuleSize Size of the whole capsule image.\r
+\r
+**/\r
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINT64 CapsuleSize\r
+ );\r
+\r
/**\r
Dump UX capsule information.\r
\r
Print(L" OffsetY - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY);\r
}\r
\r
-/**\r
- Dump FMP image authentication information.\r
-\r
- @param[in] Image The FMP capsule image\r
- @param[in] ImageSize The size of the FMP capsule image in bytes.\r
-\r
- @return the size of FMP authentication.\r
-**/\r
-UINTN\r
-DumpImageAuthentication (\r
- IN VOID *Image,\r
- IN UINTN ImageSize\r
- )\r
-{\r
- EFI_FIRMWARE_IMAGE_AUTHENTICATION *ImageAuthentication;\r
-\r
- ImageAuthentication = Image;\r
- if (CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertPkcs7Guid) ||\r
- CompareGuid(&ImageAuthentication->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid)) {\r
- Print(L"[ImageAuthentication]\n");\r
- Print(L" MonotonicCount - 0x%lx\n", ImageAuthentication->MonotonicCount);\r
- Print(L"WIN_CERTIFICATE:\n");\r
- Print(L" dwLength - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.dwLength);\r
- Print(L" wRevision - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wRevision);\r
- Print(L" wCertificateType - 0x%x\n", ImageAuthentication->AuthInfo.Hdr.wCertificateType);\r
- Print(L" CertType - %g\n", &ImageAuthentication->AuthInfo.CertType);\r
- return sizeof(ImageAuthentication->MonotonicCount) + ImageAuthentication->AuthInfo.Hdr.dwLength;\r
- } else {\r
- return 0;\r
- }\r
-}\r
\r
/**\r
Dump a non-nested FMP capsule.\r
UINTN Count;\r
EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader;\r
\r
- Print(L"[FmpCapusule]\n");\r
+ Print(L"[FmpCapsule]\n");\r
Print(L"CapsuleHeader:\n");\r
Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);\r
Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);\r
// FMP GUID after ESRT one\r
//\r
NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
- NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->HeaderSize - (UINTN)NestedCapsuleHeader;\r
+ NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize- (UINTN)NestedCapsuleHeader;\r
if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) {\r
return FALSE;\r
}\r
EFI_CAPSULE_HEADER *CapsuleHeader;\r
EFI_STATUS Status;\r
\r
+ Buffer = NULL;\r
Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer);\r
if (EFI_ERROR(Status)) {\r
Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName);\r
goto Done;\r
}\r
+ if (!IsValidCapsuleHeader (Buffer, FileSize)) {\r
+ Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto Done;\r
+ }\r
\r
CapsuleHeader = Buffer;\r
if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
}\r
\r
Done:\r
- FreePool(Buffer);\r
+ if (Buffer != NULL) {\r
+ FreePool(Buffer);\r
+ }\r
return Status;\r
}\r
\r
@retval EFI_UNSUPPORTED Input parameter is not valid.\r
**/\r
EFI_STATUS\r
-DmpCapsuleStatusVariable (\r
+DumpCapsuleStatusVariable (\r
VOID\r
)\r
{\r
UINTN CapsuleFileNameSize;\r
CHAR16 CapsuleIndexData[12];\r
CHAR16 *CapsuleIndex;\r
+ CHAR16 *CapsuleFileName;\r
+ CHAR16 *CapsuleTarget;\r
\r
Status = GetVariable2(\r
L"CapsuleMax",\r
NULL\r
);\r
if (!EFI_ERROR(Status)) {\r
+ ASSERT (CapsuleIndex != NULL);\r
CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));\r
CapsuleIndexData[11] = 0;\r
Print(L"CapsuleMax - %s\n", CapsuleIndexData);\r
NULL\r
);\r
if (!EFI_ERROR(Status)) {\r
+ ASSERT (CapsuleIndex != NULL);\r
CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16));\r
CapsuleIndexData[11] = 0;\r
Print(L"CapsuleLast - %s\n", CapsuleIndexData);\r
}\r
\r
if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
- if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {\r
+ if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) {\r
CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1);\r
Print(L" Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version);\r
Print(L" Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->PayloadIndex);\r
Print(L" Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFmp->UpdateImageIndex);\r
Print(L" Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFmp->UpdateImageTypeId);\r
- if (CapsuleResult->VariableTotalSize > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP)) {\r
- Print(L" Capsule FMP CapsuleFileName: %s\n", (CapsuleResultFmp + 1));\r
- CapsuleFileNameSize = StrSize((CHAR16 *)(CapsuleResultFmp + 1));\r
- if (CapsuleResult->VariableTotalSize > sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapsuleFileNameSize) {\r
- Print(L" Capsule FMP CapsuleTarget: %s\n", (UINT8 *)(CapsuleResultFmp + 1) + CapsuleFileNameSize);\r
- }\r
- }\r
+ CapsuleFileName = (CHAR16 *)(CapsuleResultFmp + 1);\r
+ Print(L" Capsule FMP CapsuleFileName: \"%s\"\n", CapsuleFileName);\r
+ CapsuleFileNameSize = StrSize(CapsuleFileName);\r
+ CapsuleTarget = (CHAR16 *)((UINTN)CapsuleFileName + CapsuleFileNameSize);\r
+ Print(L" Capsule FMP CapsuleTarget: \"%s\"\n", CapsuleTarget);\r
}\r
}\r
\r
Print(L" FwVersion - 0x%x\n", EsrtEntry->FwVersion);\r
Print(L" LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupportedFwVersion);\r
Print(L" CapsuleFlags - 0x%x\n", EsrtEntry->CapsuleFlags);\r
- Print(L" PERSIST_ACROSS_RESET - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET);\r
- Print(L" POPULATE_SYSTEM_TABLE - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE);\r
- Print(L" INITIATE_RESET - 0x%x\n", EsrtEntry->CapsuleFlags & CAPSULE_FLAGS_INITIATE_RESET);\r
Print(L" LastAttemptVersion - 0x%x\n", EsrtEntry->LastAttemptVersion);\r
Print(L" LastAttemptStatus - 0x%x (%a)\n", EsrtEntry->LastAttemptStatus, LastAttemptStatusToString(EsrtEntry->LastAttemptStatus));\r
}\r
Print(L"\n");\r
}\r
\r
+\r
+/**\r
+ Dump capsule information from CapsuleHeader\r
+\r
+ @param[in] CapsuleHeader The CapsuleHeader of the capsule image.\r
+\r
+ @retval EFI_SUCCESS The capsule information is dumped.\r
+\r
+**/\r
+EFI_STATUS\r
+DumpCapsuleFromBuffer (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+{\r
+ if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
+ DumpUxCapsule (CapsuleHeader);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) {\r
+ DumpFmpCapsule (CapsuleHeader);\r
+ }\r
+ if (IsNestedFmpCapsule (CapsuleHeader)) {\r
+ Print (L"[NestedCapusule]\n");\r
+ Print (L"CapsuleHeader:\n");\r
+ Print (L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);\r
+ Print (L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);\r
+ Print (L" Flags - 0x%x\n", CapsuleHeader->Flags);\r
+ Print (L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize);\r
+ DumpFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize));\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This routine is called to upper case given unicode string.\r
+\r
+ @param[in] Str String to upper case\r
+\r
+ @retval upper cased string after process\r
+\r
+**/\r
+STATIC\r
+CHAR16 *\r
+UpperCaseString (\r
+ IN CHAR16 *Str\r
+ )\r
+{\r
+ CHAR16 *Cptr;\r
+\r
+ for (Cptr = Str; *Cptr != L'\0'; Cptr++) {\r
+ if (L'a' <= *Cptr && *Cptr <= L'z') {\r
+ *Cptr = *Cptr - L'a' + L'A';\r
+ }\r
+ }\r
+\r
+ return Str;\r
+}\r
+\r
+/**\r
+ This routine is used to return substring before period '.' or '\0'\r
+ Caller should respsonsible of substr space allocation & free\r
+\r
+ @param[in] Str String to check\r
+ @param[out] SubStr First part of string before period or '\0'\r
+ @param[out] SubStrLen Length of first part of string\r
+\r
+**/\r
+STATIC\r
+VOID\r
+GetSubStringBeforePeriod (\r
+ IN CHAR16 *Str,\r
+ OUT CHAR16 *SubStr,\r
+ OUT UINTN *SubStrLen\r
+ )\r
+{\r
+ UINTN Index;\r
+ for (Index = 0; Str[Index] != L'.' && Str[Index] != L'\0'; Index++) {\r
+ SubStr[Index] = Str[Index];\r
+ }\r
+\r
+ SubStr[Index] = L'\0';\r
+ *SubStrLen = Index;\r
+}\r
+\r
+/**\r
+ This routine pad the string in tail with input character.\r
+\r
+ @param[in] StrBuf Str buffer to be padded, should be enough room for\r
+ @param[in] PadLen Expected padding length\r
+ @param[in] Character Character used to pad\r
+\r
+**/\r
+STATIC\r
+VOID\r
+PadStrInTail (\r
+ IN CHAR16 *StrBuf,\r
+ IN UINTN PadLen,\r
+ IN CHAR16 Character\r
+ )\r
+{\r
+ UINTN Index;\r
+\r
+ for (Index = 0; StrBuf[Index] != L'\0'; Index++);\r
+\r
+ while(PadLen != 0) {\r
+ StrBuf[Index] = Character;\r
+ Index++;\r
+ PadLen--;\r
+ }\r
+\r
+ StrBuf[Index] = L'\0';\r
+}\r
+\r
+/**\r
+ This routine find the offset of the last period '.' of string. if No period exists\r
+ function FileNameExtension is set to L'\0'\r
+\r
+ @param[in] FileName File name to split between last period\r
+ @param[out] FileNameFirst First FileName before last period\r
+ @param[out] FileNameExtension FileName after last period\r
+\r
+**/\r
+STATIC\r
+VOID\r
+SplitFileNameExtension (\r
+ IN CHAR16 *FileName,\r
+ OUT CHAR16 *FileNameFirst,\r
+ OUT CHAR16 *FileNameExtension\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN StringLen;\r
+\r
+ StringLen = StrLen(FileName);\r
+ for (Index = StringLen; Index > 0 && FileName[Index] != L'.'; Index--);\r
+\r
+ //\r
+ // No period exists. No FileName Extension\r
+ //\r
+ if (Index == 0 && FileName[Index] != L'.') {\r
+ FileNameExtension[0] = L'\0';\r
+ Index = StringLen;\r
+ } else {\r
+ StrCpyS (FileNameExtension, MAX_FILE_NAME_LEN, &FileName[Index+1]);\r
+ }\r
+\r
+ //\r
+ // Copy First file name\r
+ //\r
+ StrnCpyS (FileNameFirst, MAX_FILE_NAME_LEN, FileName, Index);\r
+ FileNameFirst[Index] = L'\0';\r
+}\r
+\r
+/**\r
+ The function is called by PerformQuickSort to sort file name in alphabet.\r
+\r
+ @param[in] Left The pointer to first buffer.\r
+ @param[in] Right The pointer to second buffer.\r
+\r
+ @retval 0 Buffer1 equal to Buffer2.\r
+ @return <0 Buffer1 is less than Buffer2.\r
+ @return >0 Buffer1 is greater than Buffer2.\r
+\r
+**/\r
+INTN\r
+EFIAPI\r
+CompareFileNameInAlphabet (\r
+ IN VOID *Left,\r
+ IN VOID *Right\r
+ )\r
+{\r
+ EFI_FILE_INFO *FileInfo1;\r
+ EFI_FILE_INFO *FileInfo2;\r
+ CHAR16 FileName1[MAX_FILE_NAME_SIZE];\r
+ CHAR16 FileExtension1[MAX_FILE_NAME_SIZE];\r
+ CHAR16 FileName2[MAX_FILE_NAME_SIZE];\r
+ CHAR16 FileExtension2[MAX_FILE_NAME_SIZE];\r
+ CHAR16 TempSubStr1[MAX_FILE_NAME_SIZE];\r
+ CHAR16 TempSubStr2[MAX_FILE_NAME_SIZE];\r
+ UINTN SubStrLen1;\r
+ UINTN SubStrLen2;\r
+ INTN SubStrCmpResult;\r
+\r
+ FileInfo1 = (EFI_FILE_INFO *) (*(UINTN *)Left);\r
+ FileInfo2 = (EFI_FILE_INFO *) (*(UINTN *)Right);\r
+\r
+ SplitFileNameExtension (FileInfo1->FileName, FileName1, FileExtension1);\r
+ SplitFileNameExtension (FileInfo2->FileName, FileName2, FileExtension2);\r
+\r
+ UpperCaseString (FileName1);\r
+ UpperCaseString (FileName2);\r
+\r
+ GetSubStringBeforePeriod (FileName1, TempSubStr1, &SubStrLen1);\r
+ GetSubStringBeforePeriod (FileName2, TempSubStr2, &SubStrLen2);\r
+\r
+ if (SubStrLen1 > SubStrLen2) {\r
+ //\r
+ // Substr in NewFileName is longer. Pad tail with SPACE\r
+ //\r
+ PadStrInTail (TempSubStr2, SubStrLen1 - SubStrLen2, L' ');\r
+ } else if (SubStrLen1 < SubStrLen2){\r
+ //\r
+ // Substr in ListedFileName is longer. Pad tail with SPACE\r
+ //\r
+ PadStrInTail (TempSubStr1, SubStrLen2 - SubStrLen1, L' ');\r
+ }\r
+\r
+ SubStrCmpResult = StrnCmp (TempSubStr1, TempSubStr2, MAX_FILE_NAME_LEN);\r
+ if (SubStrCmpResult != 0) {\r
+ return SubStrCmpResult;\r
+ }\r
+\r
+ UpperCaseString (FileExtension1);\r
+ UpperCaseString (FileExtension2);\r
+\r
+ return StrnCmp (FileExtension1, FileExtension2, MAX_FILE_NAME_LEN);\r
+}\r
+\r
+/**\r
+ Dump capsule information from disk.\r
+\r
+ @param[in] Fs The device path of disk.\r
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.\r
+\r
+ @retval EFI_SUCCESS The capsule information is dumped.\r
+\r
+**/\r
+EFI_STATUS\r
+DumpCapsuleFromDisk (\r
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs,\r
+ IN BOOLEAN DumpCapsuleInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FILE *Root;\r
+ EFI_FILE *DirHandle;\r
+ EFI_FILE *FileHandle;\r
+ UINTN Index;\r
+ UINTN FileSize;\r
+ VOID *FileBuffer;\r
+ EFI_FILE_INFO **FileInfoBuffer;\r
+ EFI_FILE_INFO *FileInfo;\r
+ UINTN FileCount;\r
+ BOOLEAN NoFile;\r
+\r
+ DirHandle = NULL;\r
+ FileHandle = NULL;\r
+ Index = 0;\r
+ FileInfoBuffer = NULL;\r
+ FileInfo = NULL;\r
+ FileCount = 0;\r
+ NoFile = FALSE;\r
+\r
+ Status = Fs->OpenVolume (Fs, &Root);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"Cannot open volume. Status = %r\n", Status);\r
+ goto Done;\r
+ }\r
+\r
+ Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status);\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Get file count first\r
+ //\r
+ do {\r
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\r
+ if (EFI_ERROR (Status) || FileInfo == NULL) {\r
+ Print (L"Get File Info Fail. Status = %r\n", Status);\r
+ goto Done;\r
+ }\r
+\r
+ if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {\r
+ FileCount++;\r
+ }\r
+\r
+ Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"Get Next File Fail. Status = %r\n", Status);\r
+ goto Done;\r
+ }\r
+ } while (!NoFile);\r
+\r
+ if (FileCount == 0) {\r
+ Print (L"Error: No capsule file found!\n");\r
+ Status = EFI_NOT_FOUND;\r
+ goto Done;\r
+ }\r
+\r
+ FileInfoBuffer = AllocateZeroPool (sizeof (FileInfo) * FileCount);\r
+ if (FileInfoBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+ NoFile = FALSE;\r
+\r
+ //\r
+ // Get all file info\r
+ //\r
+ do {\r
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\r
+ if (EFI_ERROR (Status) || FileInfo == NULL) {\r
+ Print (L"Get File Info Fail. Status = %r\n", Status);\r
+ goto Done;\r
+ }\r
+\r
+ if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) {\r
+ FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo);\r
+ }\r
+\r
+ Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"Get Next File Fail. Status = %r\n", Status);\r
+ goto Done;\r
+ }\r
+ } while (!NoFile);\r
+\r
+ //\r
+ // Sort FileInfoBuffer by alphabet order\r
+ //\r
+ PerformQuickSort (\r
+ FileInfoBuffer,\r
+ FileCount,\r
+ sizeof (FileInfo),\r
+ (SORT_COMPARE) CompareFileNameInAlphabet\r
+ );\r
+\r
+ Print (L"The capsules will be performed by following order:\n");\r
+\r
+ for (Index = 0; Index < FileCount; Index++) {\r
+ Print (L" %d.%s\n", Index + 1, FileInfoBuffer[Index]->FileName);\r
+ }\r
+\r
+ if (!DumpCapsuleInfo) {\r
+ Status = EFI_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ Print(L"The infomation of the capsules:\n");\r
+\r
+ for (Index = 0; Index < FileCount; Index++) {\r
+ FileHandle = NULL;\r
+ Status = DirHandle->Open (DirHandle, &FileHandle, FileInfoBuffer[Index]->FileName, EFI_FILE_MODE_READ, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);\r
+ FileHandleClose (FileHandle);\r
+ goto Done;\r
+ }\r
+\r
+ FileBuffer = AllocatePool (FileSize);\r
+ if (FileBuffer == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ Status = FileHandleRead (FileHandle, &FileSize, FileBuffer);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status);\r
+ FileHandleClose (FileHandle);\r
+ FreePool (FileBuffer);\r
+ goto Done;\r
+ }\r
+\r
+ Print (L"**************************\n");\r
+ Print (L" %d.%s:\n", Index + 1, FileInfoBuffer[Index]->FileName);\r
+ Print (L"**************************\n");\r
+ DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) FileBuffer);\r
+ FileHandleClose (FileHandle);\r
+ FreePool (FileBuffer);\r
+ }\r
+\r
+Done:\r
+ if (FileInfoBuffer != NULL) {\r
+ for (Index = 0; Index < FileCount; Index++) {\r
+ if (FileInfoBuffer[Index] != NULL) {\r
+ FreePool (FileInfoBuffer[Index]);\r
+ }\r
+ }\r
+ FreePool (FileInfoBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Dump capsule inforomation form Gather list.\r
+\r
+ @param[in] BlockDescriptors The block descriptors for the capsule images\r
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.\r
+\r
+**/\r
+VOID\r
+DumpBlockDescriptors (\r
+ IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
+ IN BOOLEAN DumpCapsuleInfo\r
+ )\r
+{\r
+ EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
+\r
+ TempBlockPtr = BlockDescriptors;\r
+\r
+ while (TRUE) {\r
+ if (TempBlockPtr->Length != 0) {\r
+ if (DumpCapsuleInfo) {\r
+ Print(L"******************************************************\n");\r
+ }\r
+ Print(L"Capsule data starts at 0x%08x with size 0x%08x\n", TempBlockPtr->Union.DataBlock, TempBlockPtr->Length);\r
+ if (DumpCapsuleInfo) {\r
+ Print(L"******************************************************\n");\r
+ DumpCapsuleFromBuffer ((EFI_CAPSULE_HEADER *) (UINTN) TempBlockPtr->Union.DataBlock);\r
+ }\r
+ TempBlockPtr += 1;\r
+ } else {\r
+ if (TempBlockPtr->Union.ContinuationPointer == (UINTN)NULL) {\r
+ break;\r
+ } else {\r
+ TempBlockPtr = (EFI_CAPSULE_BLOCK_DESCRIPTOR *) (UINTN) TempBlockPtr->Union.ContinuationPointer;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ Dump Provisioned Capsule.\r
+\r
+ @param[in] DumpCapsuleInfo The flag to indicate whether to dump the capsule inforomation.\r
+\r
+**/\r
+VOID\r
+DumpProvisionedCapsule (\r
+ IN BOOLEAN DumpCapsuleInfo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 CapsuleVarName[30];\r
+ CHAR16 *TempVarName;\r
+ UINTN Index;\r
+ EFI_PHYSICAL_ADDRESS *CapsuleDataPtr64;\r
+ UINT16 *BootNext;\r
+ CHAR16 BootOptionName[20];\r
+ EFI_BOOT_MANAGER_LOAD_OPTION BootNextOptionEntry;\r
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Fs;\r
+ EFI_SHELL_PROTOCOL *ShellProtocol;\r
+\r
+ Index = 0;\r
+ CapsuleDataPtr64 = NULL;\r
+ BootNext = NULL;\r
+\r
+ ShellProtocol = GetShellProtocol ();\r
+ if (ShellProtocol == NULL) {\r
+ Print (L"Get Shell Protocol Fail\n");\r
+ return ;\r
+ }\r
+\r
+ //\r
+ // Dump capsule provisioned on Memory\r
+ //\r
+ Print (L"#########################\n");\r
+ Print (L"### Capsule on Memory ###\n");\r
+ Print (L"#########################\n");\r
+ StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CHAR16), EFI_CAPSULE_VARIABLE_NAME);\r
+ TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
+ while (TRUE) {\r
+ if (Index > 0) {\r
+ UnicodeValueToStringS (\r
+ TempVarName,\r
+ sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
+ 0,\r
+ Index,\r
+ 0\r
+ );\r
+ }\r
+\r
+ Status = GetVariable2 (\r
+ CapsuleVarName,\r
+ &gEfiCapsuleVendorGuid,\r
+ (VOID **) &CapsuleDataPtr64,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status) || CapsuleDataPtr64 == NULL) {\r
+ if (Index == 0) {\r
+ Print (L"No data.\n");\r
+ }\r
+ break;\r
+ }\r
+\r
+ Index++;\r
+ Print (L"Capsule Description at 0x%08x\n", *CapsuleDataPtr64);\r
+ DumpBlockDescriptors ((EFI_CAPSULE_BLOCK_DESCRIPTOR*) (UINTN) *CapsuleDataPtr64, DumpCapsuleInfo);\r
+ }\r
+\r
+ //\r
+ // Dump capsule provisioned on Disk\r
+ //\r
+ Print (L"#########################\n");\r
+ Print (L"### Capsule on Disk #####\n");\r
+ Print (L"#########################\n");\r
+ Status = GetVariable2 (\r
+ L"BootNext",\r
+ &gEfiGlobalVariableGuid,\r
+ (VOID **) &BootNext,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status) || BootNext == NULL) {\r
+ Print (L"Get BootNext Variable Fail. Status = %r\n", Status);\r
+ } else {\r
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", *BootNext);\r
+ Status = EfiBootManagerVariableToLoadOption (BootOptionName, &BootNextOptionEntry);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Display description and device path\r
+ //\r
+ GetEfiSysPartitionFromBootOptionFilePath (BootNextOptionEntry.FilePath, &DevicePath, &Fs);\r
+ if(!EFI_ERROR (Status)) {\r
+ Print (L"Capsules are provisioned on BootOption: %s\n", BootNextOptionEntry.Description);\r
+ Print (L" %s %s\n", ShellProtocol->GetMapFromDevicePath (&DevicePath), ConvertDevicePathToText(DevicePath, TRUE, TRUE));\r
+ DumpCapsuleFromDisk (Fs, DumpCapsuleInfo);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
/**\r
Dump FMP information.\r
\r
EXIT:\r
FreePool(HandleBuffer);\r
}\r
+\r
+/**\r
+ Check if the ImageInfo includes the ImageTypeId.\r
+\r
+ @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+ @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.\r
+ @param[in] ImageTypeId A unique GUID identifying the firmware image type.\r
+\r
+ @return TRUE This ImageInfo includes the ImageTypeId\r
+ @return FALSE This ImageInfo does not include the ImageTypeId\r
+**/\r
+BOOLEAN\r
+IsThisFmpImageInfo (\r
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,\r
+ IN UINT8 DescriptorCount,\r
+ IN UINTN DescriptorSize,\r
+ IN EFI_GUID *ImageTypeId\r
+ )\r
+{\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;\r
+ UINTN Index;\r
+\r
+ CurrentImageInfo = ImageInfo;\r
+ for (Index = 0; Index < DescriptorCount; Index++) {\r
+ if (CompareGuid (&CurrentImageInfo->ImageTypeId, ImageTypeId)) {\r
+ return TRUE;\r
+ }\r
+ CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);\r
+ }\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ return the FMP whoes ImageInfo includes the ImageTypeId.\r
+\r
+ @param[in] ImageTypeId A unique GUID identifying the firmware image type.\r
+\r
+ @return The FMP whoes ImageInfo includes the ImageTypeId\r
+**/\r
+EFI_FIRMWARE_MANAGEMENT_PROTOCOL *\r
+FindFmpFromImageTypeId (\r
+ IN EFI_GUID *ImageTypeId\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *TargetFmp;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN NumberOfHandles;\r
+ UINTN Index;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;\r
+ UINTN ImageInfoSize;\r
+ UINT32 FmpImageInfoDescriptorVer;\r
+ UINT8 FmpImageInfoCount;\r
+ UINTN DescriptorSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ NULL,\r
+ &NumberOfHandles,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"FMP protocol - %r\n", EFI_NOT_FOUND);\r
+ return NULL;\r
+ }\r
+\r
+ TargetFmp = NULL;\r
+ for (Index = 0; Index < NumberOfHandles; Index++) {\r
+ Status = gBS->HandleProtocol(\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **)&Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ ImageInfoSize = 0;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ continue;\r
+ }\r
+\r
+ FmpImageInfoBuf = NULL;\r
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ FreePool(HandleBuffer);\r
+ Print(L"Out of resource\n");\r
+ return NULL;\r
+ }\r
+\r
+ PackageVersionName = NULL;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize, // ImageInfoSize\r
+ FmpImageInfoBuf, // ImageInfo\r
+ &FmpImageInfoDescriptorVer, // DescriptorVersion\r
+ &FmpImageInfoCount, // DescriptorCount\r
+ &DescriptorSize, // DescriptorSize\r
+ &PackageVersion, // PackageVersion\r
+ &PackageVersionName // PackageVersionName\r
+ );\r
+\r
+ //\r
+ // If FMP GetInformation interface failed, skip this resource\r
+ //\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool(FmpImageInfoBuf);\r
+ continue;\r
+ }\r
+\r
+ if (PackageVersionName != NULL) {\r
+ FreePool(PackageVersionName);\r
+ }\r
+\r
+ if (IsThisFmpImageInfo (FmpImageInfoBuf, FmpImageInfoCount, DescriptorSize, ImageTypeId)) {\r
+ TargetFmp = Fmp;\r
+ }\r
+ FreePool(FmpImageInfoBuf);\r
+ if (TargetFmp != NULL) {\r
+ break;\r
+ }\r
+ }\r
+ FreePool(HandleBuffer);\r
+ return TargetFmp;\r
+}\r
+\r
+/**\r
+ Dump FMP image data.\r
+\r
+ @param[in] ImageTypeId The ImageTypeId of the FMP image.\r
+ It is used to identify the FMP protocol.\r
+ @param[in] ImageIndex The ImageIndex of the FMP image.\r
+ It is the input parameter for FMP->GetImage().\r
+ @param[in] ImageName The file name to hold the output FMP image.\r
+**/\r
+VOID\r
+DumpFmpImage (\r
+ IN EFI_GUID *ImageTypeId,\r
+ IN UINTN ImageIndex,\r
+ IN CHAR16 *ImageName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ VOID *Image;\r
+ UINTN ImageSize;\r
+\r
+ Fmp = FindFmpFromImageTypeId (ImageTypeId);\r
+ if (Fmp == NULL) {\r
+ Print(L"No FMP include ImageTypeId %g\n", ImageTypeId);\r
+ return ;\r
+ }\r
+\r
+ if (ImageIndex > 0xFF) {\r
+ Print(L"ImageIndex 0x%x too big\n", ImageIndex);\r
+ return ;\r
+ }\r
+\r
+ Image = Fmp;\r
+ ImageSize = 0;\r
+ Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize);\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ Print(L"Fmp->GetImage - %r\n", Status);\r
+ return ;\r
+ }\r
+\r
+ Image = AllocatePool (ImageSize);\r
+ if (Image == NULL) {\r
+ Print(L"Allocate FmpImage 0x%x - %r\n", ImageSize, EFI_OUT_OF_RESOURCES);\r
+ return ;\r
+ }\r
+\r
+ Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize);\r
+ if (EFI_ERROR(Status)) {\r
+ Print(L"Fmp->GetImage - %r\n", Status);\r
+ return ;\r
+ }\r
+\r
+ Status = WriteFileFromBuffer(ImageName, ImageSize, Image);\r
+ Print(L"CapsuleApp: Dump %g ImageIndex (0x%x) to %s %r\n", ImageTypeId, ImageIndex, ImageName, Status);\r
+\r
+ FreePool (Image);\r
+\r
+ return ;\r
+}\r