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