diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c | 1444 |
1 files changed, 1444 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c new file mode 100644 index 00000000..0f8ddbb7 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Application/CapsuleApp/CapsuleDump.c @@ -0,0 +1,1444 @@ +/** @file + Dump Capsule image information. + + Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "CapsuleApp.h" + +/** + Validate if it is valid capsule header + + This function assumes the caller provided correct CapsuleHeader pointer + and CapsuleSize. + + This function validates the fields in EFI_CAPSULE_HEADER. + + @param[in] CapsuleHeader Points to a capsule header. + @param[in] CapsuleSize Size of the whole capsule image. + +**/ +BOOLEAN +IsValidCapsuleHeader ( + IN EFI_CAPSULE_HEADER *CapsuleHeader, + IN UINT64 CapsuleSize + ); + +/** + Dump UX capsule information. + + @param[in] CapsuleHeader The UX capsule header +**/ +VOID +DumpUxCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_DISPLAY_CAPSULE *DisplayCapsule; + DisplayCapsule = (EFI_DISPLAY_CAPSULE *)CapsuleHeader; + Print(L"[UxCapsule]\n"); + Print(L"CapsuleHeader:\n"); + Print(L" CapsuleGuid - %g\n", &DisplayCapsule->CapsuleHeader.CapsuleGuid); + Print(L" HeaderSize - 0x%x\n", DisplayCapsule->CapsuleHeader.HeaderSize); + Print(L" Flags - 0x%x\n", DisplayCapsule->CapsuleHeader.Flags); + Print(L" CapsuleImageSize - 0x%x\n", DisplayCapsule->CapsuleHeader.CapsuleImageSize); + Print(L"ImagePayload:\n"); + Print(L" Version - 0x%x\n", DisplayCapsule->ImagePayload.Version); + Print(L" Checksum - 0x%x\n", DisplayCapsule->ImagePayload.Checksum); + Print(L" ImageType - 0x%x\n", DisplayCapsule->ImagePayload.ImageType); + Print(L" Mode - 0x%x\n", DisplayCapsule->ImagePayload.Mode); + Print(L" OffsetX - 0x%x\n", DisplayCapsule->ImagePayload.OffsetX); + Print(L" OffsetY - 0x%x\n", DisplayCapsule->ImagePayload.OffsetY); +} + + +/** + Dump a non-nested FMP capsule. + + @param[in] CapsuleHeader A pointer to CapsuleHeader +**/ +VOID +DumpFmpCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader; + UINT64 *ItemOffsetList; + UINTN Index; + UINTN Count; + EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader; + + Print(L"[FmpCapsule]\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); + + FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize); + ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1); + Print(L"FmpHeader:\n"); + Print(L" Version - 0x%x\n", FmpCapsuleHeader->Version); + Print(L" EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount); + Print(L" PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount); + Count = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; + for (Index = 0; Index < Count; Index++) { + Print(L" Offset[%d] - 0x%x\n", Index, ItemOffsetList[Index]); + } + + for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < Count; Index++) { + Print(L"FmpPayload[%d] ImageHeader:\n", Index); + FmpImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]); + Print(L" Version - 0x%x\n", FmpImageHeader->Version); + Print(L" UpdateImageTypeId - %g\n", &FmpImageHeader->UpdateImageTypeId); + Print(L" UpdateImageIndex - 0x%x\n", FmpImageHeader->UpdateImageIndex); + Print(L" UpdateImageSize - 0x%x\n", FmpImageHeader->UpdateImageSize); + Print(L" UpdateVendorCodeSize - 0x%x\n", FmpImageHeader->UpdateVendorCodeSize); + if (FmpImageHeader->Version >= 2) { + Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance); + if (FmpImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { + Print(L" ImageCapsuleSupport - 0x%lx\n", FmpImageHeader->ImageCapsuleSupport); + } + } + } +} + +/** + Return if there is a FMP header below capsule header. + + @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER + + @retval TRUE There is a FMP header below capsule header. + @retval FALSE There is not a FMP header below capsule header +**/ +BOOLEAN +IsNestedFmpCapsule ( + IN EFI_CAPSULE_HEADER *CapsuleHeader + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_TABLE *Esrt; + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; + UINTN Index; + BOOLEAN EsrtGuidFound; + EFI_CAPSULE_HEADER *NestedCapsuleHeader; + UINTN NestedCapsuleSize; + + // + // Check ESRT + // + EsrtGuidFound = FALSE; + Status = EfiGetSystemConfigurationTable(&gEfiSystemResourceTableGuid, (VOID **)&Esrt); + if (!EFI_ERROR(Status)) { + ASSERT (Esrt != NULL); + EsrtEntry = (VOID *)(Esrt + 1); + for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) { + if (CompareGuid(&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) { + EsrtGuidFound = TRUE; + break; + } + } + } + + if (!EsrtGuidFound) { + return FALSE; + } + + // + // Check nested capsule header + // FMP GUID after ESRT one + // + NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize); + NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize- (UINTN)NestedCapsuleHeader; + if (NestedCapsuleSize < sizeof(EFI_CAPSULE_HEADER)) { + return FALSE; + } + if (!CompareGuid(&NestedCapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + return FALSE; + } + return TRUE; +} + +/** + Dump capsule information + + @param[in] CapsuleName The name of the capsule image. + + @retval EFI_SUCCESS The capsule information is dumped. + @retval EFI_UNSUPPORTED Input parameter is not valid. +**/ +EFI_STATUS +DumpCapsule ( + IN CHAR16 *CapsuleName + ) +{ + VOID *Buffer; + UINTN FileSize; + EFI_CAPSULE_HEADER *CapsuleHeader; + EFI_STATUS Status; + + Buffer = NULL; + Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer); + if (EFI_ERROR(Status)) { + Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName); + goto Done; + } + if (!IsValidCapsuleHeader (Buffer, FileSize)) { + Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + CapsuleHeader = Buffer; + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) { + DumpUxCapsule(CapsuleHeader); + Status = EFI_SUCCESS; + goto Done; + } + + if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + DumpFmpCapsule(CapsuleHeader); + } + if (IsNestedFmpCapsule(CapsuleHeader)) { + Print(L"[NestedCapsule]\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)); + } + +Done: + if (Buffer != NULL) { + FreePool(Buffer); + } + return Status; +} + +/** + Dump capsule status variable. + + @retval EFI_SUCCESS The capsule status variable is dumped. + @retval EFI_UNSUPPORTED Input parameter is not valid. +**/ +EFI_STATUS +DumpCapsuleStatusVariable ( + VOID + ) +{ + EFI_STATUS Status; + UINT32 Index; + CHAR16 CapsuleVarName[20]; + CHAR16 *TempVarName; + EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResult; + EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultFmp; + UINTN CapsuleFileNameSize; + CHAR16 CapsuleIndexData[12]; + CHAR16 *CapsuleIndex; + CHAR16 *CapsuleFileName; + CHAR16 *CapsuleTarget; + + Status = GetVariable2( + L"CapsuleMax", + &gEfiCapsuleReportGuid, + (VOID **)&CapsuleIndex, + NULL + ); + if (!EFI_ERROR(Status)) { + ASSERT (CapsuleIndex != NULL); + CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16)); + CapsuleIndexData[11] = 0; + Print(L"CapsuleMax - %s\n", CapsuleIndexData); + FreePool(CapsuleIndex); + } + Status = GetVariable2( + L"CapsuleLast", + &gEfiCapsuleReportGuid, + (VOID **)&CapsuleIndex, + NULL + ); + if (!EFI_ERROR(Status)) { + ASSERT (CapsuleIndex != NULL); + CopyMem(CapsuleIndexData, CapsuleIndex, 11 * sizeof(CHAR16)); + CapsuleIndexData[11] = 0; + Print(L"CapsuleLast - %s\n", CapsuleIndexData); + FreePool(CapsuleIndex); + } + + + StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), L"Capsule"); + TempVarName = CapsuleVarName + StrLen (CapsuleVarName); + Index = 0; + + while (TRUE) { + UnicodeSPrint (TempVarName, 5 * sizeof(CHAR16), L"%04x", Index); + + Status = GetVariable2 ( + CapsuleVarName, + &gEfiCapsuleReportGuid, + (VOID **) &CapsuleResult, + NULL + ); + if (Status == EFI_NOT_FOUND) { + break; + } else if (EFI_ERROR(Status)) { + continue; + } + ASSERT (CapsuleResult != NULL); + + // + // display capsule process status + // + if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER)) { + Print (L"CapsuleName: %s\n", CapsuleVarName); + Print (L" Capsule Guid: %g\n", &CapsuleResult->CapsuleGuid); + Print (L" Capsule ProcessedTime: %t\n", &CapsuleResult->CapsuleProcessed); + Print (L" Capsule Status: %r\n", CapsuleResult->CapsuleStatus); + } + + if (CompareGuid(&CapsuleResult->CapsuleGuid, &gEfiFmpCapsuleGuid)) { + if (CapsuleResult->VariableTotalSize >= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + sizeof(CHAR16) * 2) { + CapsuleResultFmp = (EFI_CAPSULE_RESULT_VARIABLE_FMP *)(CapsuleResult + 1); + Print(L" Capsule FMP Version: 0x%x\n", CapsuleResultFmp->Version); + Print(L" Capsule FMP PayloadIndex: 0x%x\n", CapsuleResultFmp->PayloadIndex); + Print(L" Capsule FMP UpdateImageIndex: 0x%x\n", CapsuleResultFmp->UpdateImageIndex); + Print(L" Capsule FMP UpdateImageTypeId: %g\n", &CapsuleResultFmp->UpdateImageTypeId); + CapsuleFileName = (CHAR16 *)(CapsuleResultFmp + 1); + Print(L" Capsule FMP CapsuleFileName: \"%s\"\n", CapsuleFileName); + CapsuleFileNameSize = StrSize(CapsuleFileName); + CapsuleTarget = (CHAR16 *)((UINTN)CapsuleFileName + CapsuleFileNameSize); + Print(L" Capsule FMP CapsuleTarget: \"%s\"\n", CapsuleTarget); + } + } + + FreePool(CapsuleResult); + + Index++; + if (Index > 0xFFFF) { + break; + } + } + + return EFI_SUCCESS; +} + +CHAR8 *mFwTypeString[] = { + "Unknown", + "SystemFirmware", + "DeviceFirmware", + "UefiDriver", +}; + +CHAR8 *mLastAttemptStatusString[] = { + "Success", + "Error: Unsuccessful", + "Error: Insufficient Resources", + "Error: Incorrect Version", + "Error: Invalid Format", + "Error: Auth Error", + "Error: Power Event AC", + "Error: Power Event Battery", + "Error: Unsatisfied Dependencies", +}; + +/** + Convert FwType to a string. + + @param[in] FwType FwType in ESRT + + @return a string for FwType. +**/ +CHAR8 * +FwTypeToString ( + IN UINT32 FwType + ) +{ + if (FwType < sizeof(mFwTypeString) / sizeof(mFwTypeString[0])) { + return mFwTypeString[FwType]; + } else { + return "Invalid"; + } +} + +/** + Convert LastAttemptStatus to a string. + + @param[in] LastAttemptStatus LastAttemptStatus in FMP or ESRT + + @return a string for LastAttemptStatus. +**/ +CHAR8 * +LastAttemptStatusToString ( + IN UINT32 LastAttemptStatus + ) +{ + if (LastAttemptStatus < sizeof(mLastAttemptStatusString) / sizeof(mLastAttemptStatusString[0])) { + return mLastAttemptStatusString[LastAttemptStatus]; + } else { + return "Error: Unknown"; + } +} + +/** + Dump ESRT entry. + + @param[in] EsrtEntry ESRT entry +**/ +VOID +DumpEsrtEntry ( + IN EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry + ) +{ + Print(L" FwClass - %g\n", &EsrtEntry->FwClass); + Print(L" FwType - 0x%x (%a)\n", EsrtEntry->FwType, FwTypeToString(EsrtEntry->FwType)); + Print(L" FwVersion - 0x%x\n", EsrtEntry->FwVersion); + Print(L" LowestSupportedFwVersion - 0x%x\n", EsrtEntry->LowestSupportedFwVersion); + Print(L" CapsuleFlags - 0x%x\n", EsrtEntry->CapsuleFlags); + Print(L" LastAttemptVersion - 0x%x\n", EsrtEntry->LastAttemptVersion); + Print(L" LastAttemptStatus - 0x%x (%a)\n", EsrtEntry->LastAttemptStatus, LastAttemptStatusToString(EsrtEntry->LastAttemptStatus)); +} + +/** + Dump ESRT table. + + @param[in] Esrt ESRT table +**/ +VOID +DumpEsrt ( + IN EFI_SYSTEM_RESOURCE_TABLE *Esrt + ) +{ + UINTN Index; + EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry; + + if (Esrt == NULL) { + return ; + } + + Print(L"EFI_SYSTEM_RESOURCE_TABLE:\n"); + Print(L"FwResourceCount - 0x%x\n", Esrt->FwResourceCount); + Print(L"FwResourceCountMax - 0x%x\n", Esrt->FwResourceCountMax); + Print(L"FwResourceVersion - 0x%lx\n", Esrt->FwResourceVersion); + + EsrtEntry = (VOID *)(Esrt + 1); + for (Index = 0; Index < Esrt->FwResourceCount; Index++) { + Print(L"EFI_SYSTEM_RESOURCE_ENTRY (%d):\n", Index); + DumpEsrtEntry(EsrtEntry); + EsrtEntry++; + } +} + +/** + Dump ESRT info. +**/ +VOID +DumpEsrtData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_SYSTEM_RESOURCE_TABLE *Esrt; + + Print(L"##############\n"); + Print(L"# ESRT TABLE #\n"); + Print(L"##############\n"); + + Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt); + if (EFI_ERROR(Status)) { + Print(L"ESRT - %r\n", Status); + return; + } + DumpEsrt(Esrt); + 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 != L'\0'; 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 +CompareFileNameInAlphabet ( + IN VOID *Left, + IN VOID *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 *) (*(UINTN *)Left); + FileInfo2 = (EFI_FILE_INFO *) (*(UINTN *)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] Fs 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; + FileInfoBuffer = NULL; + FileInfo = NULL; + FileCount = 0; + NoFile = FALSE; + + Status = Fs->OpenVolume (Fs, &Root); + if (EFI_ERROR (Status)) { + Print (L"Cannot open volume. Status = %r\n", Status); + goto Done; + } + + Status = Root->Open (Root, &DirHandle, EFI_CAPSULE_FILE_DIRECTORY, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE , 0); + if (EFI_ERROR (Status)) { + Print (L"Cannot open %s. Status = %r\n", EFI_CAPSULE_FILE_DIRECTORY, Status); + goto Done; + } + + // + // Get file count first + // + Status = FileHandleFindFirstFile (DirHandle, &FileInfo); + do { + if (EFI_ERROR (Status) || FileInfo == NULL) { + Print (L"Get File Info Fail. Status = %r\n", Status); + goto Done; + } + + if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) { + FileCount++; + } + + Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile); + if (EFI_ERROR (Status)) { + Print (L"Get Next File Fail. Status = %r\n", Status); + goto Done; + } + } while (!NoFile); + + if (FileCount == 0) { + Print (L"Error: No capsule file found!\n"); + Status = EFI_NOT_FOUND; + goto Done; + } + + FileInfoBuffer = AllocateZeroPool (sizeof (FileInfo) * FileCount); + if (FileInfoBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + NoFile = FALSE; + + // + // Get all file info + // + Status = FileHandleFindFirstFile (DirHandle, &FileInfo); + do { + if (EFI_ERROR (Status) || FileInfo == NULL) { + Print (L"Get File Info Fail. Status = %r\n", Status); + goto Done; + } + + if ((FileInfo->Attribute & (EFI_FILE_SYSTEM | EFI_FILE_ARCHIVE)) != 0) { + FileInfoBuffer[Index++] = AllocateCopyPool ((UINTN)FileInfo->Size, FileInfo); + } + + Status = FileHandleFindNextFile (DirHandle, FileInfo, &NoFile); + if (EFI_ERROR (Status)) { + Print (L"Get Next File Fail. Status = %r\n", Status); + goto Done; + } + } while (!NoFile); + + // + // 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) { + Status = EFI_SUCCESS; + goto Done; + } + + 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)) { + goto Done; + } + + Status = FileHandleGetSize (FileHandle, (UINT64 *) &FileSize); + if (EFI_ERROR (Status)) { + Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status); + FileHandleClose (FileHandle); + goto Done; + } + + FileBuffer = AllocatePool (FileSize); + if (FileBuffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + Status = FileHandleRead (FileHandle, &FileSize, FileBuffer); + if (EFI_ERROR (Status)) { + Print (L"Cannot read file %s. Status = %r\n", FileInfoBuffer[Index]->FileName, Status); + FileHandleClose (FileHandle); + FreePool (FileBuffer); + goto Done; + } + + 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); + } + +Done: + if (FileInfoBuffer != NULL) { + for (Index = 0; Index < FileCount; Index++) { + if (FileInfoBuffer[Index] != NULL) { + FreePool (FileInfoBuffer[Index]); + } + } + FreePool (FileInfoBuffer); + } + + return Status; +} + +/** + 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; + + Index = 0; + CapsuleDataPtr64 = NULL; + BootNext = NULL; + + ShellProtocol = GetShellProtocol (); + if (ShellProtocol == NULL) { + Print (L"Get Shell Protocol Fail\n"); + return ; + } + + // + // 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) || CapsuleDataPtr64 == NULL) { + if (Index == 0) { + Print (L"No data.\n"); + } + break; + } + + 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) || BootNext == NULL) { + Print (L"Get BootNext Variable Fail. Status = %r\n", Status); + } else { + 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. + + @param[in] ImageInfoSize The size of ImageInfo, in bytes. + @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes. + @param[in] PackageVersion The version of package. + @param[in] PackageVersionName The version name of package. +**/ +VOID +DumpFmpImageInfo ( + IN UINTN ImageInfoSize, + IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + IN UINT32 DescriptorVersion, + IN UINT8 DescriptorCount, + IN UINTN DescriptorSize, + IN UINT32 PackageVersion, + IN CHAR16 *PackageVersionName + ) +{ + EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo; + UINTN Index; + UINTN Index2; + + Print(L" DescriptorVersion - 0x%x\n", DescriptorVersion); + Print(L" DescriptorCount - 0x%x\n", DescriptorCount); + Print(L" DescriptorSize - 0x%x\n", DescriptorSize); + Print(L" PackageVersion - 0x%x\n", PackageVersion); + Print(L" PackageVersionName - \"%s\"\n", PackageVersionName); + CurrentImageInfo = ImageInfo; + for (Index = 0; Index < DescriptorCount; Index++) { + Print(L" ImageDescriptor (%d)\n", Index); + Print(L" ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex); + Print(L" ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId); + Print(L" ImageId - 0x%lx\n", CurrentImageInfo->ImageId); + Print(L" ImageIdName - \"%s\"\n", CurrentImageInfo->ImageIdName); + Print(L" Version - 0x%x\n", CurrentImageInfo->Version); + Print(L" VersionName - \"%s\"\n", CurrentImageInfo->VersionName); + Print(L" Size - 0x%x\n", CurrentImageInfo->Size); + Print(L" AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_IN_USE); + Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSupported & IMAGE_ATTRIBUTE_UEFI_IMAGE); + Print(L" AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Print(L" IN_USE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_IN_USE); + Print(L" UEFI_IMAGE - 0x%lx\n", CurrentImageInfo->AttributesSetting & IMAGE_ATTRIBUTE_UEFI_IMAGE); + Print(L" Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities); + Print(L" COMPATIB_CHECK_SUPPORTED - 0x%lx\n", CurrentImageInfo->Compatibilities & IMAGE_COMPATIBILITY_CHECK_SUPPORTED); + if (DescriptorVersion > 1) { + Print(L" LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion); + if (DescriptorVersion > 2) { + Print(L" LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion); + Print(L" LastAttemptStatus - 0x%x (%a)\n", CurrentImageInfo->LastAttemptStatus, LastAttemptStatusToString(CurrentImageInfo->LastAttemptStatus)); + Print(L" HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance); + if (DescriptorVersion > 3) { + Print(L" Dependencies - "); + if (CurrentImageInfo->Dependencies == NULL) { + Print(L"NULL\n"); + } else { + Index2 = 0; + do { + Print(L"%02x ", CurrentImageInfo->Dependencies->Dependencies[Index2]); + } while (CurrentImageInfo->Dependencies->Dependencies[Index2 ++] != EFI_FMP_DEP_END); + Print(L"\n"); + } + } + } + } + // + // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version + // + CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize); + } +} + +/** + Dump FMP package information. + + @param[in] PackageVersion The version of package. + @param[in] PackageVersionName The version name of package. + @param[in] PackageVersionNameMaxLen The maximum length of PackageVersionName. + @param[in] AttributesSupported Package attributes that are supported by this device. + @param[in] AttributesSetting Package attributes. +**/ +VOID +DumpFmpPackageInfo ( + IN UINT32 PackageVersion, + IN CHAR16 *PackageVersionName, + IN UINT32 PackageVersionNameMaxLen, + IN UINT64 AttributesSupported, + IN UINT64 AttributesSetting + ) +{ + Print(L" PackageVersion - 0x%x\n", PackageVersion); + Print(L" PackageVersionName - \"%s\"\n", PackageVersionName); + Print(L" PackageVersionNameMaxLen - 0x%x\n", PackageVersionNameMaxLen); + Print(L" AttributesSupported - 0x%lx\n", AttributesSupported); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSupported & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); + Print(L" AttributesSetting - 0x%lx\n", AttributesSetting); + Print(L" IMAGE_UPDATABLE - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_IMAGE_UPDATABLE); + Print(L" RESET_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_RESET_REQUIRED); + Print(L" AUTHENTICATION_REQUIRED - 0x%lx\n", AttributesSetting & IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED); +} + +/** + Dump FMP protocol info. +**/ +VOID +DumpFmpData ( + VOID + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINTN Index; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINTN ImageInfoSize; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + UINT32 PackageVersionNameMaxLen; + UINT64 AttributesSupported; + UINT64 AttributesSetting; + + Print(L"############\n"); + Print(L"# FMP DATA #\n"); + Print(L"############\n"); + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + Print(L"FMP protocol - %r\n", EFI_NOT_FOUND); + return; + } + + for (Index = 0; Index < NumberOfHandles; Index++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index], + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + continue; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto EXIT; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // If FMP GetInformation interface failed, skip this resource + // + if (EFI_ERROR(Status)) { + Print(L"FMP (%d) ImageInfo - %r\n", Index, Status); + FreePool(FmpImageInfoBuf); + continue; + } + + Print(L"FMP (%d) ImageInfo:\n", Index); + DumpFmpImageInfo( + ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + FmpImageInfoDescriptorVer, // DescriptorVersion + FmpImageInfoCount, // DescriptorCount + DescriptorSize, // DescriptorSize + PackageVersion, // PackageVersion + PackageVersionName // PackageVersionName + ); + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + FreePool(FmpImageInfoBuf); + + // + // Get package info + // + PackageVersionName = NULL; + Status = Fmp->GetPackageInfo ( + Fmp, + &PackageVersion, // PackageVersion + &PackageVersionName, // PackageVersionName + &PackageVersionNameMaxLen, // PackageVersionNameMaxLen + &AttributesSupported, // AttributesSupported + &AttributesSetting // AttributesSetting + ); + if (EFI_ERROR(Status)) { + Print(L"FMP (%d) PackageInfo - %r\n", Index, Status); + } else { + Print(L"FMP (%d) ImageInfo:\n", Index); + DumpFmpPackageInfo( + PackageVersion, // PackageVersion + PackageVersionName, // PackageVersionName + PackageVersionNameMaxLen, // PackageVersionNameMaxLen + AttributesSupported, // AttributesSupported + AttributesSetting // AttributesSetting + ); + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + } + } + Print(L"\n"); + +EXIT: + FreePool(HandleBuffer); +} + +/** + Check if the ImageInfo includes the ImageTypeId. + + @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR. + @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes. + @param[in] ImageTypeId A unique GUID identifying the firmware image type. + + @return TRUE This ImageInfo includes the ImageTypeId + @return FALSE This ImageInfo does not include the ImageTypeId +**/ +BOOLEAN +IsThisFmpImageInfo ( + IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo, + IN UINT8 DescriptorCount, + IN UINTN DescriptorSize, + IN EFI_GUID *ImageTypeId + ) +{ + EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo; + UINTN Index; + + CurrentImageInfo = ImageInfo; + for (Index = 0; Index < DescriptorCount; Index++) { + if (CompareGuid (&CurrentImageInfo->ImageTypeId, ImageTypeId)) { + return TRUE; + } + CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize); + } + return FALSE; +} + +/** + return the FMP whoes ImageInfo includes the ImageTypeId. + + @param[in] ImageTypeId A unique GUID identifying the firmware image type. + + @return The FMP whoes ImageInfo includes the ImageTypeId +**/ +EFI_FIRMWARE_MANAGEMENT_PROTOCOL * +FindFmpFromImageTypeId ( + IN EFI_GUID *ImageTypeId + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *TargetFmp; + EFI_HANDLE *HandleBuffer; + UINTN NumberOfHandles; + UINTN Index; + EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf; + UINTN ImageInfoSize; + UINT32 FmpImageInfoDescriptorVer; + UINT8 FmpImageInfoCount; + UINTN DescriptorSize; + UINT32 PackageVersion; + CHAR16 *PackageVersionName; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiFirmwareManagementProtocolGuid, + NULL, + &NumberOfHandles, + &HandleBuffer + ); + if (EFI_ERROR(Status)) { + Print(L"FMP protocol - %r\n", EFI_NOT_FOUND); + return NULL; + } + + TargetFmp = NULL; + for (Index = 0; Index < NumberOfHandles; Index++) { + Status = gBS->HandleProtocol( + HandleBuffer[Index], + &gEfiFirmwareManagementProtocolGuid, + (VOID **)&Fmp + ); + if (EFI_ERROR(Status)) { + continue; + } + + ImageInfoSize = 0; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + continue; + } + + FmpImageInfoBuf = NULL; + FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize); + if (FmpImageInfoBuf == NULL) { + FreePool(HandleBuffer); + Print(L"Out of resource\n"); + return NULL; + } + + PackageVersionName = NULL; + Status = Fmp->GetImageInfo ( + Fmp, + &ImageInfoSize, // ImageInfoSize + FmpImageInfoBuf, // ImageInfo + &FmpImageInfoDescriptorVer, // DescriptorVersion + &FmpImageInfoCount, // DescriptorCount + &DescriptorSize, // DescriptorSize + &PackageVersion, // PackageVersion + &PackageVersionName // PackageVersionName + ); + + // + // If FMP GetInformation interface failed, skip this resource + // + if (EFI_ERROR(Status)) { + FreePool(FmpImageInfoBuf); + continue; + } + + if (PackageVersionName != NULL) { + FreePool(PackageVersionName); + } + + if (IsThisFmpImageInfo (FmpImageInfoBuf, FmpImageInfoCount, DescriptorSize, ImageTypeId)) { + TargetFmp = Fmp; + } + FreePool(FmpImageInfoBuf); + if (TargetFmp != NULL) { + break; + } + } + FreePool(HandleBuffer); + return TargetFmp; +} + +/** + Dump FMP image data. + + @param[in] ImageTypeId The ImageTypeId of the FMP image. + It is used to identify the FMP protocol. + @param[in] ImageIndex The ImageIndex of the FMP image. + It is the input parameter for FMP->GetImage(). + @param[in] ImageName The file name to hold the output FMP image. +**/ +VOID +DumpFmpImage ( + IN EFI_GUID *ImageTypeId, + IN UINTN ImageIndex, + IN CHAR16 *ImageName + ) +{ + EFI_STATUS Status; + EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; + VOID *Image; + UINTN ImageSize; + + Fmp = FindFmpFromImageTypeId (ImageTypeId); + if (Fmp == NULL) { + Print(L"No FMP include ImageTypeId %g\n", ImageTypeId); + return ; + } + + if (ImageIndex > 0xFF) { + Print(L"ImageIndex 0x%x too big\n", ImageIndex); + return ; + } + + Image = Fmp; + ImageSize = 0; + Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize); + if (Status != EFI_BUFFER_TOO_SMALL) { + Print(L"Fmp->GetImage - %r\n", Status); + return ; + } + + Image = AllocatePool (ImageSize); + if (Image == NULL) { + Print(L"Allocate FmpImage 0x%x - %r\n", ImageSize, EFI_OUT_OF_RESOURCES); + return ; + } + + Status = Fmp->GetImage (Fmp, (UINT8)ImageIndex, Image, &ImageSize); + if (EFI_ERROR(Status)) { + Print(L"Fmp->GetImage - %r\n", Status); + return ; + } + + Status = WriteFileFromBuffer(ImageName, ImageSize, Image); + Print(L"CapsuleApp: Dump %g ImageIndex (0x%x) to %s %r\n", ImageTypeId, ImageIndex, ImageName, Status); + + FreePool (Image); + + return ; +} |