/** @file Dump Capsule image information. Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.
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"[UxCapusule]\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 >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) { Print(L" UpdateHardwareInstance - 0x%lx\n", FmpImageHeader->UpdateHardwareInstance); } } } /** 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"[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)); } 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", }; /** 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; 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); } } // // 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 ; }