summaryrefslogtreecommitdiff
path: root/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c')
-rw-r--r--MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c3382
1 files changed, 1691 insertions, 1691 deletions
diff --git a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
index 2433c76a8c..c17231d8b1 100644
--- a/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
+++ b/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c
@@ -1,1691 +1,1691 @@
-/** @file
- DXE capsule library.
-
- Caution: This module requires additional review when modified.
- This module will have external input - capsule image.
- This external input must be validated carefully to avoid security issue like
- buffer overflow, integer overflow.
-
- SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
- ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
- performs basic validation.
-
- Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <PiDxe.h>
-
-#include <IndustryStandard/WindowsUxCapsule.h>
-
-#include <Guid/FmpCapsule.h>
-#include <Guid/SystemResourceTable.h>
-#include <Guid/EventGroup.h>
-
-#include <Library/BaseLib.h>
-#include <Library/DebugLib.h>
-#include <Library/BaseMemoryLib.h>
-#include <Library/DxeServicesTableLib.h>
-#include <Library/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Library/CapsuleLib.h>
-#include <Library/DevicePathLib.h>
-#include <Library/UefiLib.h>
-#include <Library/BmpSupportLib.h>
-
-#include <Protocol/GraphicsOutput.h>
-#include <Protocol/EsrtManagement.h>
-#include <Protocol/FirmwareManagement.h>
-#include <Protocol/FirmwareManagementProgress.h>
-#include <Protocol/DevicePath.h>
-
-EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
-
-BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
-EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
-
-EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
-
-/**
- Initialize capsule related variables.
-**/
-VOID
-InitCapsuleVariable (
- VOID
- );
-
-/**
- Record capsule status variable.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus
- );
-
-/**
- Record FMP capsule status variable.
-
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
- @param[in] PayloadIndex FMP payload index
- @param[in] ImageHeader FMP image header
- @param[in] FmpDevicePath DevicePath associated with the FMP producer
- @param[in] CapFileName Capsule file name
-
- @retval EFI_SUCCESS The capsule status variable is recorded.
- @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
-**/
-EFI_STATUS
-RecordFmpCapsuleStatusVariable (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus,
- IN UINTN PayloadIndex,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
- IN CHAR16 *CapFileName OPTIONAL
- );
-
-/**
- Function indicate the current completion progress of the firmware
- update. Platform may override with own specific progress function.
-
- @param[in] Completion A value between 1 and 100 indicating the current
- completion progress of the firmware update
-
- @retval EFI_SUCESS The capsule update progress was updated.
- @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
-**/
-EFI_STATUS
-EFIAPI
-UpdateImageProgress (
- IN UINTN Completion
- );
-
-/**
- Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
-
- @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
-
- @retval TRUE It is a capsule name capsule.
- @retval FALSE It is not a capsule name capsule.
-**/
-BOOLEAN
-IsCapsuleNameCapsule (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
-}
-
-/**
- Return if this CapsuleGuid is a FMP capsule GUID or not.
-
- @param[in] CapsuleGuid A pointer to EFI_GUID
-
- @retval TRUE It is a FMP capsule GUID.
- @retval FALSE It is not a FMP capsule GUID.
-**/
-BOOLEAN
-IsFmpCapsuleGuid (
- IN EFI_GUID *CapsuleGuid
- )
-{
- if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Validate if it is valid capsule header
-
- Caution: This function may receive untrusted input.
-
- 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
- )
-{
- if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
- return FALSE;
- }
-
- if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-/**
- Validate Fmp capsules layout.
-
- Caution: This function may receive untrusted input.
-
- This function assumes the caller validated the capsule by using
- IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
- The capsule buffer size is CapsuleHeader->CapsuleImageSize.
-
- This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
- and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
-
- This function need support nested FMP capsule.
-
- @param[in] CapsuleHeader Points to a capsule header.
- @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
-
- @retval EFI_SUCESS Input capsule is a correct FMP capsule.
- @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
-**/
-EFI_STATUS
-ValidateFmpCapsule (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- OUT UINT16 *EmbeddedDriverCount OPTIONAL
- )
-{
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
- UINT8 *EndOfCapsule;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
- UINT8 *EndOfPayload;
- UINT64 *ItemOffsetList;
- UINT32 ItemNum;
- UINTN Index;
- UINTN FmpCapsuleSize;
- UINTN FmpCapsuleHeaderSize;
- UINT64 FmpImageSize;
- UINTN FmpImageHeaderSize;
-
- if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
- return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
- }
-
- if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
- DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
- return EFI_INVALID_PARAMETER;
- }
-
- FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
- EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
- FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
-
- if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
- DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
- return EFI_INVALID_PARAMETER;
- }
-
- // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
- if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
- DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
- return EFI_INVALID_PARAMETER;
- }
-
- ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
-
- // No overflow
- ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
-
- if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
- DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
- return EFI_INVALID_PARAMETER;
- }
-
- FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
-
- // Check ItemOffsetList
- for (Index = 0; Index < ItemNum; Index++) {
- if (ItemOffsetList[Index] >= FmpCapsuleSize) {
- DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
- return EFI_INVALID_PARAMETER;
- }
-
- if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
- DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // All the address in ItemOffsetList must be stored in ascending order
- //
- if (Index > 0) {
- if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
- DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
- return EFI_INVALID_PARAMETER;
- }
- }
- }
-
- // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
- for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
- ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
- if (Index == ItemNum - 1) {
- EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
- } else {
- EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
- }
-
- FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
-
- FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
- if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
- (ImageHeader->Version < 1))
- {
- DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
- return EFI_INVALID_PARAMETER;
- }
-
- if (ImageHeader->Version == 1) {
- FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
- } else if (ImageHeader->Version == 2) {
- FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
- }
-
- if (FmpImageSize < FmpImageHeaderSize) {
- DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
- return EFI_INVALID_PARAMETER;
- }
-
- // No overflow
- if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
- DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
- return EFI_INVALID_PARAMETER;
- }
- }
-
- if (ItemNum == 0) {
- //
- // No driver & payload element in FMP
- //
- EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
- if (EndOfPayload != EndOfCapsule) {
- DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_UNSUPPORTED;
- }
-
- if (EmbeddedDriverCount != NULL) {
- *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Those capsules supported by the firmwares.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
-
- @retval EFI_SUCESS Input capsule is supported by firmware.
- @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
-**/
-EFI_STATUS
-DisplayCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
- UINTN PayloadSize;
- EFI_STATUS Status;
- EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
- UINTN BltSize;
- UINTN Height;
- UINTN Width;
- EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
-
- //
- // UX capsule doesn't have extended header entries.
- //
- if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
- return EFI_UNSUPPORTED;
- }
-
- ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize);
- //
- // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
- //
- PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
-
- //
- // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
- // Further size check is performed by the logic translating BMP to GOP BLT.
- //
- if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (ImagePayload->Version != 1) {
- return EFI_UNSUPPORTED;
- }
-
- if (CalculateCheckSum8 ((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Only Support Bitmap by now
- //
- if (ImagePayload->ImageType != 0) {
- return EFI_UNSUPPORTED;
- }
-
- //
- // Try to open GOP
- //
- Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
- if (EFI_ERROR (Status)) {
- Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
- if (EFI_ERROR (Status)) {
- return EFI_UNSUPPORTED;
- }
- }
-
- if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
- return EFI_UNSUPPORTED;
- }
-
- Blt = NULL;
- Width = 0;
- Height = 0;
- Status = TranslateBmpToGopBlt (
- ImagePayload + 1,
- PayloadSize - sizeof (DISPLAY_DISPLAY_PAYLOAD),
- &Blt,
- &BltSize,
- &Height,
- &Width
- );
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = GraphicsOutput->Blt (
- GraphicsOutput,
- Blt,
- EfiBltBufferToVideo,
- 0,
- 0,
- (UINTN)ImagePayload->OffsetX,
- (UINTN)ImagePayload->OffsetY,
- Width,
- Height,
- Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
- );
-
- FreePool (Blt);
-
- return Status;
-}
-
-/**
- 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;
-
- DEBUG ((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
- DEBUG ((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
- DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
- DEBUG ((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
- DEBUG ((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
- CurrentImageInfo = ImageInfo;
- for (Index = 0; Index < DescriptorCount; Index++) {
- DEBUG ((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
- DEBUG ((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
- DEBUG ((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
- DEBUG ((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
- DEBUG ((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
- DEBUG ((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
- DEBUG ((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
- DEBUG ((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
- DEBUG ((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
- DEBUG ((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
- if (DescriptorVersion > 1) {
- DEBUG ((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
- if (DescriptorVersion > 2) {
- DEBUG ((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
- DEBUG ((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
- DEBUG ((DEBUG_VERBOSE, " 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 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;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
- UINTN Index;
- UINT64 *ItemOffsetList;
-
- FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
-
- DEBUG ((DEBUG_VERBOSE, "FmpCapsule:\n"));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
- DEBUG ((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
- DEBUG ((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
-
- ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
- for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
- DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
- }
-
- for ( ; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
- DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
- ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
-
- DEBUG ((DEBUG_VERBOSE, " ImageHeader:\n"));
- DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
- DEBUG ((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
- DEBUG ((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
- DEBUG ((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
- DEBUG ((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
- if (ImageHeader->Version >= 2) {
- DEBUG ((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
- if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
- DEBUG ((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
- }
- }
- }
-}
-
-/**
- Dump all FMP information.
-**/
-VOID
-DumpAllFmpInfo (
- VOID
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE *HandleBuffer;
- UINTN NumberOfHandles;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINTN Index;
- UINTN ImageInfoSize;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
- UINT32 FmpImageInfoDescriptorVer;
- UINT8 FmpImageInfoCount;
- UINTN DescriptorSize;
- UINT32 PackageVersion;
- CHAR16 *PackageVersionName;
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiFirmwareManagementProtocolGuid,
- NULL,
- &NumberOfHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- 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 = AllocateZeroPool (ImageInfoSize);
- if (FmpImageInfoBuf == NULL) {
- continue;
- }
-
- PackageVersionName = NULL;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- &FmpImageInfoDescriptorVer, // DescriptorVersion
- &FmpImageInfoCount, // DescriptorCount
- &DescriptorSize, // DescriptorSize
- &PackageVersion, // PackageVersion
- &PackageVersionName // PackageVersionName
- );
- if (EFI_ERROR (Status)) {
- FreePool (FmpImageInfoBuf);
- continue;
- }
-
- DEBUG ((DEBUG_INFO, "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);
- }
-
- FreePool (HandleBuffer);
-
- return;
-}
-
-/**
- Get FMP handle by ImageTypeId and HardwareInstance.
-
- @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
- @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
- @param[out] NoHandles The number of handles returned in HandleBuf.
- @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
- @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
- the requested array of handles.
-
- @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
- HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
- was returned in NoHandles.
- @retval EFI_NOT_FOUND No handles match the search.
- @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
-**/
-EFI_STATUS
-GetFmpHandleBufferByType (
- IN EFI_GUID *UpdateImageTypeId,
- IN UINT64 UpdateHardwareInstance,
- OUT UINTN *NoHandles OPTIONAL,
- OUT EFI_HANDLE **HandleBuf OPTIONAL,
- OUT BOOLEAN **ResetRequiredBuf OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE *HandleBuffer;
- UINTN NumberOfHandles;
- EFI_HANDLE *MatchedHandleBuffer;
- BOOLEAN *MatchedResetRequiredBuffer;
- UINTN MatchedNumberOfHandles;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINTN Index;
- UINTN ImageInfoSize;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
- UINT32 FmpImageInfoDescriptorVer;
- UINT8 FmpImageInfoCount;
- UINTN DescriptorSize;
- UINT32 PackageVersion;
- CHAR16 *PackageVersionName;
- UINTN Index2;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
-
- if (NoHandles != NULL) {
- *NoHandles = 0;
- }
-
- if (HandleBuf != NULL) {
- *HandleBuf = NULL;
- }
-
- if (ResetRequiredBuf != NULL) {
- *ResetRequiredBuf = NULL;
- }
-
- Status = gBS->LocateHandleBuffer (
- ByProtocol,
- &gEfiFirmwareManagementProtocolGuid,
- NULL,
- &NumberOfHandles,
- &HandleBuffer
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- MatchedNumberOfHandles = 0;
-
- MatchedHandleBuffer = NULL;
- if (HandleBuf != NULL) {
- MatchedHandleBuffer = AllocateZeroPool (sizeof (EFI_HANDLE) * NumberOfHandles);
- if (MatchedHandleBuffer == NULL) {
- FreePool (HandleBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- MatchedResetRequiredBuffer = NULL;
- if (ResetRequiredBuf != NULL) {
- MatchedResetRequiredBuffer = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfHandles);
- if (MatchedResetRequiredBuffer == NULL) {
- if (MatchedHandleBuffer != NULL) {
- FreePool (MatchedHandleBuffer);
- }
-
- FreePool (HandleBuffer);
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- 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 = AllocateZeroPool (ImageInfoSize);
- if (FmpImageInfoBuf == NULL) {
- continue;
- }
-
- PackageVersionName = NULL;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- &FmpImageInfoDescriptorVer, // DescriptorVersion
- &FmpImageInfoCount, // DescriptorCount
- &DescriptorSize, // DescriptorSize
- &PackageVersion, // PackageVersion
- &PackageVersionName // PackageVersionName
- );
- if (EFI_ERROR (Status)) {
- FreePool (FmpImageInfoBuf);
- continue;
- }
-
- if (PackageVersionName != NULL) {
- FreePool (PackageVersionName);
- }
-
- TempFmpImageInfo = FmpImageInfoBuf;
- for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
- //
- // Check if this FMP instance matches
- //
- if (CompareGuid (UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
- if ((UpdateHardwareInstance == 0) ||
- ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
- (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance)))
- {
- if (MatchedHandleBuffer != NULL) {
- MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
- }
-
- if (MatchedResetRequiredBuffer != NULL) {
- MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
- IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
- ((TempFmpImageInfo->AttributesSetting &
- IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
- }
-
- MatchedNumberOfHandles++;
- break;
- }
- }
-
- TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
- }
-
- FreePool (FmpImageInfoBuf);
- }
-
- FreePool (HandleBuffer);
-
- if (MatchedNumberOfHandles == 0) {
- return EFI_NOT_FOUND;
- }
-
- if (NoHandles != NULL) {
- *NoHandles = MatchedNumberOfHandles;
- }
-
- if (HandleBuf != NULL) {
- *HandleBuf = MatchedHandleBuffer;
- }
-
- if (ResetRequiredBuf != NULL) {
- *ResetRequiredBuf = MatchedResetRequiredBuffer;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Return FmpImageInfoDescriptorVer by an FMP handle.
-
- @param[in] Handle A FMP handle.
-
- @return FmpImageInfoDescriptorVer associated with the FMP.
-**/
-UINT32
-GetFmpImageInfoDescriptorVer (
- IN EFI_HANDLE Handle
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINTN ImageInfoSize;
- EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
- UINT32 FmpImageInfoDescriptorVer;
- UINT8 FmpImageInfoCount;
- UINTN DescriptorSize;
- UINT32 PackageVersion;
- CHAR16 *PackageVersionName;
-
- Status = gBS->HandleProtocol (
- Handle,
- &gEfiFirmwareManagementProtocolGuid,
- (VOID **)&Fmp
- );
- if (EFI_ERROR (Status)) {
- return 0;
- }
-
- ImageInfoSize = 0;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
- );
- if (Status != EFI_BUFFER_TOO_SMALL) {
- return 0;
- }
-
- FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
- if (FmpImageInfoBuf == NULL) {
- return 0;
- }
-
- PackageVersionName = NULL;
- Status = Fmp->GetImageInfo (
- Fmp,
- &ImageInfoSize, // ImageInfoSize
- FmpImageInfoBuf, // ImageInfo
- &FmpImageInfoDescriptorVer, // DescriptorVersion
- &FmpImageInfoCount, // DescriptorCount
- &DescriptorSize, // DescriptorSize
- &PackageVersion, // PackageVersion
- &PackageVersionName // PackageVersionName
- );
- if (EFI_ERROR (Status)) {
- FreePool (FmpImageInfoBuf);
- return 0;
- }
-
- return FmpImageInfoDescriptorVer;
-}
-
-/**
- Set FMP image data.
-
- @param[in] Handle A FMP handle.
- @param[in] ImageHeader The payload image header.
- @param[in] PayloadIndex The index of the payload.
-
- @return The status of FMP->SetImage.
-**/
-EFI_STATUS
-SetFmpImageData (
- IN EFI_HANDLE Handle,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN UINTN PayloadIndex
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
- UINT8 *Image;
- VOID *VendorCode;
- CHAR16 *AbortReason;
- EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
-
- Status = gBS->HandleProtocol (
- Handle,
- &gEfiFirmwareManagementProtocolGuid,
- (VOID **)&Fmp
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Lookup Firmware Management Progress Protocol before SetImage() is called
- // This is an optional protocol that may not be present on Handle.
- //
- Status = gBS->HandleProtocol (
- Handle,
- &gEdkiiFirmwareManagementProgressProtocolGuid,
- (VOID **)&mFmpProgress
- );
- if (EFI_ERROR (Status)) {
- mFmpProgress = NULL;
- }
-
- if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
- Image = (UINT8 *)(ImageHeader + 1);
- } else {
- //
- // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
- // Header should exclude UpdateHardwareInstance field, and
- // ImageCapsuleSupport field if version is 2.
- //
- if (ImageHeader->Version == 1) {
- Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
- } else {
- Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
- }
- }
-
- if (ImageHeader->UpdateVendorCodeSize == 0) {
- VendorCode = NULL;
- } else {
- VendorCode = Image + ImageHeader->UpdateImageSize;
- }
-
- AbortReason = NULL;
- DEBUG ((DEBUG_INFO, "Fmp->SetImage ...\n"));
- DEBUG ((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
- DEBUG ((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
- DEBUG ((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
- if (ImageHeader->Version >= 2) {
- DEBUG ((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
- if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
- DEBUG ((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
- }
- }
-
- DEBUG ((DEBUG_INFO, "\n"));
-
- //
- // Before calling SetImage(), reset the progress bar to 0%
- //
- ProgressCallback = UpdateImageProgress;
- Status = UpdateImageProgress (0);
- if (EFI_ERROR (Status)) {
- ProgressCallback = NULL;
- }
-
- Status = Fmp->SetImage (
- Fmp,
- ImageHeader->UpdateImageIndex, // ImageIndex
- Image, // Image
- ImageHeader->UpdateImageSize, // ImageSize
- VendorCode, // VendorCode
- ProgressCallback, // Progress
- &AbortReason // AbortReason
- );
- //
- // Set the progress bar to 100% after returning from SetImage()
- //
- if (ProgressCallback != NULL) {
- UpdateImageProgress (100);
- }
-
- DEBUG ((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
- if (AbortReason != NULL) {
- DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
- FreePool (AbortReason);
- }
-
- //
- // Clear mFmpProgress after SetImage() returns
- //
- mFmpProgress = NULL;
-
- return Status;
-}
-
-/**
- Start a UEFI image in the FMP payload.
-
- @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
- @param[in] ImageSize The size in bytes of ImageBuffer.
-
- @return The status of gBS->LoadImage and gBS->StartImage.
-**/
-EFI_STATUS
-StartFmpImage (
- IN VOID *ImageBuffer,
- IN UINTN ImageSize
- )
-{
- MEMMAP_DEVICE_PATH MemMapNode;
- EFI_STATUS Status;
- EFI_HANDLE ImageHandle;
- EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
- UINTN ExitDataSize;
-
- SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
- MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
- MemMapNode.Header.SubType = HW_MEMMAP_DP;
- MemMapNode.MemoryType = EfiBootServicesCode;
- MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
- MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
-
- DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
- if (DriverDevicePath == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
- Status = gBS->LoadImage (
- FALSE,
- gImageHandle,
- DriverDevicePath,
- ImageBuffer,
- ImageSize,
- &ImageHandle
- );
- DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
- if (EFI_ERROR (Status)) {
- //
- // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
- // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
- // If the caller doesn't have the option to defer the execution of an image, we should
- // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
- //
- if (Status == EFI_SECURITY_VIOLATION) {
- gBS->UnloadImage (ImageHandle);
- }
-
- FreePool (DriverDevicePath);
- return Status;
- }
-
- DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
- Status = gBS->StartImage (
- ImageHandle,
- &ExitDataSize,
- NULL
- );
- DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
- }
-
- FreePool (DriverDevicePath);
- return Status;
-}
-
-/**
- Record FMP capsule status.
-
- @param[in] Handle A FMP handle.
- @param[in] CapsuleHeader The capsule image header
- @param[in] CapsuleStatus The capsule process stauts
- @param[in] PayloadIndex FMP payload index
- @param[in] ImageHeader FMP image header
- @param[in] CapFileName Capsule file name
-**/
-VOID
-RecordFmpCapsuleStatus (
- IN EFI_HANDLE Handle OPTIONAL,
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN EFI_STATUS CapsuleStatus,
- IN UINTN PayloadIndex,
- IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
- IN CHAR16 *CapFileName OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
- UINT32 FmpImageInfoDescriptorVer;
- EFI_STATUS StatusEsrt;
- ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
- EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
-
- FmpDevicePath = NULL;
- if (Handle != NULL) {
- gBS->HandleProtocol (
- Handle,
- &gEfiDevicePathProtocolGuid,
- (VOID **)&FmpDevicePath
- );
- }
-
- RecordFmpCapsuleStatusVariable (
- CapsuleHeader,
- CapsuleStatus,
- PayloadIndex,
- ImageHeader,
- FmpDevicePath,
- CapFileName
- );
-
- //
- // Update corresponding ESRT entry LastAttemp Status
- //
- Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
- if (EFI_ERROR (Status)) {
- return;
- }
-
- if (Handle == NULL) {
- return;
- }
-
- //
- // Update EsrtEntry For V1, V2 FMP instance.
- // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
- //
- FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
- if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
- StatusEsrt = EsrtProtocol->GetEsrtEntry (&ImageHeader->UpdateImageTypeId, &EsrtEntry);
- if (!EFI_ERROR (StatusEsrt)) {
- if (!EFI_ERROR (CapsuleStatus)) {
- EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
- } else {
- EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
- }
-
- EsrtEntry.LastAttemptVersion = 0;
- EsrtProtocol->UpdateEsrtEntry (&EsrtEntry);
- }
- }
-}
-
-/**
- Process Firmware management protocol data capsule.
-
- This function assumes the caller validated the capsule by using
- ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
-
- This function need support nested FMP capsule.
-
- @param[in] CapsuleHeader Points to a capsule header.
- @param[in] CapFileName Capsule file name.
- @param[out] ResetRequired Indicates whether reset is required or not.
-
- @retval EFI_SUCESS Process Capsule Image successfully.
- @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
- @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
- @retval EFI_OUT_OF_RESOURCES Not enough memory.
- @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
-**/
-EFI_STATUS
-ProcessFmpCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN CHAR16 *CapFileName OPTIONAL,
- OUT BOOLEAN *ResetRequired OPTIONAL
- )
-{
- EFI_STATUS Status;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
- EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
- UINT64 *ItemOffsetList;
- UINT32 ItemNum;
- UINTN Index;
- EFI_HANDLE *HandleBuffer;
- BOOLEAN *ResetRequiredBuffer;
- UINTN NumberOfHandles;
- UINTN DriverLen;
- UINT64 UpdateHardwareInstance;
- UINTN Index2;
- BOOLEAN NotReady;
- BOOLEAN Abort;
-
- if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
- return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
- }
-
- NotReady = FALSE;
- Abort = FALSE;
-
- DumpFmpCapsule (CapsuleHeader);
-
- FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
-
- if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
- return EFI_INVALID_PARAMETER;
- }
-
- ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
-
- ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
-
- //
- // capsule in which driver count and payload count are both zero is not processed.
- //
- if (ItemNum == 0) {
- return EFI_SUCCESS;
- }
-
- //
- // 1. Try to load & start all the drivers within capsule
- //
- for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
- if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
- (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1))
- {
- //
- // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
- //
- DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
- } else {
- DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
- }
-
- Status = StartFmpImage (
- (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
- DriverLen
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
- return Status;
- }
- }
-
- //
- // 2. Route payload to right FMP instance
- //
- DEBUG ((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
-
- DumpAllFmpInfo ();
-
- //
- // Check all the payload entry in capsule payload list
- //
- for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
- ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
-
- UpdateHardwareInstance = 0;
- ///
- /// UpdateHardwareInstance field was added in Version 2
- ///
- if (ImageHeader->Version >= 2) {
- UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
- }
-
- Status = GetFmpHandleBufferByType (
- &ImageHeader->UpdateImageTypeId,
- UpdateHardwareInstance,
- &NumberOfHandles,
- &HandleBuffer,
- &ResetRequiredBuffer
- );
- if (EFI_ERROR (Status) ||
- (HandleBuffer == NULL) ||
- (ResetRequiredBuffer == NULL))
- {
- NotReady = TRUE;
- RecordFmpCapsuleStatus (
- NULL,
- CapsuleHeader,
- EFI_NOT_READY,
- Index - FmpCapsuleHeader->EmbeddedDriverCount,
- ImageHeader,
- CapFileName
- );
- continue;
- }
-
- for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
- if (Abort) {
- RecordFmpCapsuleStatus (
- HandleBuffer[Index2],
- CapsuleHeader,
- EFI_ABORTED,
- Index - FmpCapsuleHeader->EmbeddedDriverCount,
- ImageHeader,
- CapFileName
- );
- continue;
- }
-
- Status = SetFmpImageData (
- HandleBuffer[Index2],
- ImageHeader,
- Index - FmpCapsuleHeader->EmbeddedDriverCount
- );
- if (Status != EFI_SUCCESS) {
- Abort = TRUE;
- } else {
- if (ResetRequired != NULL) {
- *ResetRequired |= ResetRequiredBuffer[Index2];
- }
- }
-
- RecordFmpCapsuleStatus (
- HandleBuffer[Index2],
- CapsuleHeader,
- Status,
- Index - FmpCapsuleHeader->EmbeddedDriverCount,
- ImageHeader,
- CapFileName
- );
- }
-
- if (HandleBuffer != NULL) {
- FreePool (HandleBuffer);
- }
-
- if (ResetRequiredBuffer != NULL) {
- FreePool (ResetRequiredBuffer);
- }
- }
-
- if (NotReady) {
- return EFI_NOT_READY;
- }
-
- //
- // always return SUCCESS to indicate this capsule is processed.
- // The status of SetImage is recorded in capsule result variable.
- //
- return EFI_SUCCESS;
-}
-
-/**
- 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_ENTRY *EsrtEntry;
- UINTN Index;
- BOOLEAN EsrtGuidFound;
- EFI_CAPSULE_HEADER *NestedCapsuleHeader;
- UINTN NestedCapsuleSize;
- ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
- EFI_SYSTEM_RESOURCE_ENTRY Entry;
-
- EsrtGuidFound = FALSE;
- if (mEsrtTable != NULL) {
- EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
- for (Index = 0; Index < mEsrtTable->FwResourceCount; Index++, EsrtEntry++) {
- if (CompareGuid (&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
- EsrtGuidFound = TRUE;
- break;
- }
- }
- } else {
- //
- // Check ESRT protocol
- //
- Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
- if (!EFI_ERROR (Status)) {
- Status = EsrtProtocol->GetEsrtEntry (&CapsuleHeader->CapsuleGuid, &Entry);
- if (!EFI_ERROR (Status)) {
- EsrtGuidFound = TRUE;
- }
- }
-
- //
- // Check Firmware Management Protocols
- //
- if (!EsrtGuidFound) {
- Status = GetFmpHandleBufferByType (
- &CapsuleHeader->CapsuleGuid,
- 0,
- NULL,
- NULL,
- NULL
- );
- if (!EFI_ERROR (Status)) {
- EsrtGuidFound = TRUE;
- }
- }
- }
-
- 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 (!IsValidCapsuleHeader (NestedCapsuleHeader, NestedCapsuleSize)) {
- return FALSE;
- }
-
- if (!IsFmpCapsuleGuid (&NestedCapsuleHeader->CapsuleGuid)) {
- return FALSE;
- }
-
- DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
- return TRUE;
-}
-
-/**
- Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
-
- @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
-
- @retval TRUE It is a system FMP.
- @retval FALSE It is a device FMP.
-**/
-BOOLEAN
-IsFmpCapsule (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
- return TRUE;
- }
-
- if (IsNestedFmpCapsule (CapsuleHeader)) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Those capsules supported by the firmwares.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
-
- @retval EFI_SUCESS Input capsule is supported by firmware.
- @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
- @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
-**/
-EFI_STATUS
-EFIAPI
-SupportCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- //
- // check Display Capsule Guid
- //
- if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
- return EFI_SUCCESS;
- }
-
- //
- // Check capsule file name capsule
- //
- if (IsCapsuleNameCapsule (CapsuleHeader)) {
- return EFI_SUCCESS;
- }
-
- if (IsFmpCapsule (CapsuleHeader)) {
- //
- // Fake capsule header is valid case in QueryCapsuleCpapbilities().
- //
- if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
- return EFI_SUCCESS;
- }
-
- //
- // Check layout of FMP capsule
- //
- return ValidateFmpCapsule (CapsuleHeader, NULL);
- }
-
- DEBUG ((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
- return EFI_UNSUPPORTED;
-}
-
-/**
- The firmware implements to process the capsule image.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
- @param[in] CapFileName Capsule file name.
- @param[out] ResetRequired Indicates whether reset is required or not.
-
- @retval EFI_SUCESS Process Capsule Image successfully.
- @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
- @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
- @retval EFI_OUT_OF_RESOURCES Not enough memory.
-**/
-EFI_STATUS
-EFIAPI
-ProcessThisCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader,
- IN CHAR16 *CapFileName OPTIONAL,
- OUT BOOLEAN *ResetRequired OPTIONAL
- )
-{
- EFI_STATUS Status;
-
- if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
- RecordCapsuleStatusVariable (CapsuleHeader, EFI_UNSUPPORTED);
- return EFI_UNSUPPORTED;
- }
-
- //
- // Display image in firmware update display capsule
- //
- if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
- DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
- Status = DisplayCapsuleImage (CapsuleHeader);
- RecordCapsuleStatusVariable (CapsuleHeader, Status);
- return Status;
- }
-
- //
- // Check FMP capsule layout
- //
- if (IsFmpCapsule (CapsuleHeader)) {
- DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
- DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
- Status = ValidateFmpCapsule (CapsuleHeader, NULL);
- DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
- if (EFI_ERROR (Status)) {
- RecordCapsuleStatusVariable (CapsuleHeader, Status);
- return Status;
- }
-
- //
- // Process EFI FMP Capsule
- //
- DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
- Status = ProcessFmpCapsuleImage (CapsuleHeader, CapFileName, ResetRequired);
- DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
-
- return Status;
- }
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- The firmware implements to process the capsule image.
-
- Caution: This function may receive untrusted input.
-
- @param[in] CapsuleHeader Points to a capsule header.
-
- @retval EFI_SUCESS Process Capsule Image successfully.
- @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
- @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
- @retval EFI_OUT_OF_RESOURCES Not enough memory.
-**/
-EFI_STATUS
-EFIAPI
-ProcessCapsuleImage (
- IN EFI_CAPSULE_HEADER *CapsuleHeader
- )
-{
- return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
-}
-
-/**
- Callback function executed when the EndOfDxe event group is signaled.
-
- @param[in] Event Event whose notification function is being invoked.
- @param[in] Context The pointer to the notification function's context, which
- is implementation-dependent.
-**/
-VOID
-EFIAPI
-DxeCapsuleLibEndOfDxe (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- mDxeCapsuleLibEndOfDxe = TRUE;
-}
-
-/**
- The constructor function.
-
- @param[in] ImageHandle The firmware allocated handle for the EFI image.
- @param[in] SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The constructor successfully .
-**/
-EFI_STATUS
-EFIAPI
-DxeCapsuleLibConstructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- Status = gBS->CreateEventEx (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- DxeCapsuleLibEndOfDxe,
- NULL,
- &gEfiEndOfDxeEventGroupGuid,
- &mDxeCapsuleLibEndOfDxeEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- InitCapsuleVariable ();
-
- return EFI_SUCCESS;
-}
-
-/**
- The destructor function closes the End of DXE event.
-
- @param ImageHandle The firmware allocated handle for the EFI image.
- @param SystemTable A pointer to the EFI System Table.
-
- @retval EFI_SUCCESS The destructor completed successfully.
-**/
-EFI_STATUS
-EFIAPI
-DxeCapsuleLibDestructor (
- IN EFI_HANDLE ImageHandle,
- IN EFI_SYSTEM_TABLE *SystemTable
- )
-{
- EFI_STATUS Status;
-
- //
- // Close the End of DXE event.
- //
- Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
- ASSERT_EFI_ERROR (Status);
-
- return EFI_SUCCESS;
-}
+/** @file
+ DXE capsule library.
+
+ Caution: This module requires additional review when modified.
+ This module will have external input - capsule image.
+ This external input must be validated carefully to avoid security issue like
+ buffer overflow, integer overflow.
+
+ SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
+ ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
+ performs basic validation.
+
+ Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <IndustryStandard/WindowsUxCapsule.h>
+
+#include <Guid/FmpCapsule.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BmpSupportLib.h>
+
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EsrtManagement.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/FirmwareManagementProgress.h>
+#include <Protocol/DevicePath.h>
+
+EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
+
+BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
+EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
+
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
+
+/**
+ Initialize capsule related variables.
+**/
+VOID
+InitCapsuleVariable (
+ VOID
+ );
+
+/**
+ Record capsule status variable.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus
+ );
+
+/**
+ Record FMP capsule status variable.
+
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] FmpDevicePath DevicePath associated with the FMP producer
+ @param[in] CapFileName Capsule file name
+
+ @retval EFI_SUCCESS The capsule status variable is recorded.
+ @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
+**/
+EFI_STATUS
+RecordFmpCapsuleStatusVariable (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
+ IN CHAR16 *CapFileName OPTIONAL
+ );
+
+/**
+ Function indicate the current completion progress of the firmware
+ update. Platform may override with own specific progress function.
+
+ @param[in] Completion A value between 1 and 100 indicating the current
+ completion progress of the firmware update
+
+ @retval EFI_SUCESS The capsule update progress was updated.
+ @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
+**/
+EFI_STATUS
+EFIAPI
+UpdateImageProgress (
+ IN UINTN Completion
+ );
+
+/**
+ Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a capsule name capsule.
+ @retval FALSE It is not a capsule name capsule.
+**/
+BOOLEAN
+IsCapsuleNameCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
+}
+
+/**
+ Return if this CapsuleGuid is a FMP capsule GUID or not.
+
+ @param[in] CapsuleGuid A pointer to EFI_GUID
+
+ @retval TRUE It is a FMP capsule GUID.
+ @retval FALSE It is not a FMP capsule GUID.
+**/
+BOOLEAN
+IsFmpCapsuleGuid (
+ IN EFI_GUID *CapsuleGuid
+ )
+{
+ if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Validate if it is valid capsule header
+
+ Caution: This function may receive untrusted input.
+
+ 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
+ )
+{
+ if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
+ return FALSE;
+ }
+
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Validate Fmp capsules layout.
+
+ Caution: This function may receive untrusted input.
+
+ This function assumes the caller validated the capsule by using
+ IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
+ The capsule buffer size is CapsuleHeader->CapsuleImageSize.
+
+ This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
+
+ This function need support nested FMP capsule.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
+
+ @retval EFI_SUCESS Input capsule is a correct FMP capsule.
+ @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
+**/
+EFI_STATUS
+ValidateFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ OUT UINT16 *EmbeddedDriverCount OPTIONAL
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT8 *EndOfCapsule;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT8 *EndOfPayload;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ UINTN FmpCapsuleSize;
+ UINTN FmpCapsuleHeaderSize;
+ UINT64 FmpImageSize;
+ UINTN FmpImageHeaderSize;
+
+ if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
+ return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
+ }
+
+ if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
+ DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+ EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
+ FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
+
+ if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
+ DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
+ if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ // No overflow
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
+ DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
+
+ // Check ItemOffsetList
+ for (Index = 0; Index < ItemNum; Index++) {
+ if (ItemOffsetList[Index] >= FmpCapsuleSize) {
+ DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
+ DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // All the address in ItemOffsetList must be stored in ascending order
+ //
+ if (Index > 0) {
+ if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
+ DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ if (Index == ItemNum - 1) {
+ EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
+ } else {
+ EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
+ }
+
+ FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
+
+ FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
+ if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
+ (ImageHeader->Version < 1))
+ {
+ DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImageHeader->Version == 1) {
+ FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ } else if (ImageHeader->Version == 2) {
+ FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
+ }
+
+ if (FmpImageSize < FmpImageHeaderSize) {
+ DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ // No overflow
+ if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
+ DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (ItemNum == 0) {
+ //
+ // No driver & payload element in FMP
+ //
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
+ if (EndOfPayload != EndOfCapsule) {
+ DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EmbeddedDriverCount != NULL) {
+ *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Input capsule is supported by firmware.
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+**/
+EFI_STATUS
+DisplayCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
+ UINTN PayloadSize;
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINTN BltSize;
+ UINTN Height;
+ UINTN Width;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+
+ //
+ // UX capsule doesn't have extended header entries.
+ //
+ if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize);
+ //
+ // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
+ //
+ PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+
+ //
+ // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
+ // Further size check is performed by the logic translating BMP to GOP BLT.
+ //
+ if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ImagePayload->Version != 1) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (CalculateCheckSum8 ((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Only Support Bitmap by now
+ //
+ if (ImagePayload->ImageType != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Try to open GOP
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR (Status)) {
+ Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Blt = NULL;
+ Width = 0;
+ Height = 0;
+ Status = TranslateBmpToGopBlt (
+ ImagePayload + 1,
+ PayloadSize - sizeof (DISPLAY_DISPLAY_PAYLOAD),
+ &Blt,
+ &BltSize,
+ &Height,
+ &Width
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ Blt,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN)ImagePayload->OffsetX,
+ (UINTN)ImagePayload->OffsetY,
+ Width,
+ Height,
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+
+ FreePool (Blt);
+
+ return Status;
+}
+
+/**
+ 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;
+
+ DEBUG ((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
+ DEBUG ((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
+ DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
+ DEBUG ((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
+ DEBUG ((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
+ CurrentImageInfo = ImageInfo;
+ for (Index = 0; Index < DescriptorCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
+ DEBUG ((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
+ DEBUG ((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
+ DEBUG ((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
+ DEBUG ((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
+ DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
+ DEBUG ((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
+ DEBUG ((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
+ DEBUG ((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
+ DEBUG ((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
+ DEBUG ((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
+ if (DescriptorVersion > 1) {
+ DEBUG ((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
+ if (DescriptorVersion > 2) {
+ DEBUG ((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
+ DEBUG ((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
+ DEBUG ((DEBUG_VERBOSE, " 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 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;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINTN Index;
+ UINT64 *ItemOffsetList;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ DEBUG ((DEBUG_VERBOSE, "FmpCapsule:\n"));
+ DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
+ DEBUG ((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
+ DEBUG ((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
+ }
+
+ for ( ; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
+ DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+ DEBUG ((DEBUG_VERBOSE, " ImageHeader:\n"));
+ DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
+ DEBUG ((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
+ DEBUG ((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
+ DEBUG ((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
+ DEBUG ((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
+ if (ImageHeader->Version >= 2) {
+ DEBUG ((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ DEBUG ((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
+ }
+ }
+ }
+}
+
+/**
+ Dump all FMP information.
+**/
+VOID
+DumpAllFmpInfo (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN Index;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ 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 = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FmpImageInfoBuf);
+ continue;
+ }
+
+ DEBUG ((DEBUG_INFO, "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);
+ }
+
+ FreePool (HandleBuffer);
+
+ return;
+}
+
+/**
+ Get FMP handle by ImageTypeId and HardwareInstance.
+
+ @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
+ @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
+ @param[out] NoHandles The number of handles returned in HandleBuf.
+ @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
+ @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
+ the requested array of handles.
+
+ @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
+ HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
+ was returned in NoHandles.
+ @retval EFI_NOT_FOUND No handles match the search.
+ @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
+**/
+EFI_STATUS
+GetFmpHandleBufferByType (
+ IN EFI_GUID *UpdateImageTypeId,
+ IN UINT64 UpdateHardwareInstance,
+ OUT UINTN *NoHandles OPTIONAL,
+ OUT EFI_HANDLE **HandleBuf OPTIONAL,
+ OUT BOOLEAN **ResetRequiredBuf OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN NumberOfHandles;
+ EFI_HANDLE *MatchedHandleBuffer;
+ BOOLEAN *MatchedResetRequiredBuffer;
+ UINTN MatchedNumberOfHandles;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN Index;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ UINTN Index2;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
+
+ if (NoHandles != NULL) {
+ *NoHandles = 0;
+ }
+
+ if (HandleBuf != NULL) {
+ *HandleBuf = NULL;
+ }
+
+ if (ResetRequiredBuf != NULL) {
+ *ResetRequiredBuf = NULL;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MatchedNumberOfHandles = 0;
+
+ MatchedHandleBuffer = NULL;
+ if (HandleBuf != NULL) {
+ MatchedHandleBuffer = AllocateZeroPool (sizeof (EFI_HANDLE) * NumberOfHandles);
+ if (MatchedHandleBuffer == NULL) {
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ MatchedResetRequiredBuffer = NULL;
+ if (ResetRequiredBuf != NULL) {
+ MatchedResetRequiredBuffer = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfHandles);
+ if (MatchedResetRequiredBuffer == NULL) {
+ if (MatchedHandleBuffer != NULL) {
+ FreePool (MatchedHandleBuffer);
+ }
+
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ 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 = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ continue;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FmpImageInfoBuf);
+ continue;
+ }
+
+ if (PackageVersionName != NULL) {
+ FreePool (PackageVersionName);
+ }
+
+ TempFmpImageInfo = FmpImageInfoBuf;
+ for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
+ //
+ // Check if this FMP instance matches
+ //
+ if (CompareGuid (UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
+ if ((UpdateHardwareInstance == 0) ||
+ ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
+ (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance)))
+ {
+ if (MatchedHandleBuffer != NULL) {
+ MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
+ }
+
+ if (MatchedResetRequiredBuffer != NULL) {
+ MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
+ IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
+ ((TempFmpImageInfo->AttributesSetting &
+ IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
+ }
+
+ MatchedNumberOfHandles++;
+ break;
+ }
+ }
+
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
+ }
+
+ FreePool (FmpImageInfoBuf);
+ }
+
+ FreePool (HandleBuffer);
+
+ if (MatchedNumberOfHandles == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (NoHandles != NULL) {
+ *NoHandles = MatchedNumberOfHandles;
+ }
+
+ if (HandleBuf != NULL) {
+ *HandleBuf = MatchedHandleBuffer;
+ }
+
+ if (ResetRequiredBuf != NULL) {
+ *ResetRequiredBuf = MatchedResetRequiredBuffer;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return FmpImageInfoDescriptorVer by an FMP handle.
+
+ @param[in] Handle A FMP handle.
+
+ @return FmpImageInfoDescriptorVer associated with the FMP.
+**/
+UINT32
+GetFmpImageInfoDescriptorVer (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN ImageInfoSize;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINT8 FmpImageInfoCount;
+ UINTN DescriptorSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ return 0;
+ }
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ return 0;
+ }
+
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ return 0;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FmpImageInfoBuf);
+ return 0;
+ }
+
+ return FmpImageInfoDescriptorVer;
+}
+
+/**
+ Set FMP image data.
+
+ @param[in] Handle A FMP handle.
+ @param[in] ImageHeader The payload image header.
+ @param[in] PayloadIndex The index of the payload.
+
+ @return The status of FMP->SetImage.
+**/
+EFI_STATUS
+SetFmpImageData (
+ IN EFI_HANDLE Handle,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN UINTN PayloadIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINT8 *Image;
+ VOID *VendorCode;
+ CHAR16 *AbortReason;
+ EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Lookup Firmware Management Progress Protocol before SetImage() is called
+ // This is an optional protocol that may not be present on Handle.
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEdkiiFirmwareManagementProgressProtocolGuid,
+ (VOID **)&mFmpProgress
+ );
+ if (EFI_ERROR (Status)) {
+ mFmpProgress = NULL;
+ }
+
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ Image = (UINT8 *)(ImageHeader + 1);
+ } else {
+ //
+ // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
+ // Header should exclude UpdateHardwareInstance field, and
+ // ImageCapsuleSupport field if version is 2.
+ //
+ if (ImageHeader->Version == 1) {
+ Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
+ } else {
+ Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
+ }
+ }
+
+ if (ImageHeader->UpdateVendorCodeSize == 0) {
+ VendorCode = NULL;
+ } else {
+ VendorCode = Image + ImageHeader->UpdateImageSize;
+ }
+
+ AbortReason = NULL;
+ DEBUG ((DEBUG_INFO, "Fmp->SetImage ...\n"));
+ DEBUG ((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
+ DEBUG ((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
+ DEBUG ((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
+ if (ImageHeader->Version >= 2) {
+ DEBUG ((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
+ if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
+ DEBUG ((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+
+ //
+ // Before calling SetImage(), reset the progress bar to 0%
+ //
+ ProgressCallback = UpdateImageProgress;
+ Status = UpdateImageProgress (0);
+ if (EFI_ERROR (Status)) {
+ ProgressCallback = NULL;
+ }
+
+ Status = Fmp->SetImage (
+ Fmp,
+ ImageHeader->UpdateImageIndex, // ImageIndex
+ Image, // Image
+ ImageHeader->UpdateImageSize, // ImageSize
+ VendorCode, // VendorCode
+ ProgressCallback, // Progress
+ &AbortReason // AbortReason
+ );
+ //
+ // Set the progress bar to 100% after returning from SetImage()
+ //
+ if (ProgressCallback != NULL) {
+ UpdateImageProgress (100);
+ }
+
+ DEBUG ((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
+ if (AbortReason != NULL) {
+ DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
+ FreePool (AbortReason);
+ }
+
+ //
+ // Clear mFmpProgress after SetImage() returns
+ //
+ mFmpProgress = NULL;
+
+ return Status;
+}
+
+/**
+ Start a UEFI image in the FMP payload.
+
+ @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
+ @param[in] ImageSize The size in bytes of ImageBuffer.
+
+ @return The status of gBS->LoadImage and gBS->StartImage.
+**/
+EFI_STATUS
+StartFmpImage (
+ IN VOID *ImageBuffer,
+ IN UINTN ImageSize
+ )
+{
+ MEMMAP_DEVICE_PATH MemMapNode;
+ EFI_STATUS Status;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ UINTN ExitDataSize;
+
+ SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
+ MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
+ MemMapNode.Header.SubType = HW_MEMMAP_DP;
+ MemMapNode.MemoryType = EfiBootServicesCode;
+ MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
+
+ DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
+ if (DriverDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ DriverDevicePath,
+ ImageBuffer,
+ ImageSize,
+ &ImageHandle
+ );
+ DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ //
+ // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
+ // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
+ // If the caller doesn't have the option to defer the execution of an image, we should
+ // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
+ //
+ if (Status == EFI_SECURITY_VIOLATION) {
+ gBS->UnloadImage (ImageHandle);
+ }
+
+ FreePool (DriverDevicePath);
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
+ Status = gBS->StartImage (
+ ImageHandle,
+ &ExitDataSize,
+ NULL
+ );
+ DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ }
+
+ FreePool (DriverDevicePath);
+ return Status;
+}
+
+/**
+ Record FMP capsule status.
+
+ @param[in] Handle A FMP handle.
+ @param[in] CapsuleHeader The capsule image header
+ @param[in] CapsuleStatus The capsule process stauts
+ @param[in] PayloadIndex FMP payload index
+ @param[in] ImageHeader FMP image header
+ @param[in] CapFileName Capsule file name
+**/
+VOID
+RecordFmpCapsuleStatus (
+ IN EFI_HANDLE Handle OPTIONAL,
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN EFI_STATUS CapsuleStatus,
+ IN UINTN PayloadIndex,
+ IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
+ IN CHAR16 *CapFileName OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
+ UINT32 FmpImageInfoDescriptorVer;
+ EFI_STATUS StatusEsrt;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
+ EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
+
+ FmpDevicePath = NULL;
+ if (Handle != NULL) {
+ gBS->HandleProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **)&FmpDevicePath
+ );
+ }
+
+ RecordFmpCapsuleStatusVariable (
+ CapsuleHeader,
+ CapsuleStatus,
+ PayloadIndex,
+ ImageHeader,
+ FmpDevicePath,
+ CapFileName
+ );
+
+ //
+ // Update corresponding ESRT entry LastAttemp Status
+ //
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ if (Handle == NULL) {
+ return;
+ }
+
+ //
+ // Update EsrtEntry For V1, V2 FMP instance.
+ // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
+ //
+ FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
+ if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
+ StatusEsrt = EsrtProtocol->GetEsrtEntry (&ImageHeader->UpdateImageTypeId, &EsrtEntry);
+ if (!EFI_ERROR (StatusEsrt)) {
+ if (!EFI_ERROR (CapsuleStatus)) {
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+ } else {
+ EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
+ }
+
+ EsrtEntry.LastAttemptVersion = 0;
+ EsrtProtocol->UpdateEsrtEntry (&EsrtEntry);
+ }
+ }
+}
+
+/**
+ Process Firmware management protocol data capsule.
+
+ This function assumes the caller validated the capsule by using
+ ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
+
+ This function need support nested FMP capsule.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapFileName Capsule file name.
+ @param[out] ResetRequired Indicates whether reset is required or not.
+
+ @retval EFI_SUCESS Process Capsule Image successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+ @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
+**/
+EFI_STATUS
+ProcessFmpCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN CHAR16 *CapFileName OPTIONAL,
+ OUT BOOLEAN *ResetRequired OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ EFI_HANDLE *HandleBuffer;
+ BOOLEAN *ResetRequiredBuffer;
+ UINTN NumberOfHandles;
+ UINTN DriverLen;
+ UINT64 UpdateHardwareInstance;
+ UINTN Index2;
+ BOOLEAN NotReady;
+ BOOLEAN Abort;
+
+ if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
+ return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
+ }
+
+ NotReady = FALSE;
+ Abort = FALSE;
+
+ DumpFmpCapsule (CapsuleHeader);
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ //
+ // capsule in which driver count and payload count are both zero is not processed.
+ //
+ if (ItemNum == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 1. Try to load & start all the drivers within capsule
+ //
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+ if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
+ (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1))
+ {
+ //
+ // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
+ //
+ DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
+ } else {
+ DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
+ }
+
+ Status = StartFmpImage (
+ (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
+ DriverLen
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ return Status;
+ }
+ }
+
+ //
+ // 2. Route payload to right FMP instance
+ //
+ DEBUG ((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
+
+ DumpAllFmpInfo ();
+
+ //
+ // Check all the payload entry in capsule payload list
+ //
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+
+ UpdateHardwareInstance = 0;
+ ///
+ /// UpdateHardwareInstance field was added in Version 2
+ ///
+ if (ImageHeader->Version >= 2) {
+ UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
+ }
+
+ Status = GetFmpHandleBufferByType (
+ &ImageHeader->UpdateImageTypeId,
+ UpdateHardwareInstance,
+ &NumberOfHandles,
+ &HandleBuffer,
+ &ResetRequiredBuffer
+ );
+ if (EFI_ERROR (Status) ||
+ (HandleBuffer == NULL) ||
+ (ResetRequiredBuffer == NULL))
+ {
+ NotReady = TRUE;
+ RecordFmpCapsuleStatus (
+ NULL,
+ CapsuleHeader,
+ EFI_NOT_READY,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ continue;
+ }
+
+ for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
+ if (Abort) {
+ RecordFmpCapsuleStatus (
+ HandleBuffer[Index2],
+ CapsuleHeader,
+ EFI_ABORTED,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ continue;
+ }
+
+ Status = SetFmpImageData (
+ HandleBuffer[Index2],
+ ImageHeader,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount
+ );
+ if (Status != EFI_SUCCESS) {
+ Abort = TRUE;
+ } else {
+ if (ResetRequired != NULL) {
+ *ResetRequired |= ResetRequiredBuffer[Index2];
+ }
+ }
+
+ RecordFmpCapsuleStatus (
+ HandleBuffer[Index2],
+ CapsuleHeader,
+ Status,
+ Index - FmpCapsuleHeader->EmbeddedDriverCount,
+ ImageHeader,
+ CapFileName
+ );
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ if (ResetRequiredBuffer != NULL) {
+ FreePool (ResetRequiredBuffer);
+ }
+ }
+
+ if (NotReady) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // always return SUCCESS to indicate this capsule is processed.
+ // The status of SetImage is recorded in capsule result variable.
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ 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_ENTRY *EsrtEntry;
+ UINTN Index;
+ BOOLEAN EsrtGuidFound;
+ EFI_CAPSULE_HEADER *NestedCapsuleHeader;
+ UINTN NestedCapsuleSize;
+ ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
+ EFI_SYSTEM_RESOURCE_ENTRY Entry;
+
+ EsrtGuidFound = FALSE;
+ if (mEsrtTable != NULL) {
+ EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
+ for (Index = 0; Index < mEsrtTable->FwResourceCount; Index++, EsrtEntry++) {
+ if (CompareGuid (&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
+ EsrtGuidFound = TRUE;
+ break;
+ }
+ }
+ } else {
+ //
+ // Check ESRT protocol
+ //
+ Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
+ if (!EFI_ERROR (Status)) {
+ Status = EsrtProtocol->GetEsrtEntry (&CapsuleHeader->CapsuleGuid, &Entry);
+ if (!EFI_ERROR (Status)) {
+ EsrtGuidFound = TRUE;
+ }
+ }
+
+ //
+ // Check Firmware Management Protocols
+ //
+ if (!EsrtGuidFound) {
+ Status = GetFmpHandleBufferByType (
+ &CapsuleHeader->CapsuleGuid,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ EsrtGuidFound = TRUE;
+ }
+ }
+ }
+
+ 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 (!IsValidCapsuleHeader (NestedCapsuleHeader, NestedCapsuleSize)) {
+ return FALSE;
+ }
+
+ if (!IsFmpCapsuleGuid (&NestedCapsuleHeader->CapsuleGuid)) {
+ return FALSE;
+ }
+
+ DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
+ return TRUE;
+}
+
+/**
+ Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
+
+ @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
+
+ @retval TRUE It is a system FMP.
+ @retval FALSE It is a device FMP.
+**/
+BOOLEAN
+IsFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
+ return TRUE;
+ }
+
+ if (IsNestedFmpCapsule (CapsuleHeader)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Input capsule is supported by firmware.
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+ @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ //
+ // check Display Capsule Guid
+ //
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check capsule file name capsule
+ //
+ if (IsCapsuleNameCapsule (CapsuleHeader)) {
+ return EFI_SUCCESS;
+ }
+
+ if (IsFmpCapsule (CapsuleHeader)) {
+ //
+ // Fake capsule header is valid case in QueryCapsuleCpapbilities().
+ //
+ if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Check layout of FMP capsule
+ //
+ return ValidateFmpCapsule (CapsuleHeader, NULL);
+ }
+
+ DEBUG ((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware implements to process the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+ @param[in] CapFileName Capsule file name.
+ @param[out] ResetRequired Indicates whether reset is required or not.
+
+ @retval EFI_SUCESS Process Capsule Image successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+**/
+EFI_STATUS
+EFIAPI
+ProcessThisCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader,
+ IN CHAR16 *CapFileName OPTIONAL,
+ OUT BOOLEAN *ResetRequired OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
+ RecordCapsuleStatusVariable (CapsuleHeader, EFI_UNSUPPORTED);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Display image in firmware update display capsule
+ //
+ if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
+ Status = DisplayCapsuleImage (CapsuleHeader);
+ RecordCapsuleStatusVariable (CapsuleHeader, Status);
+ return Status;
+ }
+
+ //
+ // Check FMP capsule layout
+ //
+ if (IsFmpCapsule (CapsuleHeader)) {
+ DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
+ DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
+ Status = ValidateFmpCapsule (CapsuleHeader, NULL);
+ DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ RecordCapsuleStatusVariable (CapsuleHeader, Status);
+ return Status;
+ }
+
+ //
+ // Process EFI FMP Capsule
+ //
+ DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
+ Status = ProcessFmpCapsuleImage (CapsuleHeader, CapFileName, ResetRequired);
+ DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
+
+ return Status;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware implements to process the capsule image.
+
+ Caution: This function may receive untrusted input.
+
+ @param[in] CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Process Capsule Image successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
+}
+
+/**
+ Callback function executed when the EndOfDxe event group is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context, which
+ is implementation-dependent.
+**/
+VOID
+EFIAPI
+DxeCapsuleLibEndOfDxe (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mDxeCapsuleLibEndOfDxe = TRUE;
+}
+
+/**
+ The constructor function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully .
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DxeCapsuleLibEndOfDxe,
+ NULL,
+ &gEfiEndOfDxeEventGroupGuid,
+ &mDxeCapsuleLibEndOfDxeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ InitCapsuleVariable ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function closes the End of DXE event.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+**/
+EFI_STATUS
+EFIAPI
+DxeCapsuleLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Close the End of DXE event.
+ //
+ Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}