From: "Bob Morgan" <bobm@nvidia.com>
To: <devel@edk2.groups.io>
Cc: <gaoliming@byosoft.com.cn>, <michael.d.kinney@intel.com>,
<guomin.jiang@intel.com>, <wei6.xu@intel.com>,
Bob Morgan <bobm@nvidia.com>
Subject: [PATCH 5/5] FmpDevicePkg/FmpDxe: Add runtime FmpDxe driver
Date: Wed, 22 Sep 2021 17:59:54 -0600 [thread overview]
Message-ID: <b15bc242c1b5a250ee977209034c6c4dccc1901a.1632353122.git.bobm@nvidia.com> (raw)
In-Reply-To: <cover.1632353122.git.bobm@nvidia.com>
Adds a runtime version of FmpDxe driver to allow firmware updates after
ExitBootServices() is called.
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Cc: Wei6 Xu <wei6.xu@intel.com>
Signed-off-by: Bob Morgan <bobm@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
next prev parent reply other threads:[~2021-09-23 0:01 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-22 23:59 [PATCH 0/5] FmpDevicePkg: Add support for runtime FmpDxe driver Bob Morgan
2021-09-22 23:59 ` [PATCH 1/5] FmpDevicePkg/FmpDeviceLibNull: Add DXE_RUNTIME_DRIVER support Bob Morgan
2021-09-22 23:59 ` [PATCH 2/5] FmpDevicePkg/FmpPayloadHeaderLibV1: " Bob Morgan
2021-09-22 23:59 ` [PATCH 3/5] FmpDevicePkg/FmpDependencyCheckLibNull: " Bob Morgan
2021-09-22 23:59 ` [PATCH 4/5] FmpDevicePkg/FmpDependencyDeviceLibNull: " Bob Morgan
2021-09-22 23:59 ` Bob Morgan [this message]
2021-09-24 0:56 ` 回复: [edk2-devel] [PATCH 0/5] FmpDevicePkg: Add support for runtime FmpDxe driver gaoliming
2021-09-24 2:18 ` Bob Morgan
[not found] ` <16A7A0910520505F.360@groups.io>
2021-10-20 19:41 ` Bob Morgan
2021-10-21 1:53 ` 回复: " gaoliming
[not found] ` <16AFE8DE7122BA33.23075@groups.io>
2021-11-02 1:11 ` gaoliming
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=b15bc242c1b5a250ee977209034c6c4dccc1901a.1632353122.git.bobm@nvidia.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