--- /dev/null
+/** @file\r
+ Provides FMP capsule dependency check services when updating the firmware\r
+ image of a FMP device.\r
+\r
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\r
+\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/FmpDependencyLib.h>\r
+#include <Library/FmpDependencyCheckLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+\r
+/**\r
+ Check dependency for firmware update.\r
+\r
+ @param[in] ImageTypeId Image Type Id.\r
+ @param[in] Version New version.\r
+ @param[in] Dependencies Fmp dependency.\r
+ @param[in] DependenciesSize Size, in bytes, of the Fmp dependency.\r
+\r
+ @retval TRUE Dependencies are satisfied.\r
+ @retval FALSE Dependencies are unsatisfied or dependency check fails.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+CheckFmpDependency (\r
+ IN EFI_GUID ImageTypeId,\r
+ IN UINT32 Version,\r
+ IN EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL\r
+ IN UINT32 DependenciesSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_HANDLE *HandleBuffer;\r
+ UINTN Index;\r
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;\r
+ UINTN ImageInfoSize;\r
+ UINT32 *DescriptorVer;\r
+ UINT8 FmpImageInfoCount;\r
+ UINTN *DescriptorSize;\r
+ UINT32 PackageVersion;\r
+ CHAR16 *PackageVersionName;\r
+ UINTN NumberOfFmpInstance;\r
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR **FmpImageInfoBuf;\r
+ FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions;\r
+ UINTN FmpVersionsCount;\r
+ BOOLEAN IsSatisfied;\r
+\r
+ FmpImageInfoBuf = NULL;\r
+ DescriptorVer = NULL;\r
+ DescriptorSize = NULL;\r
+ NumberOfFmpInstance = 0;\r
+ FmpVersions = NULL;\r
+ FmpVersionsCount = 0;\r
+ IsSatisfied = TRUE;\r
+ PackageVersionName = NULL;\r
+\r
+ //\r
+ // Get ImageDescriptors of all FMP instances, and archive them for dependency evaluation.\r
+ //\r
+ Status = gBS->LocateHandleBuffer (\r
+ ByProtocol,\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ NULL,\r
+ &NumberOfFmpInstance,\r
+ &HandleBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "CheckFmpDependency: Get Firmware Management Protocol failed. (%r)", Status));\r
+ goto cleanup;\r
+ }\r
+\r
+ FmpImageInfoBuf = AllocateZeroPool (sizeof(EFI_FIRMWARE_IMAGE_DESCRIPTOR *) * NumberOfFmpInstance);\r
+ if (FmpImageInfoBuf == NULL) {\r
+ IsSatisfied = FALSE;\r
+ goto cleanup;\r
+ }\r
+\r
+ DescriptorVer = AllocateZeroPool (sizeof(UINT32) * NumberOfFmpInstance);\r
+ if (DescriptorVer == NULL ) {\r
+ IsSatisfied = FALSE;\r
+ goto cleanup;\r
+ }\r
+\r
+ DescriptorSize = AllocateZeroPool (sizeof(UINTN) * NumberOfFmpInstance);\r
+ if (DescriptorSize == NULL ) {\r
+ IsSatisfied = FALSE;\r
+ goto cleanup;\r
+ }\r
+\r
+ FmpVersions = AllocateZeroPool (sizeof(FMP_DEPEX_CHECK_VERSION_DATA) * NumberOfFmpInstance);\r
+ if (FmpVersions == NULL) {\r
+ IsSatisfied = FALSE;\r
+ goto cleanup;\r
+ }\r
+\r
+ for (Index = 0; Index < NumberOfFmpInstance; Index ++) {\r
+ Status = gBS->HandleProtocol (\r
+ HandleBuffer[Index],\r
+ &gEfiFirmwareManagementProtocolGuid,\r
+ (VOID **) &Fmp\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ continue;\r
+ }\r
+\r
+ ImageInfoSize = 0;\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL,\r
+ NULL\r
+ );\r
+ if (Status != EFI_BUFFER_TOO_SMALL) {\r
+ continue;\r
+ }\r
+\r
+ FmpImageInfoBuf[Index] = AllocateZeroPool (ImageInfoSize);\r
+ if (FmpImageInfoBuf[Index] == NULL) {\r
+ continue;\r
+ }\r
+\r
+ Status = Fmp->GetImageInfo (\r
+ Fmp,\r
+ &ImageInfoSize, // ImageInfoSize\r
+ FmpImageInfoBuf[Index], // ImageInfo\r
+ &DescriptorVer[Index], // DescriptorVersion\r
+ &FmpImageInfoCount, // DescriptorCount\r
+ &DescriptorSize[Index], // DescriptorSize\r
+ &PackageVersion, // PackageVersion\r
+ &PackageVersionName // PackageVersionName\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (FmpImageInfoBuf[Index]);\r
+ FmpImageInfoBuf[Index] = NULL;\r
+ continue;\r
+ }\r
+\r
+ if (PackageVersionName != NULL) {\r
+ FreePool (PackageVersionName);\r
+ PackageVersionName = NULL;\r
+ }\r
+\r
+ CopyGuid (&FmpVersions[FmpVersionsCount].ImageTypeId, &FmpImageInfoBuf[Index]->ImageTypeId);\r
+ FmpVersions[FmpVersionsCount].Version = FmpImageInfoBuf[Index]->Version;\r
+ FmpVersionsCount ++;\r
+ }\r
+\r
+ //\r
+ // Evaluate firmware image's depex, against the version of other Fmp instances.\r
+ //\r
+ if (Dependencies != NULL) {\r
+ IsSatisfied = EvaluateDependency (Dependencies, DependenciesSize, FmpVersions, FmpVersionsCount);\r
+ }\r
+\r
+ if (!IsSatisfied) {\r
+ DEBUG ((DEBUG_ERROR, "CheckFmpDependency: %g\'s dependency is not satisfied!\n", ImageTypeId));\r
+ goto cleanup;\r
+ }\r
+\r
+cleanup:\r
+ if (FmpImageInfoBuf != NULL) {\r
+ for (Index = 0; Index < NumberOfFmpInstance; Index ++) {\r
+ if (FmpImageInfoBuf[Index] != NULL) {\r
+ FreePool (FmpImageInfoBuf[Index]);\r
+ }\r
+ }\r
+ FreePool (FmpImageInfoBuf);\r
+ }\r
+\r
+ if (DescriptorVer != NULL) {\r
+ FreePool (DescriptorVer);\r
+ }\r
+\r
+ if (DescriptorSize != NULL) {\r
+ FreePool (DescriptorSize);\r
+ }\r
+\r
+ if (FmpVersions != NULL) {\r
+ FreePool (FmpVersions);\r
+ }\r
+\r
+ return IsSatisfied;\r
+}\r