|
@@ -0,0 +1,196 @@
|
|
|
+/** @file
|
|
|
+ Provides FMP capsule dependency check services when updating the firmware
|
|
|
+ image of a FMP device.
|
|
|
+
|
|
|
+ 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>
|
|
|
+
|
|
|
+/**
|
|
|
+ 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));
|
|
|
+ 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;
|
|
|
+}
|