Files
system76-edk2/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
Michael Kubacki 207414cba4 FmpDevicePkg: Add Last Attempt Status support to dependency libs
The FMP dependency libraries are leveraged during firmware update
to check for dependencies required to update the image.

This change adds granular Last Attempt Status code support to these
services so failures can be more easily observed during the firmware
update process via Last Attempt Status codes.

Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Cc: Wei6 Xu <wei6.xu@intel.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
Acked-by: Liming Gao <gaoliming@byosoft.com.cn>
Reviewed-by: Wei6 Xu <wei6.xu@intel.com>
Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com>
2020-10-28 06:05:52 +00:00

218 lines
7.3 KiB
C

/** @file
Provides FMP capsule dependency check services when updating the firmware
image of a FMP device.
Copyright (c) Microsoft Corporation.<BR>
Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiDxe.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/FmpDependencyLib.h>
#include <Library/FmpDependencyCheckLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/UefiLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Guid/SystemResourceTable.h>
#include <LastAttemptStatus.h>
#include <FmpLastAttemptStatus.h>
/**
Check dependency for firmware update.
@param[in] ImageTypeId Image Type Id.
@param[in] Version New version.
@param[in] Dependencies Fmp dependency.
@param[in] DependenciesSize Size, in bytes, of the Fmp dependency.
@param[out] LastAttemptStatus An optional pointer to a UINT32 that holds the
last attempt status to report back to the caller.
This function will set the value to LAST_ATTEMPT_STATUS_SUCCESS
if an error code is not set.
@retval TRUE Dependencies are satisfied.
@retval FALSE Dependencies are unsatisfied or dependency check fails.
**/
BOOLEAN
EFIAPI
CheckFmpDependency (
IN EFI_GUID ImageTypeId,
IN UINT32 Version,
IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL
IN UINT32 DependenciesSize,
OUT UINT32 *LastAttemptStatus OPTIONAL
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN Index;
EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
UINTN ImageInfoSize;
UINT32 LocalLastAttemptStatus;
UINT32 *DescriptorVer;
UINT8 FmpImageInfoCount;
UINTN *DescriptorSize;
UINT32 PackageVersion;
CHAR16 *PackageVersionName;
UINTN NumberOfFmpInstance;
EFI_FIRMWARE_IMAGE_DESCRIPTOR **FmpImageInfoBuf;
FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions;
UINTN FmpVersionsCount;
BOOLEAN IsSatisfied;
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
FmpImageInfoBuf = NULL;
DescriptorVer = NULL;
DescriptorSize = NULL;
NumberOfFmpInstance = 0;
FmpVersions = NULL;
FmpVersionsCount = 0;
IsSatisfied = TRUE;
PackageVersionName = NULL;
//
// Get ImageDescriptors of all FMP instances, and archive them for dependency evaluation.
//
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareManagementProtocolGuid,
NULL,
&NumberOfFmpInstance,
&HandleBuffer
);
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "CheckFmpDependency: Get Firmware Management Protocol failed. (%r)", Status));
IsSatisfied = FALSE;
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_FMP_PROTOCOL_NOT_FOUND;
goto cleanup;
}
FmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfFmpInstance);
if (FmpImageInfoBuf == NULL) {
IsSatisfied = FALSE;
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_FMP_INFO_BUFFER_FAILED;
goto cleanup;
}
DescriptorVer = AllocateZeroPool (sizeof(UINT32) * NumberOfFmpInstance);
if (DescriptorVer == NULL ) {
IsSatisfied = FALSE;
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_DESC_VER_BUFFER_FAILED;
goto cleanup;
}
DescriptorSize = AllocateZeroPool (sizeof(UINTN) * NumberOfFmpInstance);
if (DescriptorSize == NULL ) {
IsSatisfied = FALSE;
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_DESC_SIZE_BUFFER_FAILED;
goto cleanup;
}
FmpVersions = AllocateZeroPool (sizeof(FMP_DEPEX_CHECK_VERSION_DATA) * NumberOfFmpInstance);
if (FmpVersions == NULL) {
IsSatisfied = FALSE;
LocalLastAttemptStatus = LAST_ATTEMPT_STATUS_DEPENDENCY_CHECK_LIB_ERROR_MEM_ALLOC_FMP_VER_BUFFER_FAILED;
goto cleanup;
}
for (Index = 0; Index < NumberOfFmpInstance; 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[Index] = AllocateZeroPool (ImageInfoSize);
if (FmpImageInfoBuf[Index] == NULL) {
continue;
}
Status = Fmp->GetImageInfo (
Fmp,
&ImageInfoSize, // ImageInfoSize
FmpImageInfoBuf[Index], // ImageInfo
&DescriptorVer[Index], // DescriptorVersion
&FmpImageInfoCount, // DescriptorCount
&DescriptorSize[Index], // DescriptorSize
&PackageVersion, // PackageVersion
&PackageVersionName // PackageVersionName
);
if (EFI_ERROR(Status)) {
FreePool (FmpImageInfoBuf[Index]);
FmpImageInfoBuf[Index] = NULL;
continue;
}
if (PackageVersionName != NULL) {
FreePool (PackageVersionName);
PackageVersionName = NULL;
}
CopyGuid (&FmpVersions[FmpVersionsCount].ImageTypeId, &FmpImageInfoBuf[Index]->ImageTypeId);
FmpVersions[FmpVersionsCount].Version = FmpImageInfoBuf[Index]->Version;
FmpVersionsCount ++;
}
//
// Evaluate firmware image's depex, against the version of other Fmp instances.
//
if (Dependencies != NULL) {
IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount, &LocalLastAttemptStatus);
}
if (!IsSatisfied) {
DEBUG ((DEBUG_ERROR, "CheckFmpDependency: %g\'s dependency is not satisfied!\n", ImageTypeId));
goto cleanup;
}
cleanup:
if (FmpImageInfoBuf != NULL) {
for (Index = 0; Index < NumberOfFmpInstance; Index ++) {
if (FmpImageInfoBuf[Index] != NULL) {
FreePool (FmpImageInfoBuf[Index]);
}
}
FreePool (FmpImageInfoBuf);
}
if (DescriptorVer != NULL) {
FreePool (DescriptorVer);
}
if (DescriptorSize != NULL) {
FreePool (DescriptorSize);
}
if (FmpVersions != NULL) {
FreePool (FmpVersions);
}
if (LastAttemptStatus != NULL) {
*LastAttemptStatus = LocalLastAttemptStatus;
}
return IsSatisfied;
}