/** @file\r
Dump Capsule image information.\r
\r
- Copyright (c) 2016 - 2018, 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 - 2020, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
-#include <PiDxe.h>\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/UefiBootServicesTableLib.h>\r
-#include <Library/UefiRuntimeServicesTableLib.h>\r
-#include <Library/UefiLib.h>\r
-#include <Library/PrintLib.h>\r
-#include <Protocol/FirmwareManagement.h>\r
-#include <Guid/ImageAuthentication.h>\r
-#include <Guid/CapsuleReport.h>\r
-#include <Guid/SystemResourceTable.h>\r
-#include <Guid/FmpCapsule.h>\r
-#include <IndustryStandard/WindowsUxCapsule.h>\r
+#include "CapsuleApp.h"\r
\r
/**\r
- Read a file.\r
-\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
+ Validate if it is valid capsule header\r
\r
- @retval EFI_SUCCESS Read file successfully\r
- @retval EFI_NOT_FOUND File not found\r
-**/\r
-EFI_STATUS\r
-ReadFileToBuffer (\r
- IN CHAR16 *FileName,\r
- OUT UINTN *BufferSize,\r
- OUT VOID **Buffer\r
- );\r
+ This function assumes the caller provided correct CapsuleHeader pointer\r
+ and CapsuleSize.\r
\r
-/**\r
- Write a file.\r
+ This function validates the fields in EFI_CAPSULE_HEADER.\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
+ @param[in] CapsuleHeader Points to a capsule header.\r
+ @param[in] CapsuleSize Size of the whole capsule image.\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
+BOOLEAN\r
+IsValidCapsuleHeader (\r
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
+ IN UINT64 CapsuleSize\r
);\r
\r
/**\r
{\r
EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader;\r
- Print(L"[UxCapusule]\n");\r
+ Print(L"[UxCapsule]\n");\r
Print(L"CapsuleHeader:\n");\r
Print(L" CapsuleGuid - %g\n", &DisplayCapsule->CapsuleHeader.CapsuleGuid);\r
Print(L" HeaderSize - 0x%x\n", DisplayCapsule->CapsuleHeader.HeaderSize);\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
Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateImageIndex);\r
Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateImageSize);\r
Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize);\r
- if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ if (FmpImageHeader->Version >= 2) {\r
Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance);\r
+ if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r
+ Print(L" ImageCapsuleSupport - 0x%lx\n", FmpImageHeader->ImageCapsuleSupport);\r
+ }\r
}\r
}\r
}\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
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
DumpFmpCapsule(CapsuleHeader);\r
}\r
if (IsNestedFmpCapsule(CapsuleHeader)) {\r
- Print(L"[NestedCapusule]\n");\r
+ Print(L"[NestedCapsule]\n");\r
Print(L"CapsuleHeader:\n");\r
Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid);\r
Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize);\r
@retval EFI_UNSUPPORTED Input parameter is not valid.\r
**/\r
EFI_STATUS\r
-DmpCapsuleStatusVariable (\r
+DumpCapsuleStatusVariable (\r
VOID\r
)\r
{\r
"Error: Auth Error",\r
"Error: Power Event AC",\r
"Error: Power Event Battery",\r
+ "Error: Unsatisfied Dependencies",\r
};\r
\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
+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
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\r
+ do {\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
+ Status = FileHandleFindFirstFile (DirHandle, &FileInfo);\r
+ do {\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
{\r
EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;\r
UINTN Index;\r
+ UINTN Index2;\r
\r
Print(L" DescriptorVersion - 0x%x\n", DescriptorVersion);\r
Print(L" DescriptorCount - 0x%x\n", DescriptorCount);\r
Print(L" LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion);\r
Print(L" LastAttemptStatus - 0x%x (%a)\n", CurrentImageInfo->LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus));\r
Print(L" HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance);\r
+ if (DescriptorVersion > 3) {\r
+ Print(L" Dependencies - ");\r
+ if (CurrentImageInfo->Dependencies == NULL) {\r
+ Print(L"NULL\n");\r
+ } else {\r
+ Index2 = 0;\r
+ do {\r
+ Print(L"%02x ", CurrentImageInfo->Dependencies->Dependencies[Index2]);\r
+ } while (CurrentImageInfo->Dependencies->Dependencies[Index2 ++] != EFI_FMP_DEP_END);\r
+ Print(L"\n");\r
+ }\r
+ }\r
}\r
}\r
//\r