/** @file Provides FMP capsule dependency check services when updating the firmware image of a FMP device. Copyright (c) Microsoft Corporation.
Copyright (c) 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include /** 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. @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 ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN Index; EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp; UINTN ImageInfoSize; 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; 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; goto cleanup; } FmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfFmpInstance); if (FmpImageInfoBuf == NULL) { IsSatisfied = FALSE; goto cleanup; } DescriptorVer = AllocateZeroPool (sizeof(UINT32) * NumberOfFmpInstance); if (DescriptorVer == NULL ) { IsSatisfied = FALSE; goto cleanup; } DescriptorSize = AllocateZeroPool (sizeof(UINTN) * NumberOfFmpInstance); if (DescriptorSize == NULL ) { IsSatisfied = FALSE; goto cleanup; } FmpVersions = AllocateZeroPool (sizeof(FMP_DEPEX_CHECK_VERSION_DATA) * NumberOfFmpInstance); if (FmpVersions == NULL) { IsSatisfied = FALSE; 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); } 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); } return IsSatisfied; }