/** @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 | |
EFIAPI | |
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; | |
} |