From: "Xu, Wei6" <wei6.xu@intel.com>
To: devel@edk2.groups.io
Cc: Michael D Kinney <michael.d.kinney@intel.com>,
Liming Gao <liming.gao@intel.com>,
Sean Brogan <sean.brogan@microsoft.com>
Subject: [edk2-devel] [PATCH 3/4] FmpDevicePkg: Add FmpDependencyCheck library class and instances
Date: Tue, 28 Apr 2020 21:25:29 +0800 [thread overview]
Message-ID: <20200428132530.4068-4-wei6.xu@intel.com> (raw)
In-Reply-To: <20200428132530.4068-1-wei6.xu@intel.com>
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2696
* This library class provides services to check Fmp Capsule Dependency
during updating firmware image, save the dependency to Fmp device after
update succeed and retrieve the dependency from Fmp device.
* Add FmpDependencyCheck instance, and provide PCD as an option to
disable Fmp Capsule dependency feature support.
* Add NULL instance as an option to skip the dependency check.
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Signed-off-by: Wei6 Xu <wei6.xu@intel.com>
---
FmpDevicePkg/FmpDevicePkg.dec | 9 +
FmpDevicePkg/FmpDevicePkg.dsc | 3 +
FmpDevicePkg/FmpDevicePkg.uni | 4 +-
.../Include/Library/FmpDependencyCheckLib.h | 71 +++
.../FmpDependencyCheckLib/FmpDependencyCheckLib.c | 533 +++++++++++++++++++++
.../FmpDependencyCheckLib.inf | 51 ++
.../FmpDependencyCheckLib.uni | 13 +
.../FmpDependencyCheckLibNull.c | 74 +++
.../FmpDependencyCheckLibNull.inf | 30 ++
.../FmpDependencyCheckLibNull.uni | 13 +
10 files changed, 800 insertions(+), 1 deletion(-)
create mode 100644 FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni
create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
create mode 100644 FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni
diff --git a/FmpDevicePkg/FmpDevicePkg.dec b/FmpDevicePkg/FmpDevicePkg.dec
index 4947008346..4905d3b581 100644
--- a/FmpDevicePkg/FmpDevicePkg.dec
+++ b/FmpDevicePkg/FmpDevicePkg.dec
@@ -37,10 +37,14 @@
## @libraryclass Provides generic services to support capsule dependency
# expression evaluation.
FmpDependencyLib|Include/Library/FmpDependencyLib.h
+ ## @libraryclass Provides platform specific services to support dependency
+ # check during update of firmware image.
+ FmpDependencyCheckLib|Include/Library/FmpDependencyCheckLib.h
+
[LibraryClasses.Common.Private]
## @libraryclass Provides services to retrieve values from a capsule's FMP
# Payload Header. The structure is not included in the
# library class. Instead, services are provided to retrieve
# information from the FMP Payload Header. If information is
@@ -115,10 +119,15 @@
## The Image Type ID to use if one is not provided by FmpDeviceLib. If this
# PCD is not a valid GUID value, then gEfiCallerIdGuid is used.
# @Prompt Firmware Device Image Type ID
gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageTypeIdGuid|{0}|VOID*|0x40000010
+ ## Indicate whether to perform the Fmp dependency check during the update of a
+ # firmware device.
+ # @Prompt Fmp Dependency Check Enable
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDependencyCheckEnable|FALSE|BOOLEAN|0x40000013
+
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
## One or more PKCS7 certificates used to verify a firmware device capsule
# update image. Encoded using the Variable-Length Opaque Data format of RFC
# 4506 External Data Representation Standard (XDR). The default value is
# empty with 0 certificates.
diff --git a/FmpDevicePkg/FmpDevicePkg.dsc b/FmpDevicePkg/FmpDevicePkg.dsc
index 49c6ff3a30..7e80806171 100644
--- a/FmpDevicePkg/FmpDevicePkg.dsc
+++ b/FmpDevicePkg/FmpDevicePkg.dsc
@@ -61,10 +61,11 @@
FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
CapsuleUpdatePolicyLib|FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf
FmpPayloadHeaderLib|FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf
FmpDeviceLib|FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf
FmpDependencyLib|FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
+ FmpDependencyCheckLib|FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
[LibraryClasses.ARM, LibraryClasses.AARCH64]
#
# It is not possible to prevent the ARM compiler for generic intrinsic functions.
@@ -90,10 +91,12 @@
FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf
FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolicyLibOnProtocol.inf
FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf
FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf
FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
+ FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
+ FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
FmpDevicePkg/FmpDxe/FmpDxeLib.inf
#
# Modules
#
diff --git a/FmpDevicePkg/FmpDevicePkg.uni b/FmpDevicePkg/FmpDevicePkg.uni
index 263f88078b..52e5ba08af 100644
--- a/FmpDevicePkg/FmpDevicePkg.uni
+++ b/FmpDevicePkg/FmpDevicePkg.uni
@@ -78,6 +78,8 @@
"If this PCD is not a valid GUID value, then the firmware device is locked"
"when gEfiEndOfDxeEventGroupGuid (End of DXE Phase) is signaled. The"
"default value is empty, so by default the firmware device is locked at the"
"end of the DXE phase."
-
+#string STR_gFmpDevicePkgTokenSpaceGuid_PcdFmpDependencyCheckEnable_PROMPT #language en-US "Fmp Dependency Check Enable"
+#string STR_gFmpDevicePkgTokenSpaceGuid_PcdFmpDependencyCheckEnable_HELP #language en-US "Indicate whether to perform the Fmp dependency check during the update of a"
+ "firmware device."
diff --git a/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h b/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
new file mode 100644
index 0000000000..fe329937d1
--- /dev/null
+++ b/FmpDevicePkg/Include/Library/FmpDependencyCheckLib.h
@@ -0,0 +1,71 @@
+/** @file
+ Fmp Capsule Dependency support functions for Firmware Management Protocol based
+ firmware updates.
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FMP_DEPENDENCY_CHECK_LIB__
+#define __FMP_DEPENDENCY_CHECK_LIB__
+
+#include <PiDxe.h>
+#include <Protocol/FirmwareManagement.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 CONST EFI_GUID ImageTypeId,
+ IN CONST UINT32 Version,
+ IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL
+ IN CONST UINT32 DependenciesSize OPTIONAL
+ );
+
+/**
+ Save dependency to Fmp device.
+
+ @param[in] Depex Fmp dependency.
+ @param[in] DepexSize Size, in bytes, of the Fmp dependency.
+
+ @retval EFI_SUCCESS Save Fmp dependency succeeds.
+ @retval EFI_UNSUPPORTED Save Fmp dependency is not supported.
+ @retval Others Save Fmp dependency fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveFmpDependency (
+ IN EFI_FIRMWARE_IMAGE_DEP *Depex,
+ IN UINT32 DepexSize
+ );
+
+/**
+ Get dependency from the Fmp device.
+
+ @param[out] DepexSize Size, in bytes, of the dependency.
+
+ @retval The pointer to dependency.
+ @retval NULL
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetFmpDependency (
+ OUT UINT32 *DepexSize OPTIONAL
+ );
+
+#endif
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
new file mode 100644
index 0000000000..05804d6d19
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.c
@@ -0,0 +1,533 @@
+/** @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/FmpDeviceLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/PrintLib.h>
+#include <Protocol/VariableLock.h>
+
+#define FMP_DEPENDENCY_VARIABLE_NAME L"FmpDepex"
+
+/**
+ Check if there is dependency in EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+
+ @param[in] FmpImageInfoBuf Pointer to EFI Firmware Image Descriptor.
+ @param[in] DescriptorVer Version of the descriptor.
+ @param[in] DescriptorSize Size of the Descriptor.
+
+ @retval TRUE There is dependency in descriptor.
+ @retval FALSE There is no dependency in descriptor.
+
+**/
+BOOLEAN
+DoDependencyExist (
+ IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf,
+ IN UINT32 DescriptorVer,
+ IN UINTN DescriptorSize
+ )
+{
+ //
+ // Descriptor version must be greater than or equal to 4.
+ //
+ if (DescriptorVer < 4) {
+ return FALSE;
+ }
+
+ //
+ // Dependency must be enabled.
+ //
+ if ((FmpImageInfoBuf->AttributesSetting & IMAGE_ATTRIBUTE_DEPENDENCY) == 0) {
+ return FALSE;
+ }
+
+ //
+ // Descriptor size must be large enough to reference the 'Dependencies' field.
+ //
+ if (DescriptorSize < OFFSET_OF(EFI_FIRMWARE_IMAGE_DESCRIPTOR, Dependencies)) {
+ return FALSE;
+ }
+
+ //
+ // Dependencies must not be NULL.
+ //
+ if (FmpImageInfoBuf->Dependencies == NULL) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ 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 CONST EFI_GUID ImageTypeId,
+ IN CONST UINT32 Version,
+ IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL
+ IN CONST UINT32 DependenciesSize OPTIONAL
+ )
+{
+ 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 DepexSize;
+ UINTN NumberOfFmpInstance;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR **FmpImageInfoBuf;
+ FMP_DEPEX_CHECK_VERSION_DATA *FmpVersions;
+ UINTN FmpVersionsCount;
+ BOOLEAN IsSatisfied;
+
+ if (!FeaturePcdGet (PcdFmpDependencyCheckEnable)) {
+ return TRUE;
+ }
+
+ 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 ++;
+ }
+
+ //
+ // Step 1 - 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;
+ }
+
+ //
+ // Step 2 - Evaluate the depex of all other Fmp instances, against the new version in
+ // the firmware image.
+ //
+
+ //
+ // Update the new version to FmpVersions.
+ //
+ for (Index = 0; Index < FmpVersionsCount; Index ++) {
+ if (CompareGuid (&ImageTypeId, &FmpVersions[Index].ImageTypeId)) {
+ FmpVersions[Index].Version = Version;
+ break;
+ }
+ }
+
+ //
+ // Evaluate the Dependencies one by one.
+ //
+ for (Index = 0; Index < NumberOfFmpInstance; Index ++) {
+ if (FmpImageInfoBuf[Index] != NULL) {
+ //
+ // Skip the Fmp instance to be "SetImage".
+ //
+ if (CompareGuid (&ImageTypeId, &FmpImageInfoBuf[Index]->ImageTypeId)) {
+ continue;
+ }
+ //
+ // Check if dependency exists in the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ //
+ if (DoDependencyExist (FmpImageInfoBuf[Index], DescriptorVer[Index], DescriptorSize[Index])) {
+ //
+ // Get the size of dependency.
+ // Assume that the dependencies in EFI_FIRMWARE_IMAGE_DESCRIPTOR is validated when PopulateDescriptor().
+ //
+ DepexSize = GetDependencySize (FmpImageInfoBuf[Index]->Dependencies);
+ if (DepexSize > 0) {
+ IsSatisfied = EvaluateDependency (FmpImageInfoBuf[Index]->Dependencies, DepexSize, FmpVersions, FmpVersionsCount);
+ if (!IsSatisfied) {
+ DEBUG ((DEBUG_ERROR, "CheckFmpDependency: %g\'s dependency is not satisfied!\n", FmpImageInfoBuf[Index]->ImageTypeId));
+ break;
+ }
+ }
+ }
+ }
+ }
+
+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;
+}
+
+/**
+ Generates a Null-terminated Unicode string UEFI Variable name from a base name
+ and a hardware instance. If the hardware instance value is 0, then the base
+ name is returned. If the hardware instance value is non-zero, then the 64-bit
+ hardware instance value is converted to a 16 character hex string and appended
+ to base name. The UEFI Variable name returned is allocated using the UEFI
+ Boot Service AllocatePool().
+
+ @return Pointer to the allocated UEFI Variable name. Returns NULL if the
+ UEFI Variable can not be allocated.
+**/
+static
+CHAR16 *
+GenerateFmpDepexVariableName (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ CHAR16 *VariableName;
+ UINT64 HardwareInstance;
+
+ //
+ // Allocate Unicode string with room for BaseVariableName and a 16 digit
+ // hexadecimal value for the HardwareInstance value.
+ //
+ Size = StrSize (FMP_DEPENDENCY_VARIABLE_NAME) + 16 * sizeof (CHAR16);
+ VariableName = AllocateCopyPool (Size, FMP_DEPENDENCY_VARIABLE_NAME);
+ if (VariableName == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDependencyCheckLib: Failed to generate variable name %s.\n", FMP_DEPENDENCY_VARIABLE_NAME));
+ return VariableName;
+ }
+
+ //
+ // Get the hardware instance from FmpDeviceLib
+ //
+ Status = FmpDeviceGetHardwareInstance (&HardwareInstance);
+ if (EFI_ERROR (Status)) {
+ return VariableName;
+ }
+
+ UnicodeValueToStringS (
+ &VariableName[StrLen(FMP_DEPENDENCY_VARIABLE_NAME)],
+ Size,
+ PREFIX_ZERO | RADIX_HEX,
+ HardwareInstance,
+ 16
+ );
+ return VariableName;
+}
+
+/**
+ Save dependency to Fmp device.
+
+ @param[in] Depex Fmp dependency.
+ @param[in] DepexSize Size, in bytes, of the Fmp dependency.
+
+ @retval EFI_SUCCESS Save Fmp dependency succeeds.
+ @retval EFI_UNSUPPORTED Save Fmp dependency is not supported.
+ @retval Others Save Fmp dependency fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveFmpDependency (
+ IN EFI_FIRMWARE_IMAGE_DEP *Depex,
+ IN UINT32 DepexSize
+ )
+{
+ EFI_STATUS Status;
+ CHAR16 *VariableName;
+
+ if (!FeaturePcdGet (PcdFmpDependencyCheckEnable)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Generate dependency variable name by HardwareInstance.
+ //
+ VariableName = GenerateFmpDepexVariableName ();
+ if (VariableName == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Save dependency to variable.
+ //
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ DepexSize,
+ (VOID *) Depex
+ );
+
+ if (VariableName != NULL) {
+ FreePool (VariableName);
+ }
+
+ return Status;
+}
+
+/**
+ Get dependency from the Fmp device.
+
+ @param[out] DepexSize Size, in bytes, of the dependency.
+
+ @retval The pointer to dependency.
+ @retval NULL
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetFmpDependency (
+ OUT UINT32 *DepexSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_IMAGE_DEP *Depex;
+ UINTN Size;
+ CHAR16 *VariableName;
+
+ if (DepexSize != NULL) {
+ *DepexSize = 0;
+ }
+
+ if (!FeaturePcdGet (PcdFmpDependencyCheckEnable)) {
+ return NULL;
+ }
+
+ Depex = NULL;
+ Size = 0;
+
+ //
+ // Generate dependency variable name by HardwareInstance.
+ //
+ VariableName = GenerateFmpDepexVariableName ();
+ if (VariableName == NULL) {
+ return NULL;
+ }
+
+ //
+ // Get dependency from variable.
+ //
+ Status = GetVariable2 (
+ VariableName,
+ &gEfiCallerIdGuid,
+ (VOID **) &Depex,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ //
+ // Treat EFI_NOT_FOUND as no dependency.
+ // Other errors are treated as dependency evaluates to FALSE.
+ //
+ Size = 2;
+ Depex = AllocatePool (Size * sizeof(UINT8));
+ if (Depex != NULL) {
+ Depex->Dependencies[0] = EFI_FMP_DEP_FALSE;
+ Depex->Dependencies[1] = EFI_FMP_DEP_END;
+ }
+ }
+ }
+
+ if (DepexSize != NULL) {
+ *DepexSize = (UINT32) Size;
+ }
+
+ if (VariableName != NULL) {
+ FreePool (VariableName);
+ }
+
+ return Depex;
+}
+
+/**
+ The constructor function to lock FmpDepex variable.
+
+ @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 succeeds.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDependencyCheckLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ CHAR16 *VariableName;
+
+ VariableLock = NULL;
+ Status = gBS->LocateProtocol (
+ &gEdkiiVariableLockProtocolGuid,
+ NULL,
+ (VOID **)&VariableLock
+ );
+ if (EFI_ERROR (Status) || VariableLock == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDependencyCheckLib: Failed to locate Variable Lock Protocol (%r).\n", Status));
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Generate dependency variable name by HardwareInstance.
+ //
+ VariableName = GenerateFmpDepexVariableName ();
+ if (VariableName == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ Status = VariableLock->RequestToLock (
+ VariableLock,
+ VariableName,
+ &gEfiCallerIdGuid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDependencyCheckLib: Failed to lock variable %s (%r)\n", VariableName, Status));
+ }
+
+ if (VariableName != NULL) {
+ FreePool (VariableName);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
new file mode 100644
index 0000000000..f08516cb28
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf
@@ -0,0 +1,51 @@
+## @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
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpDependencyCheckLib
+ MODULE_UNI_FILE = FmpDependencyCheckLib.uni
+ FILE_GUID = 8296D425-3095-4CFE-88D8-B0A44DB174A8
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FmpDependencyCheckLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = FmpDependencyCheckLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ FmpDependencyCheckLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ FmpDependencyLib
+ FmpDeviceLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ PcdLib
+ PrintLib
+
+[Pcd]
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDependencyCheckEnable
+
+[Protocols]
+ gEdkiiVariableLockProtocolGuid ## CONSUMES
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni
new file mode 100644
index 0000000000..c6369e2277
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.uni
@@ -0,0 +1,13 @@
+// /** @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
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "FMP Dependency Check Lib"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides FMP capsule dependency check services when updating the firmware image of a FMP device."
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
new file mode 100644
index 0000000000..d2eea04c15
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.c
@@ -0,0 +1,74 @@
+/** @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/FmpDependencyCheckLib.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 CONST EFI_GUID ImageTypeId,
+ IN CONST UINT32 Version,
+ IN CONST EFI_FIRMWARE_IMAGE_DEP *Dependencies, OPTIONAL
+ IN CONST UINT32 DependenciesSize OPTIONAL
+ )
+{
+ return TRUE;
+}
+
+/**
+ Save dependency to Fmp device.
+
+ @param[in] Depex Fmp dependency.
+ @param[in] DepexSize Size, in bytes, of the Fmp dependency.
+
+ @retval EFI_SUCCESS Save Fmp dependency succeeds.
+ @retval EFI_UNSUPPORTED Save Fmp dependency is not supported.
+ @retval Others Save Fmp dependency fails.
+
+**/
+EFI_STATUS
+EFIAPI
+SaveFmpDependency (
+ IN EFI_FIRMWARE_IMAGE_DEP *Depex,
+ IN UINT32 DepexSize
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Get dependency from the Fmp device.
+
+ @param[out] DepexSize Size, in bytes, of the dependency.
+
+ @retval The pointer to dependency.
+ @retval NULL
+
+**/
+EFI_FIRMWARE_IMAGE_DEP*
+EFIAPI
+GetFmpDependency (
+ OUT UINT32 *DepexSize OPTIONAL
+ )
+{
+ return NULL;
+}
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
new file mode 100644
index 0000000000..363c52d85b
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
@@ -0,0 +1,30 @@
+## @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
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpDependencyCheckLibNull
+ MODULE_UNI_FILE = FmpDependencyCheckLibNull.uni
+ FILE_GUID = D63F3166-9CBC-4AC2-8F23-8818E42EA2BD
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = FmpDependencyCheckLib|DXE_DRIVER UEFI_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+ FmpDependencyCheckLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ FmpDevicePkg/FmpDevicePkg.dec
diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni
new file mode 100644
index 0000000000..c6369e2277
--- /dev/null
+++ b/FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.uni
@@ -0,0 +1,13 @@
+// /** @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
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "FMP Dependency Check Lib"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides FMP capsule dependency check services when updating the firmware image of a FMP device."
--
2.16.2.windows.1
next prev parent reply other threads:[~2020-04-28 13:25 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-04-28 13:25 [edk2-devel] [PATCH 0/4] FmpDevicePkg: Move capsule dependency implement to library Xu, Wei6
2020-04-28 13:25 ` [edk2-devel] [PATCH 1/4] FmpDevicePkg: Add FmpDependency library class and BASE instance Xu, Wei6
2020-04-28 13:25 ` [edk2-devel] [PATCH 2/4] FmpDevicePkg/Test: Add FmpDependencyLib unit test Xu, Wei6
2020-04-28 13:25 ` Xu, Wei6 [this message]
2020-04-28 13:25 ` [edk2-devel] [PATCH 4/4] FmpDevicePkg/FmpDxe: Use FmpDependencyLib and FmpDependencyCheckLib Xu, Wei6
2020-05-06 14:08 ` [edk2-devel] [PATCH 0/4] FmpDevicePkg: Move capsule dependency implement to library Liming Gao
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200428132530.4068-4-wei6.xu@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox