[edk2-devel] [PATCH 5/5] FmpDevicePkg/FmpDxe: Add runtime FmpDxe driver

Bob Morgan via groups.io bobm=nvidia.com at groups.io
Wed Sep 22 23:59:54 UTC 2021


Adds a runtime version of FmpDxe driver to allow firmware updates after
ExitBootServices() is called.

Cc: Liming Gao <gaoliming at byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney at intel.com>
Cc: Guomin Jiang <guomin.jiang at intel.com>
Cc: Wei6 Xu <wei6.xu at intel.com>
Signed-off-by: Bob Morgan <bobm at nvidia.com>
---
 FmpDevicePkg/FmpDevicePkg.dsc         |  29 ++++
 FmpDevicePkg/FmpDxe/FmpDxe.c          |  34 +++--
 FmpDevicePkg/FmpDxe/FmpRuntimeDxe.c   | 185 ++++++++++++++++++++++++++
 FmpDevicePkg/FmpDxe/FmpRuntimeDxe.inf |  87 ++++++++++++
 FmpDevicePkg/FmpDxe/VariableSupport.c |   7 +
 5 files changed, 332 insertions(+), 10 deletions(-)
 create mode 100644 FmpDevicePkg/FmpDxe/FmpRuntimeDxe.c
 create mode 100644 FmpDevicePkg/FmpDxe/FmpRuntimeDxe.inf

diff --git a/FmpDevicePkg/FmpDevicePkg.dsc b/FmpDevicePkg/FmpDevicePkg.dsc
index b420f52a08..0f38e47ae4 100644
--- a/FmpDevicePkg/FmpDevicePkg.dsc
+++ b/FmpDevicePkg/FmpDevicePkg.dsc
@@ -29,6 +29,7 @@
   #
   DEFINE SYSTEM_FMP_ESRT_GUID   = B461B3BD-E62A-4A71-841C-50BA4E500267
   DEFINE DEVICE_FMP_ESRT_GUID   = 226034C4-8B67-4536-8653-D6EE7CE5A316
+  DEFINE RUNTIME_FMP_ESRT_GUID  = DECC975F-135A-426F-B667-ACA49E8CEF2A
 
   #
   # TRUE  - Build FmpDxe module for with storage access enabled
@@ -173,6 +174,34 @@
       CapsuleUpdatePolicyLib|FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf
   }
 
+  FmpDevicePkg/FmpDxe/FmpRuntimeDxe.inf {
+    <Defines>
+      #
+      # FILE_GUID is used as ESRT GUID
+      #
+      FILE_GUID = $(RUNTIME_FMP_ESRT_GUID)
+    <PcdsFixedAtBuild>
+      #
+      # Unicode name string that is used to populate FMP Image Descriptor for this capsule update module
+      #
+      gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageIdName|L"Sample Firmware Device"
+      #
+      # Certificates used to authenticate capsule update image
+      #
+      !include BaseTools/Source/Python/Pkcs7Sign/TestRoot.cer.gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr.inc
+    <PcdsPatchableInModule>
+      gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageTypeIdGuid|{GUID("$(RUNTIME_FMP_ESRT_GUID)")}
+    <LibraryClasses>
+      UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+
+      #
+      # Directly use a platform specific CapsuleUpdatePolicyLib instance.
+      # Only works for FmpDxe modules that are build from sources and included
+      # in a system firmware image.
+      #
+      CapsuleUpdatePolicyLib|FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf
+  }
+
   #
   # Add UEFI Target Based Unit Tests
   #
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.c b/FmpDevicePkg/FmpDxe/FmpDxe.c
index 6b0675ea38..2ebf99d68b 100644
--- a/FmpDevicePkg/FmpDxe/FmpDxe.c
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.c
@@ -84,6 +84,8 @@ const FIRMWARE_MANAGEMENT_PRIVATE_DATA  mFirmwareManagementPrivateDataTemplate =
   TRUE                                         // DependenciesSatisfied
 };
 
+FIRMWARE_MANAGEMENT_PRIVATE_DATA    *mPrivate = NULL;
+
 ///
 /// GUID that is used to create event used to lock the firmware storage device.
 ///
@@ -99,6 +101,11 @@ EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  mProgressFunc = NULL;
 ///
 CHAR16  *mImageIdName = NULL;
 
+///
+/// Optional function to determine if we're executing after ExitBootServices().
+///
+BOOLEAN (EFIAPI *mFmpAtRuntimeFunction) (VOID) = NULL;
+
 /**
   Callback function to report the process of the firmware updating.
 
@@ -1451,8 +1458,10 @@ cleanup:
   //
   // Need repopulate after SetImage is called to
   // update LastAttemptVersion and LastAttemptStatus.
+  // But don't force repopulate if executing at runtime.
   //
-  if (Private != NULL) {
+  if ((Private != NULL) &&
+      ((mFmpAtRuntimeFunction == NULL) || !mFmpAtRuntimeFunction ())) {
     Private->DescriptorPopulated = FALSE;
   }
 
@@ -1628,16 +1637,21 @@ InstallFmpInstance (
   }
 
   //
-  // Allocate FMP Protocol instance
+  // Allocate FMP Protocol instance if FmpRuntimeDxe didn't already do it
   //
-  Private = AllocateCopyPool (
-              sizeof (mFirmwareManagementPrivateDataTemplate),
-              &mFirmwareManagementPrivateDataTemplate
-              );
-  if (Private == NULL) {
-    DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to allocate memory for private structure.\n", mImageIdName));
-    Status = EFI_OUT_OF_RESOURCES;
-    goto cleanup;
+  if (mPrivate == NULL) {
+    Private = AllocateCopyPool (
+                sizeof (mFirmwareManagementPrivateDataTemplate),
+                &mFirmwareManagementPrivateDataTemplate
+                );
+    if (Private == NULL) {
+      DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to allocate memory for private structure.\n", mImageIdName));
+      Status = EFI_OUT_OF_RESOURCES;
+      goto cleanup;
+    }
+    mPrivate = Private;
+  } else {
+    Private = mPrivate;
   }
 
   //
diff --git a/FmpDevicePkg/FmpDxe/FmpRuntimeDxe.c b/FmpDevicePkg/FmpDxe/FmpRuntimeDxe.c
new file mode 100644
index 0000000000..d7e0a988d6
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpRuntimeDxe.c
@@ -0,0 +1,185 @@
+/** @file
+  Support for runtime Firmware Management Protocol
+
+  Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.<BR>
+  Copyright (c) Microsoft Corporation.<BR>
+  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/UefiRuntimeLib.h>
+#include "FmpDxe.h"
+
+EFI_EVENT                                       mAddressChangeEvent = NULL;
+
+///
+/// FILE_GUID from FmpRuntimeDxe.inf.  When FmpRuntimeDxe.inf is used in a platform,
+/// the FILE_GUID must always be overridden in the <Defines> section to provide
+/// the ESRT GUID value associated with the updatable firmware image.  A
+/// check is made in this module's driver entry point to verify that a
+/// new FILE_GUID value has been defined.
+///
+const EFI_GUID  mDefaultRuntimeModuleFileGuid = {
+  0xd12aece5, 0x7399, 0x4d05, { 0x88, 0xe4, 0x1c, 0x42, 0x84, 0xd8, 0xa0, 0x23 }
+};
+
+// FmpDxe module variables
+extern FIRMWARE_MANAGEMENT_PRIVATE_DATA         *mPrivate;
+extern CHAR16                                   *mImageIdName;
+extern const FIRMWARE_MANAGEMENT_PRIVATE_DATA   mFirmwareManagementPrivateDataTemplate;
+extern BOOLEAN                                  (EFIAPI *mFmpAtRuntimeFunction) (VOID);
+
+// FmpDxe ENTRY_POINT function prototype
+EFI_STATUS
+EFIAPI
+FmpDxeEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+// FmpDxe UNLOAD_IMAGE function prototype
+EFI_STATUS
+EFIAPI
+UninstallFmpInstance (
+  IN EFI_HANDLE  Handle
+  );
+
+/**
+  Event notification function that is invoked when the event GUID specified by
+  gEfiEventVirtualAddressChangeGuid is signaled.
+
+  @param[in] Event    Event whose notification function is being invoked.
+  @param[in] Context  The pointer to the notification function's context,
+                      which is implementation-dependent.
+**/
+VOID
+EFIAPI
+FmpRuntimeDxeAddressChangeEventNotify (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
+
+  if (Context == NULL) {
+    ASSERT (Context != NULL);
+    return;
+  }
+
+  Private = (FIRMWARE_MANAGEMENT_PRIVATE_DATA *) Context;
+
+  EfiConvertPointer (0x0, (VOID **) &Private->Descriptor.VersionName);
+  EfiConvertPointer (0x0, (VOID **) &Private->Descriptor.Dependencies);
+  EfiConvertPointer (0x0, (VOID **) &Private->FmpDeviceContext);
+  EfiConvertPointer (0x0, (VOID **) &Private->VersionVariableName);
+  EfiConvertPointer (0x0, (VOID **) &Private->LsvVariableName);
+  EfiConvertPointer (0x0, (VOID **) &Private->LastAttemptStatusVariableName);
+  EfiConvertPointer (0x0, (VOID **) &Private->LastAttemptVersionVariableName);
+  EfiConvertPointer (0x0, (VOID **) &Private->FmpStateVariableName);
+
+  EfiConvertPointer (0x0, (VOID **) &Private->Fmp.GetImageInfo);
+  EfiConvertPointer (0x0, (VOID **) &Private->Fmp.GetImage);
+  EfiConvertPointer (0x0, (VOID **) &Private->Fmp.SetImage);
+  EfiConvertPointer (0x0, (VOID **) &Private->Fmp.CheckImage);
+  EfiConvertPointer (0x0, (VOID **) &Private->Fmp.GetPackageInfo);
+  EfiConvertPointer (0x0, (VOID **) &Private->Fmp.SetPackageInfo);
+
+  EfiConvertPointer (0x0, (VOID **) &mPrivate);
+  EfiConvertPointer (0x0, (VOID **) &mImageIdName);
+  EfiConvertPointer (0x0, (VOID **) &mFmpAtRuntimeFunction);
+}
+
+/**
+  Function to uninstall FMP instance.
+
+  @param[in]  Handle  The device handle to uninstall.
+
+  @retval  EFI_SUCCESS            FMP Uninstalled
+  @retval  other                  Error from UninstallFmpInstance().
+
+**/
+EFI_STATUS
+EFIAPI
+UninstallRuntimeFmpInstance (
+  IN EFI_HANDLE  Handle
+  )
+{
+  EFI_STATUS                        Status;
+
+  if (mAddressChangeEvent != NULL) {
+    gBS->CloseEvent (mAddressChangeEvent);
+  }
+
+  Status = UninstallFmpInstance (Handle);
+
+  return Status;
+}
+
+/**
+  Entry point for runtime FmpDxe.  Performs runtime-only initialization and
+  then calls regular FmpDxe initialization.
+
+  @param[in] ImageHandle  Image handle this driver.
+  @param[in] SystemTable  Pointer to SystemTable.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpRuntimeDxeEntryPoint (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // Verify that a new FILE_GUID value has been provided in the <Defines>
+  // section of this module.  The FILE_GUID is the ESRT GUID that must be
+  // unique for each updatable firmware image.
+  //
+  if (CompareGuid (&mDefaultRuntimeModuleFileGuid, &gEfiCallerIdGuid)) {
+    DEBUG ((DEBUG_ERROR, "FmpRuntimeDxe: Use of default FILE_GUID detected.  FILE_GUID must be set to a unique value.\n"));
+    ASSERT (FALSE);
+    return EFI_UNSUPPORTED;
+  }
+
+  //
+  // Allocate and initialize private data structure from runtime pool
+  //
+  mPrivate = AllocateRuntimeCopyPool (sizeof (mFirmwareManagementPrivateDataTemplate),
+                                      &mFirmwareManagementPrivateDataTemplate);
+  if (mPrivate == NULL) {
+    DEBUG ((DEBUG_ERROR, "FmpRuntimeDxe: Failed to allocate memory for private structure.\n"));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  //
+  // Create and register notify function for virtual address change event
+  //
+  Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,
+                               TPL_NOTIFY,
+                               FmpRuntimeDxeAddressChangeEventNotify,
+                               mPrivate,
+                               &gEfiEventVirtualAddressChangeGuid,
+                               &mAddressChangeEvent);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "FmpRuntimeDxe: Failed to register address change notification.  Status = %r\n",
+            Status));
+    return Status;
+  }
+
+  //
+  // Initialize FmpDxe
+  //
+  Status = FmpDxeEntryPoint (ImageHandle, SystemTable);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "FmpRuntimeDxe: Failed to initialize FmpDxe: %r\n", Status));
+  }
+
+  // Set AtRuntime function pointer
+  mFmpAtRuntimeFunction = EfiAtRuntime;
+
+  return Status;
+}
diff --git a/FmpDevicePkg/FmpDxe/FmpRuntimeDxe.inf b/FmpDevicePkg/FmpDxe/FmpRuntimeDxe.inf
new file mode 100644
index 0000000000..fff779bc4d
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpRuntimeDxe.inf
@@ -0,0 +1,87 @@
+## @file
+#  Produces a runtime Firmware Management Protocol that supports updates
+#  to a firmware image stored in a firmware device with platform and
+#  firmware device specific information provided through PCDs and libraries.
+#
+#  Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.<BR>
+#  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+#  Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION                    = 1.27
+  BASE_NAME                      = FmpDxe
+  MODULE_UNI_FILE                = FmpDxe.uni
+  FILE_GUID                      = D12AECE5-7399-4D05-88E4-1C4284D8A023
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = FmpRuntimeDxeEntryPoint
+  UNLOAD_IMAGE                   = UninstallRuntimeFmpInstance
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64
+#
+
+[Sources]
+  FmpRuntimeDxe.c
+  FmpDxe.c
+  FmpDxe.h
+  DetectTestKey.c
+  VariableSupport.h
+  VariableSupport.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  CryptoPkg/CryptoPkg.dec
+  FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+  UefiDriverEntryPoint
+  DebugLib
+  BaseLib
+  BaseMemoryLib
+  UefiBootServicesTableLib
+  MemoryAllocationLib
+  PrintLib
+  UefiLib
+  BaseCryptLib
+  FmpAuthenticationLib
+  FmpDeviceLib
+  FmpPayloadHeaderLib
+  CapsuleUpdatePolicyLib
+  FmpDependencyLib
+  FmpDependencyCheckLib
+  FmpDependencyDeviceLib
+  UefiRuntimeLib
+
+[Guids]
+  gEfiEndOfDxeEventGroupGuid
+  gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+  gEdkiiVariableLockProtocolGuid                ## CONSUMES
+  gEfiFirmwareManagementProtocolGuid            ## PRODUCES
+  gEdkiiFirmwareManagementProgressProtocolGuid  ## PRODUCES
+
+[Pcd]
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceStorageAccessEnable              ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageIdName                      ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceBuildTimeLowestSupportedVersion  ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceLockEventGuid                    ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressWatchdogTimeInSeconds    ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressColor                    ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr               ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceTestKeySha256Digest              ## CONSUMES
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageTypeIdGuid                  ## CONSUMES
+  gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed                            ## SOMETIMES_PRODUCES
+
+[Depex]
+  gEfiVariableWriteArchProtocolGuid AND gEdkiiVariableLockProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+  FmpDxeExtra.uni
diff --git a/FmpDevicePkg/FmpDxe/VariableSupport.c b/FmpDevicePkg/FmpDxe/VariableSupport.c
index 86dd5b203b..13fc638618 100644
--- a/FmpDevicePkg/FmpDxe/VariableSupport.c
+++ b/FmpDevicePkg/FmpDxe/VariableSupport.c
@@ -12,6 +12,8 @@
 #include "FmpDxe.h"
 #include "VariableSupport.h"
 
+extern BOOLEAN (EFIAPI *mFmpAtRuntimeFunction) (VOID);
+
 /**
   Retrieve the value of a 32-bit UEFI Variable specified by VariableName and
   a GUID of gEfiCallerIdGuid.
@@ -103,6 +105,11 @@ GetFmpControllerState (
   FMP_CONTROLLER_STATE  *FmpControllerState;
   UINTN                 Size;
 
+  // FmpState variable not accessible at runtime
+  if ((mFmpAtRuntimeFunction != NULL) && mFmpAtRuntimeFunction ()) {
+    return NULL;
+  }
+
   FmpControllerState = NULL;
   Size               = 0;
   Status = GetVariable2 (
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#80994): https://edk2.groups.io/g/devel/message/80994
Mute This Topic: https://groups.io/mt/85803594/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-





More information about the edk2-devel-archive mailing list