* [PATCH 00/12] arm64: FF-A runtime transport for EFI variables
@ 2026-04-24 17:31 Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 01/12] efi_loader: add runtime memset helper Harsimran Singh Tungal
` (14 more replies)
0 siblings, 15 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Hi all,
This series adds FF-A runtime transport support so EFI variable runtime
services can communicate with the secure world after ExitBootServices().
It also extends tests, docs, and board configs to validate the runtime
path and keep boot‑time behavior aligned with the runtime flow.
Changes in this series:
- Add EFI runtime-safe memset helper and FF-A runtime transport support.
- Implement FF-A runtime communication in the EFI variable TEE backend.
- Enable runtime variable operations and move helpers to avoid conflicts.
- Add sandbox runtime transport tests and metadata reuse.
- Extend EFI selftests for runtime variables and bootefi selftest config.
- Document the FF-A runtime transport and selftest behavior.
- Align boot‑time cache maintenance with the runtime path.
Harsimran Singh Tungal (12):
efi_loader: add runtime memset helper
arm-ffa: add FF-A bus runtime support
efi_loader: add FF-A runtime support in EFI variable TEE driver
efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A
transport
efi_loader: move runtime GetVariable() helpers to efi_variable.c
corstone1000: enable bootefi selftest
efi: selftest: add runtime variable tests with non-volatile storage
test: dm: add sandbox FF-A runtime transport tests
sandbox: ffa: share synthetic partition metadata via macros
doc: arm64: document FF-A runtime path for EFI variables
doc: bootefi: note two-phase runtime variables selftest
efi_loader: align FF-A cache maintenance with runtime path
arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +-
configs/corstone1000_defconfig | 3 +
doc/arch/arm64.ffa.rst | 92 ++-
doc/usage/cmd/armffa.rst | 11 +
doc/usage/cmd/bootefi.rst | 12 +
drivers/firmware/arm-ffa/Kconfig | 11 +
drivers/firmware/arm-ffa/Makefile | 4 +-
drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 ++++++++
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 +--
drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 48 +-
include/arm_ffa.h | 16 +-
include/arm_ffa_priv.h | 24 +-
include/arm_ffa_runtime.h | 183 +++++
include/efi_loader.h | 3 +
lib/charset.c | 2 +-
lib/efi_loader/efi_runtime.c | 21 +
lib/efi_loader/efi_var_common.c | 24 -
lib/efi_loader/efi_variable.c | 24 +
lib/efi_loader/efi_variable_tee.c | 686 +++++++++++++++++-
.../efi_selftest_variables_runtime.c | 106 ++-
test/dm/Makefile | 3 +-
test/dm/ffa.c | 6 +-
test/dm/ffa_runtime.c | 82 +++
24 files changed, 1602 insertions(+), 189 deletions(-)
create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
create mode 100644 include/arm_ffa_runtime.h
create mode 100644 test/dm/ffa_runtime.c
--
2.34.1
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH 01/12] efi_loader: add runtime memset helper
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-27 7:54 ` Ilias Apalodimas
2026-04-28 18:08 ` Simon Glass
2026-04-24 17:31 ` [PATCH 02/12] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
` (13 subsequent siblings)
14 siblings, 2 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Add efi_memset_runtime() for EFI runtime paths
This keeps buffer initialization in runtime-resident code after
ExitBootServices() and avoids relying on non-runtime helpers.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
include/efi_loader.h | 3 +++
lib/efi_loader/efi_runtime.c | 21 +++++++++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3a4d502631c..63944192aeb 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -1151,6 +1151,9 @@ void efi_memcpy_runtime(void *dest, const void *src, size_t n);
/* runtime implementation of memcmp() */
int efi_memcmp_runtime(const void *s1, const void *s2, size_t n);
+/* runtime implementation of memset */
+__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n);
+
/* commonly used helper functions */
u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
unsigned int index);
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 73d4097464c..d9604399209 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -233,6 +233,27 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
return 0;
}
+/**
+ * efi_memset_runtime() - fill a memory region with a byte value
+ *
+ * At runtime memset() is not available.
+ *
+ * @dest: pointer to the block of memory to fill.
+ * @c: value to be set. The value is passed as an int, but the
+ * function fills the block of memory using the u8 conversion of this value.
+ * @n: number of bytes to be set to the value.
+ * Return: dest is returned
+ */
+__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
+{
+ u8 *d = dest;
+
+ for (; n; --n)
+ *d++ = c;
+
+ return dest;
+}
+
/**
* efi_update_table_header_crc32() - Update crc32 in table header
*
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 02/12] arm-ffa: add FF-A bus runtime support
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 01/12] efi_loader: add runtime memset helper Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:10 ` Simon Glass
2026-04-24 17:31 ` [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
` (12 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Enable FF-A runtime transport for EFI services
This patch introduces the FF-A runtime infrastructure that enables
U-Boot to use the Arm Firmware Framework for Arm A-profile (FF-A)
transport layer after ExitBootServices().
The runtime transport provides persistent, runtime-safe
implementations of key FF-A functions used by EFI runtime services.
Summary of key changes:
-----------------------
- Add drivers/firmware/arm-ffa/arm-ffa-runtime.c implementing FF-A
runtime operations.
- Introduce include/arm_ffa_runtime.h exporting FF-A runtime
functions and data structures.
- Move FF-A error mapping into runtime context.
- Introduce invoke_ffa_fn_runtime() as runtime safe SMC wrapper.
- Add runtime SMC wrapper for sandbox emulation.
- Add ARM_FFA_RT_MODE Kconfig to enable runtime support.
- Register ExitBootServices hook for runtime context.
- Copy ffa_priv runtime fields into resident storage at
ExitBootServices.
- Extend Makefile to build arm-ffa-runtime.c.
All runtime functions and global data are tagged with __efi_runtime or
__efi_runtime_data to ensure persistence after ExitBootServices().
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
drivers/firmware/arm-ffa/Kconfig | 11 +
drivers/firmware/arm-ffa/Makefile | 4 +-
drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 +++++++++++++++++++++
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 ++------
drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 +
include/arm_ffa.h | 16 +-
include/arm_ffa_priv.h | 24 +-
include/arm_ffa_runtime.h | 183 +++++++++++++
test/dm/ffa.c | 6 +-
10 files changed, 551 insertions(+), 119 deletions(-)
create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
create mode 100644 include/arm_ffa_runtime.h
diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
index 3706a889305..7aaf25fdb58 100644
--- a/drivers/firmware/arm-ffa/Kconfig
+++ b/drivers/firmware/arm-ffa/Kconfig
@@ -18,6 +18,9 @@ config ARM_FFA_TRANSPORT
The FF-A support in U-Boot is based on FF-A specification v1.0 and uses SMC32
calling convention.
+ The FF-A bus also provides a runtime layer to keep a minimal set of FF-A
+ operations available after ExitBootServices().
+
FF-A specification:
https://developer.arm.com/documentation/den0077/a/?lang=en
@@ -41,3 +44,11 @@ config ARM_FFA_TRANSPORT
Secure World (sandbox_ffa.c).
For more details about the FF-A support, please refer to doc/arch/arm64.ffa.rst
+
+config ARM_FFA_RT_MODE
+ bool "Enable FF-A runtime support"
+ depends on ARM_FFA_TRANSPORT && EFI_LOADER
+ default y
+ help
+ Enable the FF-A runtime layer, keeping a minimal set of FF-A
+ operations available after ExitBootServices().
diff --git a/drivers/firmware/arm-ffa/Makefile b/drivers/firmware/arm-ffa/Makefile
index 318123a7f42..9deb59ba640 100644
--- a/drivers/firmware/arm-ffa/Makefile
+++ b/drivers/firmware/arm-ffa/Makefile
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+# Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
#
# Authors:
# Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
# build the generic FF-A methods
-obj-y += arm-ffa-uclass.o
+obj-y += arm-ffa-uclass.o arm-ffa-runtime.o
ifeq ($(CONFIG_SANDBOX),y)
# build the FF-A sandbox emulator and driver
obj-y += ffa-emul-uclass.o sandbox_ffa.o
diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
new file mode 100644
index 00000000000..3b80cce272b
--- /dev/null
+++ b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#include <arm_ffa_runtime.h>
+#include <arm_ffa_priv.h>
+#include <log.h>
+#include <asm/global_data.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Error mapping declarations */
+
+int __ffa_runtime_data ffa_to_std_errmap[MAX_NUMBER_FFA_ERR] = {
+ [NOT_SUPPORTED] = -EOPNOTSUPP,
+ [INVALID_PARAMETERS] = -EINVAL,
+ [NO_MEMORY] = -ENOMEM,
+ [BUSY] = -EBUSY,
+ [INTERRUPTED] = -EINTR,
+ [DENIED] = -EACCES,
+ [RETRY] = -EAGAIN,
+ [ABORTED] = -ECANCELED,
+};
+
+static __ffa_runtime_data struct ffa_priv_runtime ffa_priv_rt = {0};
+
+/* Arm FF-A driver runtime operations */
+static const __ffa_runtime_data struct ffa_bus_ops_runtime ffa_ops_rt = {
+ .sync_send_receive = ffa_msg_send_direct_req_hdlr_runtime,
+};
+
+#define ffa_get_ops_runtime() (&ffa_ops_rt)
+#define ffa_get_priv_runtime() (&ffa_priv_rt)
+
+#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
+static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
+ void *context)
+{
+ struct ffa_priv *priv = context;
+
+ if (priv)
+ ffa_copy_runtime_priv(&priv->rt);
+ else
+ log_err("FF-A: Entering RT mode without FF-A runtime data information\n");
+
+ ffa_enable_runtime_context();
+}
+
+/**
+ * ffa_setup_efi_exit_boot_services_event() - register ExitBootServices event
+ * @priv: pointer to the FF-A private data
+ *
+ * Register an EFI event that enables the FF-A runtime context when
+ * ExitBootServices() is invoked.
+ *
+ * Return: 0 on success, -EPERM on failure to create the event.
+ */
+int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv)
+{
+ efi_status_t efi_ret;
+ struct efi_event *evt = NULL;
+
+ efi_ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+ ffa_rt_exit_boot_services_notify, priv,
+ &efi_guid_event_group_exit_boot_services,
+ &evt);
+ if (efi_ret != EFI_SUCCESS) {
+ log_err("FF-A: cannot install ExitBootServices event %p, err (%lu)\n",
+ evt, efi_ret);
+ return -EPERM;
+ }
+
+ return 0;
+}
+#endif
+
+/**
+ * ffa_copy_runtime_priv() - copy runtime data into resident storage
+ * @priv: pointer to the runtime private data
+ *
+ * Copy boot-time runtime data into the resident runtime storage to be used
+ * after ExitBootServices().
+ */
+void ffa_copy_runtime_priv(const struct ffa_priv_runtime *priv)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ if (priv)
+ *priv_rt = *priv;
+}
+
+/**
+ * ffa_enable_runtime_context() - Enable FF-A runtime context
+ *
+ * This function marks the FF-A runtime environment as ready for use by
+ * EFI runtime services. It is called when ExitBootServices() is invoked,
+ * after the FF-A bus device has successfully probed and U-Boot’s FF-A
+ * endpoint ID has been discovered and stored in the runtime private data
+ * structure.
+ *
+ * The FF-A runtime flag allows the EFI runtime layer to verify that the
+ * FF-A transport was initialized during the boot phase and that all
+ * runtime-safe FF-A operations may now be used after ExitBootServices().
+ *
+ */
+void ffa_enable_runtime_context(void)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ priv_rt->use_ffa_runtime = true;
+}
+
+/**
+ * ffa_get_status_runtime_context() - Query FF-A runtime readiness
+ *
+ * This helper returns whether the FF-A runtime environment has been
+ * enabled during the boot phase. Runtime FF-A operations must check this
+ * flag before attempting any FF-A access, as the U-Boot driver model
+ * (DM/uclass) is no longer available after ExitBootServices().
+ *
+ * The runtime context becomes enabled when ffa_enable_runtime_context()
+ * is called, typically after the FF-A bus device has probed and the
+ * endpoint ID has been discovered and stored in the runtime private
+ * data structure.
+ *
+ * Return: true if FF-A runtime support is ready, false otherwise.
+ */
+bool __ffa_runtime ffa_get_status_runtime_context(void)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ return priv_rt->use_ffa_runtime;
+}
+
+/**
+ * ffa_to_std_errno() - convert FF-A error code to standard error code
+ * @ffa_errno: Error code returned by the FF-A ABI
+ *
+ * Map the given FF-A error code as specified
+ * by the spec to a u-boot standard error code.
+ *
+ * Return: Standard U-Boot errno for known FF-A errors, or -EINVAL otherwise.
+ */
+int __ffa_runtime ffa_to_std_errno(int ffa_errno)
+{
+ int err_idx = -ffa_errno;
+
+ /* Map the FF-A error code to the standard u-boot error code */
+ if (err_idx > 0 && err_idx < MAX_NUMBER_FFA_ERR)
+ return ffa_to_std_errmap[err_idx];
+ return -EINVAL;
+}
+
+/**
+ * ffa_invoke_msg_send_direct_req() - Invokes FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * @endpoint_id: u-boot endpoint id
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
+ * The response from the secure partition is handled by reading the
+ * FFA_MSG_SEND_DIRECT_RESP arguments.
+ *
+ * The maximum size of the data that can be exchanged is 40 bytes which is
+ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
+ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int __ffa_runtime ffa_invoke_msg_send_direct_req(u16 endpoint_id, u16 dst_part_id,
+ struct ffa_send_direct_data *msg, bool is_smc64)
+{
+ int ffa_errno;
+ u64 req_mode;
+ ffa_value_t ffa_args_rt;
+ ffa_value_t ffa_res_rt;
+
+ if (is_smc64) {
+ req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
+ } else {
+ req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
+ }
+
+ efi_memset_runtime(&ffa_args_rt, 0, sizeof(ffa_args_rt));
+ efi_memset_runtime(&ffa_res_rt, 0, sizeof(ffa_res_rt));
+ ffa_args_rt.a0 = req_mode;
+ ffa_args_rt.a1 = PREP_SELF_ENDPOINT_ID(endpoint_id) |
+ PREP_PART_ENDPOINT_ID(dst_part_id);
+ ffa_args_rt.a2 = 0;
+ ffa_args_rt.a3 = msg->data0;
+ ffa_args_rt.a4 = msg->data1;
+ ffa_args_rt.a5 = msg->data2;
+ ffa_args_rt.a6 = msg->data3;
+ ffa_args_rt.a7 = msg->data4;
+
+ invoke_ffa_fn_runtime(&ffa_args_rt, &ffa_res_rt);
+
+ while (ffa_res_rt.a0 == FFA_SMC_32(FFA_INTERRUPT) ||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_INTERRUPT)) {
+ efi_memset_runtime(&ffa_args_rt, 0, sizeof(ffa_args_rt));
+ ffa_args_rt.a0 = (ffa_res_rt.a0 == FFA_SMC_64(FFA_INTERRUPT)) ?
+ FFA_SMC_64(FFA_RUN) : FFA_SMC_32(FFA_RUN);
+ ffa_args_rt.a1 = ffa_res_rt.a1;
+
+ invoke_ffa_fn_runtime(&ffa_args_rt, &ffa_res_rt);
+ }
+ if (ffa_res_rt.a0 == FFA_SMC_32(FFA_SUCCESS) ||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_SUCCESS)) {
+ /* Message sent with no response */
+ return 0;
+ }
+
+ if (ffa_res_rt.a0 == FFA_SMC_32(FFA_MSG_SEND_DIRECT_RESP) ||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP)) {
+ /* Message sent with response extract the return data */
+ msg->data0 = ffa_res_rt.a3;
+ msg->data1 = ffa_res_rt.a4;
+ msg->data2 = ffa_res_rt.a5;
+ msg->data3 = ffa_res_rt.a6;
+ msg->data4 = ffa_res_rt.a7;
+ return 0;
+ }
+
+ ffa_errno = ffa_res_rt.a2;
+ return ffa_to_std_errno(ffa_errno);
+}
+
+/**
+ * ffa_msg_send_direct_req_hdlr_runtime() - Runtime implementation of
+ * FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int __ffa_runtime ffa_msg_send_direct_req_hdlr_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ return ffa_invoke_msg_send_direct_req(priv_rt->id, dst_part_id, msg, is_smc64);
+}
+
+/**
+ * ffa_sync_send_receive_runtime() - Runtime implementation of
+ * ffa_sync_send_receive()
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * Please see ffa_msg_send_direct_req_hdlr_runtime() description for more details.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int __ffa_runtime ffa_sync_send_receive_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64)
+{
+ const struct ffa_bus_ops_runtime *ops_rt = ffa_get_ops_runtime();
+
+ if (!ffa_get_status_runtime_context())
+ return -EPERM;
+
+ if (!ops_rt->sync_send_receive)
+ return -ENOSYS;
+
+ return ops_rt->sync_send_receive(dst_part_id, msg, is_smc64);
+}
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 76a8775e911..af04ba1bcbc 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <arm_ffa.h>
#include <arm_ffa_priv.h>
+#include <arm_ffa_runtime.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
@@ -18,19 +19,6 @@
#include <linux/errno.h>
#include <linux/sizes.h>
-/* Error mapping declarations */
-
-int ffa_to_std_errmap[MAX_NUMBER_FFA_ERR] = {
- [NOT_SUPPORTED] = -EOPNOTSUPP,
- [INVALID_PARAMETERS] = -EINVAL,
- [NO_MEMORY] = -ENOMEM,
- [BUSY] = -EBUSY,
- [INTERRUPTED] = -EINTR,
- [DENIED] = -EACCES,
- [RETRY] = -EAGAIN,
- [ABORTED] = -ECANCELED,
-};
-
static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
[FFA_ID_TO_ERRMAP_ID(FFA_VERSION)] = {
{
@@ -94,27 +82,6 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
},
};
-/**
- * ffa_to_std_errno() - convert FF-A error code to standard error code
- * @ffa_errno: Error code returned by the FF-A ABI
- *
- * Map the given FF-A error code as specified
- * by the spec to a u-boot standard error code.
- *
- * Return:
- *
- * The standard error code on success. . Otherwise, failure
- */
-static int ffa_to_std_errno(int ffa_errno)
-{
- int err_idx = -ffa_errno;
-
- /* Map the FF-A error code to the standard u-boot error code */
- if (err_idx > 0 && err_idx < MAX_NUMBER_FFA_ERR)
- return ffa_to_std_errmap[err_idx];
- return -EINVAL;
-}
-
/**
* ffa_print_error_log() - print the error log corresponding to the selected FF-A ABI
* @ffa_id: FF-A ABI ID
@@ -204,7 +171,7 @@ int ffa_get_version_hdlr(struct udevice *dev)
if (dev) {
uc_priv = dev_get_uclass_priv(dev);
if (uc_priv)
- uc_priv->fwk_version = res.a0;
+ uc_priv->rt.fwk_version = res.a0;
}
return 0;
@@ -238,8 +205,8 @@ static int ffa_get_endpoint_id(struct udevice *dev)
}, &res);
if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
- uc_priv->id = GET_SELF_ENDPOINT_ID((u32)res.a2);
- log_debug("FF-A endpoint ID is %u\n", uc_priv->id);
+ uc_priv->rt.id = GET_SELF_ENDPOINT_ID((u32)res.a2);
+ log_debug("FF-A endpoint ID is %u\n", uc_priv->rt.id);
return 0;
}
@@ -461,7 +428,7 @@ int ffa_unmap_rxtx_buffers_hdlr(struct udevice *dev)
invoke_ffa_fn((ffa_value_t){
.a0 = FFA_SMC_32(FFA_RXTX_UNMAP),
- .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->id),
+ .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->rt.id),
}, &res);
if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
@@ -851,16 +818,8 @@ static int ffa_cache_partitions_info(struct udevice *dev)
* @msg: pointer to the message data preallocated by the client (in/out)
* @is_smc64: select 64-bit or 32-bit FF-A ABI
*
- * Implement FFA_MSG_SEND_DIRECT_{REQ,RESP}
- * FF-A functions.
- *
- * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
- * The response from the secure partition is handled by reading the
- * FFA_MSG_SEND_DIRECT_RESP arguments.
- *
- * The maximum size of the data that can be exchanged is 40 bytes which is
- * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
- * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
*
* Return:
*
@@ -869,9 +828,6 @@ static int ffa_cache_partitions_info(struct udevice *dev)
int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
struct ffa_send_direct_data *msg, bool is_smc64)
{
- ffa_value_t res = {0};
- int ffa_errno;
- u64 req_mode, resp_mode;
struct ffa_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
@@ -880,50 +836,7 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
if (!uc_priv->partitions.count || !uc_priv->partitions.descs)
return -ENODEV;
- if (is_smc64) {
- req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
- resp_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP);
- } else {
- req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
- resp_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_RESP);
- }
-
- invoke_ffa_fn((ffa_value_t){
- .a0 = req_mode,
- .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->id) |
- PREP_PART_ENDPOINT_ID(dst_part_id),
- .a2 = 0,
- .a3 = msg->data0,
- .a4 = msg->data1,
- .a5 = msg->data2,
- .a6 = msg->data3,
- .a7 = msg->data4,
- }, &res);
-
- while (res.a0 == FFA_SMC_32(FFA_INTERRUPT))
- invoke_ffa_fn((ffa_value_t){
- .a0 = FFA_SMC_32(FFA_RUN),
- .a1 = res.a1,
- }, &res);
-
- if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
- /* Message sent with no response */
- return 0;
- }
-
- if (res.a0 == resp_mode) {
- /* Message sent with response extract the return data */
- msg->data0 = res.a3;
- msg->data1 = res.a4;
- msg->data2 = res.a5;
- msg->data3 = res.a6;
- msg->data4 = res.a7;
-
- return 0;
- }
-
- ffa_errno = res.a2;
- return ffa_to_std_errno(ffa_errno);
+ return ffa_invoke_msg_send_direct_req(uc_priv->rt.id, dst_part_id, msg, is_smc64);
}
/* FF-A driver operations (used by clients for communicating with FF-A)*/
@@ -1024,6 +937,7 @@ int ffa_rxtx_unmap(struct udevice *dev)
static int ffa_do_probe(struct udevice *dev)
{
int ret;
+ struct ffa_priv *uc_priv = dev_get_uclass_priv(dev);
ret = ffa_get_version_hdlr(dev);
if (ret)
@@ -1047,6 +961,11 @@ static int ffa_do_probe(struct udevice *dev)
return ret;
}
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+ ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
+ if (ret)
+ return ret;
+ }
return 0;
}
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c
index 9e6b5dcc542..241ef018817 100644
--- a/drivers/firmware/arm-ffa/arm-ffa.c
+++ b/drivers/firmware/arm-ffa/arm-ffa.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -8,6 +8,7 @@
#include <arm_ffa.h>
#include <arm_ffa_priv.h>
+#include <arm_ffa_runtime.h>
#include <dm.h>
#include <log.h>
#include <dm/device-internal.h>
@@ -25,6 +26,19 @@ void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
arm_smccc_1_2_smc(&args, res);
}
+/**
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
+ * @args: FF-A ABI arguments to be copied to Xn registers
+ * @res: FF-A ABI return values copied from Xn registers
+ *
+ * Calls the SMCCC SMC 1.2 helper from EFI runtime context. This wrapper
+ * is marked __ffa_runtime so it remains available after ExitBootServices().
+ */
+void __ffa_runtime invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res)
+{
+ arm_smccc_1_2_smc(args, res);
+}
+
/**
* arm_ffa_discover() - perform FF-A discovery
* @dev: The Arm FF-A bus device (arm_ffa)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
index 6198d687354..d270f7b614e 100644
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
@@ -671,6 +671,18 @@ void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
sandbox_arm_ffa_smccc_smc(&args, res);
}
+/**
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
+ * @args: FF-A ABI arguments to be copied to Xn registers
+ * @res: FF-A ABI return data to be copied from Xn registers
+ *
+ * Calls the emulated SMC call.
+ */
+void invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res)
+{
+ sandbox_arm_ffa_smccc_smc(args, res);
+}
+
/**
* ffa_emul_find() - Find the FF-A emulator
* @dev: the sandbox FF-A device (sandbox-arm-ffa)
diff --git a/include/arm_ffa.h b/include/arm_ffa.h
index 2994d8ee3ae..6a03aad81a8 100644
--- a/include/arm_ffa.h
+++ b/include/arm_ffa.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -129,21 +129,13 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id,
/**
* ffa_msg_send_direct_req_hdlr() - FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
- * @dev: The arm_ffa bus device
+ * @dev: The FF-A bus device
* @dst_part_id: destination partition ID
* @msg: pointer to the message data preallocated by the client (in/out)
* @is_smc64: select 64-bit or 32-bit FF-A ABI
*
- * This function implements FFA_MSG_SEND_DIRECT_{REQ,RESP}
- * FF-A functions.
- *
- * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
- * The response from the secure partition is handled by reading the
- * FFA_MSG_SEND_DIRECT_RESP arguments.
- *
- * The maximum size of the data that can be exchanged is 40 bytes which is
- * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
- * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
*
* Return:
*
diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
index d564c33c647..87c6abe4299 100644
--- a/include/arm_ffa_priv.h
+++ b/include/arm_ffa_priv.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -200,11 +200,26 @@ struct ffa_partitions {
};
/**
- * struct ffa_priv - the driver private data structure
+ * struct ffa_priv_runtime - the driver's private runtime data structure
*
+ * @use_ffa_runtime: Whether FF-A runtime is available to use or not
* @fwk_version: FF-A framework version
- * @emul: FF-A sandbox emulator
* @id: u-boot endpoint ID
+ *
+ * The device private runtime data structure containing all the
+ * data read from secure world.
+ */
+struct ffa_priv_runtime {
+ bool use_ffa_runtime;
+ u32 fwk_version;
+ u16 id;
+};
+
+/**
+ * struct ffa_priv - the driver private data structure
+ *
+ * @rt: Runtime data captured at boot time
+ * @emul: FF-A sandbox emulator
* @partitions: The partitions descriptors structure
* @pair: The RX/TX buffers pair
*
@@ -212,9 +227,8 @@ struct ffa_partitions {
* data read from secure world.
*/
struct ffa_priv {
- u32 fwk_version;
+ struct ffa_priv_runtime rt;
struct udevice *emul;
- u16 id;
struct ffa_partitions partitions;
struct ffa_rxtxpair pair;
};
diff --git a/include/arm_ffa_runtime.h b/include/arm_ffa_runtime.h
new file mode 100644
index 00000000000..5fc411192ab
--- /dev/null
+++ b/include/arm_ffa_runtime.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#ifndef __ARM_FFA_RUNTIME_H
+#define __ARM_FFA_RUNTIME_H
+
+#include <linux/types.h>
+#include <arm_ffa.h>
+#include <arm_ffa_priv.h>
+#include <efi_loader.h>
+
+/**
+ * __ffa_runtime - controls whether functions are
+ * available after calling the EFI ExitBootServices service.
+ * Functions tagged with these keywords are resident (available at boot time and
+ * at runtime)
+ */
+#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
+#define __ffa_runtime_data __efi_runtime_data
+#define __ffa_runtime __efi_runtime
+#else
+#define __ffa_runtime_data
+#define __ffa_runtime
+#endif
+
+/**
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
+ * @args: FF-A ABI arguments to be copied to Xn registers
+ * @res: FF-A ABI return values copied from Xn registers
+ *
+ * Calls low level SMC implementation. This wrapper
+ * is marked __ffa_runtime so it remains available after ExitBootServices().
+ */
+void __ffa_runtime invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res);
+
+/**
+ * struct ffa_bus_ops_runtime - Operations for FF-A runtime
+ * @sync_send_receive: callback for the FFA_MSG_SEND_DIRECT_REQ
+ *
+ * The data structure providing all the runtime operations supported by the driver.
+ * This structure is an EFI runtime resident.
+ */
+struct ffa_bus_ops_runtime {
+ int (*sync_send_receive)(u16 dst_part_id, struct ffa_send_direct_data *msg,
+ bool is_smc64);
+};
+
+/**
+ * ffa_enable_runtime_context() - Enable FF-A runtime context
+ *
+ * This function marks the FF-A runtime environment as ready for use by
+ * EFI runtime services. It is called when ExitBootServices() is invoked,
+ * after the FF-A bus device has successfully probed and U-Boot’s FF-A
+ * endpoint ID has been discovered and stored in the runtime private data
+ * structure.
+ *
+ * The FF-A runtime flag allows the EFI runtime layer to verify that the
+ * FF-A transport was initialized during the boot phase and that all
+ * runtime-safe FF-A operations may now be used after ExitBootServices().
+ *
+ */
+void ffa_enable_runtime_context(void);
+
+/**
+ * ffa_copy_runtime_priv() - copy runtime data into resident storage
+ * @priv: pointer to the runtime private data
+ *
+ * Copy boot-time runtime data into the resident runtime storage to be used
+ * after ExitBootServices().
+ */
+void ffa_copy_runtime_priv(const struct ffa_priv_runtime *priv);
+
+/**
+ * ffa_setup_efi_exit_boot_services_event() - register ExitBootServices event
+ * @priv: pointer to the FF-A private data
+ *
+ * Register an EFI event that enables the FF-A runtime context when
+ * ExitBootServices() is invoked.
+ *
+ * Return: 0 on success, -EPERM on failure to create the event.
+ */
+#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
+int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv);
+#else
+static inline int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv)
+{
+ return 0;
+}
+#endif
+
+/**
+ * ffa_get_status_runtime_context() - Query FF-A runtime readiness
+ *
+ * This helper returns whether the FF-A runtime environment has been
+ * enabled during the boot phase. Runtime FF-A operations must check this
+ * flag before attempting any FF-A access, as the U-Boot driver model
+ * (DM/uclass) is no longer available after ExitBootServices().
+ *
+ * The runtime context becomes enabled when ffa_enable_runtime_context()
+ * is called, typically after the FF-A bus device has probed and the
+ * endpoint ID has been discovered and stored in the runtime private
+ * data structure.
+ *
+ * Return: true if FF-A runtime support is ready, false otherwise.
+ */
+bool __ffa_runtime ffa_get_status_runtime_context(void);
+
+/**
+ * ffa_to_std_errno() - convert FF-A error code to standard error code
+ * @ffa_errno: Error code returned by the FF-A ABI
+ *
+ * Map the given FF-A error code as specified
+ * by the spec to a u-boot standard error code.
+ *
+ * Return: Standard U-Boot errno for known FF-A errors, or -EINVAL otherwise.
+ */
+int __ffa_runtime ffa_to_std_errno(int ffa_errno);
+
+/**
+ * ffa_sync_send_receive_runtime() - Runtime implementation of
+ * ffa_sync_send_receive()
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * Please see ffa_msg_send_direct_req_hdlr_runtime() description for more details.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int __ffa_runtime ffa_sync_send_receive_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64);
+
+/**
+ * ffa_invoke_msg_send_direct_req() - Invokes FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * @endpoint_id: u-boot endpoint id
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
+ * The response from the secure partition is handled by reading the
+ * FFA_MSG_SEND_DIRECT_RESP arguments.
+ *
+ * The maximum size of the data that can be exchanged is 40 bytes which is
+ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
+ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, error on failure
+ */
+int __ffa_runtime ffa_invoke_msg_send_direct_req(u16 endpoint_id, u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64);
+
+/**
+ * ffa_msg_send_direct_req_hdlr_runtime() - Runtime implementation of
+ * FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int __ffa_runtime ffa_msg_send_direct_req_hdlr_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64);
+
+#endif
diff --git a/test/dm/ffa.c b/test/dm/ffa.c
index 593b7177fce..a0c95e62607 100644
--- a/test/dm/ffa.c
+++ b/test/dm/ffa.c
@@ -2,7 +2,7 @@
/*
* Functional tests for UCLASS_FFA class
*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -26,14 +26,14 @@ static int check_fwk_version(struct ffa_priv *uc_priv, struct unit_test_state *u
func_data.data0 = &fwk_version;
func_data.data0_size = sizeof(fwk_version);
ut_assertok(sandbox_query_ffa_emul_state(FFA_VERSION, &func_data));
- ut_asserteq(uc_priv->fwk_version, fwk_version);
+ ut_asserteq(uc_priv->rt.fwk_version, fwk_version);
return 0;
}
static int check_endpoint_id(struct ffa_priv *uc_priv, struct unit_test_state *uts)
{
- ut_asserteq(0, uc_priv->id);
+ ut_asserteq(0, uc_priv->rt.id);
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 01/12] efi_loader: add runtime memset helper Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 02/12] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-27 16:21 ` Ilias Apalodimas
2026-04-28 18:12 ` Simon Glass
2026-04-24 17:31 ` [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
` (11 subsequent siblings)
14 siblings, 2 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Enable MM variable services over FF-A after ExitBootServices
This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
communication with the secure world during EFI runtime. It enables EFI
runtime variable access and MM communication using FF-A transport when
ExitBootServices() has already been called.
Key changes:
------------
- Introduce runtime-safe implementations for MM communication,
notification, and variable access using FF-A driver.
- Introduce communication-buffer helper (get_comm_buf()) that switches
between dynamic allocation (boot phase) and the fixed FF-A shared
buffer (runtime phase).
- Mark persistent data and code with __efi_runtime and
__efi_runtime_data attributes.
- Use direct physical address mapping for shared buffers since
U-Boot operates with 1:1 physical-to-virtual mapping.
- Only per-buffer cache maintenance is performed at runtime,
as whole D-cache invalidation would violate the OS coherency model
after ExitBootServices().
- Add runtime-phase tracking (efi_runtime_enabled).
The change reuses the statically reserved shared buffer, replaces
allocations with __efi_runtime copies, and updates the runtime service
table so EFI variable runtime calls reach the secure partition via FF-A.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
lib/efi_loader/efi_variable_tee.c | 331 ++++++++++++++++++++++++++++--
1 file changed, 319 insertions(+), 12 deletions(-)
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 6a1fa39bb6f..e4d97dc55ab 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
* Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -14,6 +14,7 @@
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
#include <arm_ffa.h>
+#include <arm_ffa_runtime.h>
#endif
#include <cpu_func.h>
#include <dm.h>
@@ -34,20 +35,47 @@
#define MM_DENIED (-3)
#define MM_NO_MEMORY (-5)
+static const int __efi_runtime_rodata mm_sp_errmap[] = {
+ [-MM_NOT_SUPPORTED] = -EINVAL,
+ [-MM_INVALID_PARAMETER] = -EPERM,
+ [-MM_DENIED] = -EACCES,
+ [-MM_NO_MEMORY] = -EBUSY,
+};
+
static const char *mm_sp_svc_uuid = MM_SP_UUID;
-static u16 mm_sp_id;
+static u16 __efi_runtime_data mm_sp_id;
#endif
+static void *__efi_runtime_data ffa_shared_buf;
+static const efi_guid_t __efi_runtime_rodata mm_var_guid_runtime =
+ EFI_MM_VARIABLE_GUID;
+
extern struct efi_var_file __efi_runtime_data *efi_var_buf;
-static efi_uintn_t max_buffer_size; /* comm + var + func + data */
-static efi_uintn_t max_payload_size; /* func + data */
+static efi_uintn_t __efi_runtime_data max_buffer_size; /* comm + var + func + data */
+static efi_uintn_t __efi_runtime_data max_payload_size; /* func + data */
static const u16 __efi_runtime_rodata pk[] = u"PK";
+static bool __efi_runtime_data efi_runtime_enabled;
struct mm_connection {
struct udevice *tee;
u32 session;
};
+/**
+ * efi_is_runtime_enabled() - Indicate whether the system is in the UEFI runtime phase
+ *
+ * This helper returns whether the firmware has transitioned into the
+ * UEFI runtime phase, meaning that ExitBootServices() has been invoked.
+ *
+ * Return:
+ * true - The system is operating in UEFI runtime mode.
+ * false - The system is still in the boot services phase.
+ */
+static bool __efi_runtime efi_is_runtime_enabled(void)
+{
+ return efi_runtime_enabled;
+}
+
/**
* get_connection() - Retrieve OP-TEE session for a specific UUID.
*
@@ -169,6 +197,28 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
}
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+/**
+ * ffa_map_sp_event_runtime() - Map MM SP response to errno (runtime-safe)
+ * @sp_event_ret: MM SP return code from ffa_notify_mm_sp_runtime()
+ *
+ * Convert the MM SP return code into a standard U-Boot errno. This helper
+ * is marked __efi_runtime to ensure it is safe to call after
+ * ExitBootServices().
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static __efi_runtime int ffa_map_sp_event_runtime(int sp_event_ret)
+{
+ int idx = -sp_event_ret;
+
+ if (sp_event_ret == MM_SUCCESS)
+ return 0;
+ if (idx > 0 && idx < (int)ARRAY_SIZE(mm_sp_errmap) &&
+ mm_sp_errmap[idx])
+ return mm_sp_errmap[idx];
+ return -EACCES;
+}
+
/**
* ffa_notify_mm_sp() - Announce there is data in the shared buffer
*
@@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
return ret;
}
+/**
+ * ffa_notify_mm_sp_runtime() - Runtime implementation of
+ * ffa_notify_mm_sp()
+ *
+ * Notify the MM partition in the trusted world that
+ * data is available in the shared buffer.
+ * This is a blocking call during which trusted world has exclusive access
+ * to the MM shared buffer.
+ *
+ * Return:
+ *
+ * 0 on success
+ */
+static int __efi_runtime ffa_notify_mm_sp_runtime(void)
+{
+ struct ffa_send_direct_data msg = {0};
+ int ret;
+ int sp_event_ret;
+
+ msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
+
+ ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
+ if (ret)
+ return ret;
+
+ ret = ffa_map_sp_event_runtime(sp_event_ret);
+ return ret;
+}
+
/**
* ffa_discover_mm_sp_id() - Query the MM partition ID
*
@@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
return efi_ret;
}
+/**
+ * ffa_mm_communicate_runtime() - Runtime implementation of ffa_mm_communicate()
+ * @comm_buf: locally allocated communication buffer used for rx/tx
+ * @comm_buf_size: communication buffer size
+ *
+ * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
+ * that there is data to read from the shared buffer.
+ * Communication with the MM SP is performed using FF-A transport.
+ * On the event, MM SP can read the data from the buffer and
+ * update the MM shared buffer with response data.
+ * The response data is copied back to the communication buffer.
+ *
+ * Return:
+ *
+ * EFI status code
+ */
+static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
+ ulong comm_buf_size)
+{
+ ulong tx_data_size;
+ int ffa_ret;
+ efi_status_t efi_ret;
+ struct efi_mm_communicate_header *mm_hdr;
+
+ if (!comm_buf)
+ return EFI_INVALID_PARAMETER;
+
+ /* Discover MM partition ID at boot time */
+ if (!mm_sp_id)
+ return EFI_UNSUPPORTED;
+
+ mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
+ tx_data_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
+
+ if (comm_buf_size != tx_data_size || tx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
+ return EFI_INVALID_PARAMETER;
+
+ /*
+ * Shared buffer cache maintenance for FF-A / OP-TEE communication:
+ *
+ * NS -> S (request path):
+ *
+ * The non-secure side populates the shared buffer. If the buffer is cached
+ * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
+ * visible in DDR. Since the secure world typically reads the shared buffer
+ * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
+ * must clean the corresponding cache lines to the Point of Coherency (PoC)
+ * before entering secure world.
+ *
+ * S -> NS (response path):
+ *
+ * The secure world may update the same shared buffer in DDR. After returning
+ * to non-secure, any cached copies of that region in NS may be stale. We
+ * therefore invalidate the shared buffer range after the FF-A call to drop
+ * those lines and force subsequent reads to fetch the latest data from DDR.
+ *
+ * Note: Whole-cache invalidation must not be used in EFI runtime context.
+ * After ExitBootServices(), the OS owns the cache hierarchy; global invalidation
+ * could drop OS dirty lines and violate the OS coherency model. Always operate
+ * on the shared buffer range only.
+ */
+ if (IS_ENABLED(CONFIG_ARM64))
+ flush_dcache_range((unsigned long)comm_buf,
+ (unsigned long)((u8 *)comm_buf +
+ CONFIG_FFA_SHARED_MM_BUF_SIZE));
+
+ /* Announce there is data in the shared buffer */
+
+ ffa_ret = ffa_notify_mm_sp_runtime();
+
+ if (IS_ENABLED(CONFIG_ARM64))
+ invalidate_dcache_range((unsigned long)comm_buf,
+ (unsigned long)((u8 *)comm_buf +
+ CONFIG_FFA_SHARED_MM_BUF_SIZE));
+
+ switch (ffa_ret) {
+ case 0: {
+ ulong rx_data_size;
+
+ rx_data_size = ((struct efi_mm_communicate_header *)comm_buf)->message_len +
+ sizeof(efi_guid_t) +
+ sizeof(size_t);
+
+ if (rx_data_size > comm_buf_size) {
+ efi_ret = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+
+ efi_ret = EFI_SUCCESS;
+ break;
+ }
+ case -EINVAL:
+ efi_ret = EFI_DEVICE_ERROR;
+ break;
+ case -EPERM:
+ efi_ret = EFI_INVALID_PARAMETER;
+ break;
+ case -EACCES:
+ efi_ret = EFI_ACCESS_DENIED;
+ break;
+ case -EBUSY:
+ efi_ret = EFI_OUT_OF_RESOURCES;
+ break;
+ default:
+ efi_ret = EFI_ACCESS_DENIED;
+ }
+
+ return efi_ret;
+}
+
/**
* get_mm_comms() - detect the available MM transport
*
@@ -386,6 +575,27 @@ static enum mm_comms_select get_mm_comms(void)
return MM_COMMS_FFA;
}
+
+/**
+ * get_mm_comms_runtime() - detect the available MM transport at runtime
+ *
+ * Make sure the FF-A bus is available at runtime and ready
+ * for use.
+ *
+ * Return:
+ *
+ * MM_COMMS_FFA or MM_COMMS_UNDEFINED
+ */
+static enum mm_comms_select __efi_runtime get_mm_comms_runtime(void)
+{
+ bool ret;
+
+ ret = efi_is_runtime_enabled();
+ if (!ret)
+ return MM_COMMS_UNDEFINED;
+
+ return MM_COMMS_FFA;
+}
#endif
/**
@@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
return var_hdr->ret_status;
}
+/**
+ * mm_communicate_runtime() - Runtime implementation of mm_communicate()
+ *
+ * @comm_buf: locally allocated communication buffer
+ * @dsize: buffer size
+ *
+ * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
+ * The comm_buf format is the same for both partitions.
+ * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
+ * When using the u-boot FF-A driver, any MM SP is supported.
+ *
+ * Return: status code
+ */
+static efi_status_t __efi_runtime mm_communicate_runtime(u8 *comm_buf, efi_uintn_t dsize)
+{
+ efi_status_t ret = EFI_UNSUPPORTED;
+ struct efi_mm_communicate_header *mm_hdr;
+ struct smm_variable_communicate_header *var_hdr;
+ enum mm_comms_select mm_comms;
+
+ dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
+ mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
+ var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
+
+ if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) {
+ mm_comms = get_mm_comms_runtime();
+ if (mm_comms == MM_COMMS_FFA)
+ ret = ffa_mm_communicate_runtime(comm_buf, dsize);
+ }
+
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ return var_hdr->ret_status;
+}
+
+/**
+ * get_comm_buf() - Obtain a communication buffer for MM/FF-A exchange
+ * @payload_size: size of the payload that will be appended to the
+ * MM communication header
+ * This helper returns a buffer suitable for constructing an
+ * EFI_MM_COMMUNICATE message. During the boot phase a new buffer is
+ * dynamically allocated. After ExitBootServices(), dynamic
+ * allocation is no longer permitted, and all runtime communication must
+ * use the statically reserved FF-A shared buffer.
+ *
+ * Return:
+ * Pointer to a valid communication buffer on success,
+ * NULL if allocation fails during the boot phase.
+ */
+static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
+{
+ u8 *comm_buf;
+
+ /* After ExitBootServices(), dynamic allocation is no longer permitted.
+ * Use the predefined FF-A shared buffer at runtime; otherwise allocate
+ * a fresh buffer during the boot phase.
+ */
+ if (efi_is_runtime_enabled()) {
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+ comm_buf = ffa_shared_buf;
+ if (!comm_buf)
+ return NULL;
+ efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
+ } else {
+ return NULL;
+ }
+ } else {
+ comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
+ MM_VARIABLE_COMMUNICATE_SIZE +
+ payload_size);
+ if (!comm_buf)
+ return NULL;
+ }
+ return comm_buf;
+}
+
/**
* setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
- * header data.
+ * header data. It is runtime safe.
*
* @dptr: pointer address of the corresponding StandAloneMM
* function
@@ -444,10 +731,9 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
* @ret: EFI return code
* Return: buffer or NULL
*/
-static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
- efi_uintn_t func, efi_status_t *ret)
+static __efi_runtime u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
+ efi_uintn_t func, efi_status_t *ret)
{
- const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
struct efi_mm_communicate_header *mm_hdr;
struct smm_variable_communicate_header *var_hdr;
u8 *comm_buf;
@@ -465,16 +751,15 @@ static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
return NULL;
}
- comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
- MM_VARIABLE_COMMUNICATE_SIZE +
- payload_size);
+ comm_buf = get_comm_buf(payload_size);
if (!comm_buf) {
*ret = EFI_OUT_OF_RESOURCES;
return NULL;
}
mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
- guidcpy(&mm_hdr->header_guid, &mm_var_guid);
+ efi_memcpy_runtime(&mm_hdr->header_guid, &mm_var_guid_runtime,
+ sizeof(mm_hdr->header_guid));
mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
@@ -982,6 +1267,9 @@ void efi_variables_boot_exit_notify(void)
efi_get_next_variable_name_runtime;
efi_runtime_services.set_variable = efi_set_variable_runtime;
efi_update_table_header_crc32(&efi_runtime_services.hdr);
+
+ /* Set efi_runtime_enabled as true after ExitBootServices */
+ efi_runtime_enabled = true;
}
/**
@@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
{
efi_status_t ret;
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+ /*
+ * The FF-A shared buffer is accessed by EFI runtime services, so it must
+ * be marked as runtime memory in the EFI memory map.
+ */
+ ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
+ ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
+ CONFIG_FFA_SHARED_MM_BUF_SIZE,
+ EFI_RUNTIME_SERVICES_DATA);
+ if (ret != EFI_SUCCESS) {
+ log_err("EFI: failed to add FF-A shared buffer to runtime map (%lu)\n",
+ ret);
+ return ret;
+ }
+ log_info("EFI: FF-A shared buffer runtime map: addr=0x%lx size=0x%lx\n",
+ (ulong)CONFIG_FFA_SHARED_MM_BUF_ADDR,
+ (ulong)CONFIG_FFA_SHARED_MM_BUF_SIZE);
+ }
+
/* Create a cached copy of the variables that will be enabled on ExitBootServices() */
ret = efi_var_mem_init();
if (ret != EFI_SUCCESS)
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (2 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:16 ` Simon Glass
2026-04-24 17:31 ` [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c Harsimran Singh Tungal
` (10 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Route EFI runtime variable APIs through FF-A MM communication
This patch implements full EFI Runtime Variable Services (GetVariable,
SetVariable, GetNextVariableName, and QueryVariableInfo) using the
FF-A/MM communication backend. Once ExitBootServices() has been invoked,
all variable operations now use the runtime-safe FF-A transport instead
of the boot-time communication paths.
Key changes:
============
- Add runtime-safe variable property handling via FF-A MM SP.
- Add runtime versions of variable access and property operations.
- Replace all standard memory operations with EFI-runtime-safe variants.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
lib/charset.c | 2 +-
lib/efi_loader/efi_variable_tee.c | 322 +++++++++++++++++++++++++++++-
2 files changed, 318 insertions(+), 6 deletions(-)
diff --git a/lib/charset.c b/lib/charset.c
index 182c92a50c4..738ad1352de 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -407,7 +407,7 @@ size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
return i;
}
-size_t u16_strsize(const void *in)
+size_t __efi_runtime u16_strsize(const void *in)
{
return (u16_strlen(in) + 1) * sizeof(u16);
}
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index e4d97dc55ab..30687c21b8e 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -859,6 +859,38 @@ out:
return ret;
}
+static efi_status_t __efi_runtime set_property_int_runtime(const u16 *variable_name,
+ efi_uintn_t name_size,
+ const efi_guid_t *vendor,
+ struct var_check_property *var_property)
+{
+ struct smm_variable_var_check_property *smm_property;
+ efi_uintn_t payload_size;
+ u8 *comm_buf = NULL;
+ efi_status_t ret;
+
+ payload_size = sizeof(*smm_property) + name_size;
+ if (payload_size > max_payload_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+ comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
+ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(*vendor));
+ smm_property->name_size = name_size;
+ efi_memcpy_runtime(&smm_property->property, var_property,
+ sizeof(smm_property->property));
+ efi_memcpy_runtime(smm_property->name, variable_name, name_size);
+
+ ret = mm_communicate_runtime(comm_buf, payload_size);
+
+ return ret;
+}
+
static efi_status_t get_property_int(const u16 *variable_name,
efi_uintn_t name_size,
const efi_guid_t *vendor,
@@ -904,6 +936,49 @@ out:
return ret;
}
+static efi_status_t __efi_runtime get_property_int_runtime(const u16 *variable_name,
+ efi_uintn_t name_size,
+ const efi_guid_t *vendor,
+ struct var_check_property *var_property)
+{
+ struct smm_variable_var_check_property *smm_property;
+ efi_uintn_t payload_size;
+ u8 *comm_buf = NULL;
+ efi_status_t ret;
+
+ efi_memset_runtime(var_property, 0, sizeof(*var_property));
+ payload_size = sizeof(*smm_property) + name_size;
+ if (payload_size > max_payload_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+ comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
+ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(smm_property->guid));
+ smm_property->name_size = name_size;
+ efi_memcpy_runtime(smm_property->name, variable_name, name_size);
+
+ ret = mm_communicate_runtime(comm_buf, payload_size);
+ /*
+ * Currently only R/O property is supported in StMM.
+ * Variables that are not set to R/O will not set the property in StMM
+ * and the call will return EFI_NOT_FOUND. We are setting the
+ * properties to 0x0 so checking against that is enough for the
+ * EFI_NOT_FOUND case.
+ */
+ if (ret == EFI_NOT_FOUND)
+ ret = EFI_SUCCESS;
+ if (ret != EFI_SUCCESS)
+ return ret;
+ efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
+
+ return ret;
+}
+
efi_status_t efi_get_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size,
@@ -991,6 +1066,92 @@ out:
return ret;
}
+efi_status_t __efi_runtime efi_get_variable_runtime(u16 *variable_name,
+ const efi_guid_t *vendor,
+ u32 *attributes,
+ efi_uintn_t *data_size,
+ void *data)
+{
+ struct var_check_property var_property;
+ struct smm_variable_access *var_acc;
+ efi_uintn_t payload_size;
+ efi_uintn_t name_size;
+ efi_uintn_t tmp_dsize;
+ u8 *comm_buf = NULL;
+ efi_status_t ret, tmp;
+
+ if (!variable_name || !vendor || !data_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ /* Check payload size */
+ name_size = u16_strsize(variable_name);
+ if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ /* Trim output buffer size */
+ tmp_dsize = *data_size;
+ if (name_size + tmp_dsize >
+ max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
+ tmp_dsize = max_payload_size -
+ MM_VARIABLE_ACCESS_HEADER_SIZE -
+ name_size;
+ }
+
+ /* Get communication buffer and initialize header */
+ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
+ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
+ SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret);
+ if (!comm_buf)
+ return ret;
+
+ /* Fill in contents */
+ efi_memcpy_runtime(&var_acc->guid, vendor, sizeof(var_acc->guid));
+ var_acc->data_size = tmp_dsize;
+ var_acc->name_size = name_size;
+ var_acc->attr = attributes ? *attributes : 0;
+ efi_memcpy_runtime(var_acc->name, variable_name, name_size);
+
+ /* Communicate */
+ ret = mm_communicate_runtime(comm_buf, payload_size);
+ if (ret != EFI_SUCCESS && ret != EFI_BUFFER_TOO_SMALL)
+ return ret;
+
+ /* Update with reported data size for trimmed case */
+ *data_size = var_acc->data_size;
+
+ /* Copy the data if ret is EFI_SUCCESS */
+ if (ret == EFI_SUCCESS) {
+ if (data)
+ efi_memcpy_runtime(data, (u8 *)var_acc->name + var_acc->name_size,
+ var_acc->data_size);
+ else
+ ret = EFI_INVALID_PARAMETER;
+ }
+
+ /*
+ * UEFI > 2.7 needs the attributes set even if the buffer is
+ * smaller
+ */
+ if (attributes) {
+ tmp = get_property_int_runtime(variable_name, name_size, vendor,
+ &var_property);
+ if (tmp != EFI_SUCCESS) {
+ ret = tmp;
+ return ret;
+ }
+ *attributes = var_acc->attr;
+ if (var_property.property &
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
+ *attributes |= EFI_VARIABLE_READ_ONLY;
+ }
+
+ return ret;
+}
+
efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
u16 *variable_name,
efi_guid_t *guid)
@@ -1055,6 +1216,68 @@ out:
return ret;
}
+efi_status_t __efi_runtime efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
+ u16 *variable_name,
+ efi_guid_t *guid)
+{
+ struct smm_variable_getnext *var_getnext;
+ efi_uintn_t payload_size;
+ efi_uintn_t out_name_size;
+ efi_uintn_t in_name_size;
+ u8 *comm_buf = NULL;
+ efi_status_t ret;
+
+ if (!variable_name_size || !variable_name || !guid) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ out_name_size = *variable_name_size;
+ in_name_size = u16_strsize(variable_name);
+
+ if (out_name_size < in_name_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ /* Trim output buffer size */
+ if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
+ out_name_size = max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE;
+
+ payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
+ comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size,
+ SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ /* Fill in contents */
+ efi_memcpy_runtime(&var_getnext->guid, guid, sizeof(*guid));
+ var_getnext->name_size = out_name_size;
+ efi_memcpy_runtime(var_getnext->name, variable_name, in_name_size);
+ efi_memset_runtime((u8 *)var_getnext->name + in_name_size, 0x0,
+ out_name_size - in_name_size);
+
+ /* Communicate */
+ ret = mm_communicate_runtime(comm_buf, payload_size);
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
+ /* Update with reported data size for trimmed case */
+ *variable_name_size = var_getnext->name_size;
+ }
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ efi_memcpy_runtime(guid, &var_getnext->guid, sizeof(*guid));
+ efi_memcpy_runtime(variable_name, var_getnext->name, var_getnext->name_size);
+
+ return ret;
+}
+
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor, u32 attributes,
efi_uintn_t data_size, const void *data,
@@ -1197,11 +1420,11 @@ out:
*
* @attributes: bitmask to select variables to be
* queried
- * @maximum_variable_storage_size: maximum size of storage area for the
+ * @max_variable_storage_size: maximum size of storage area for the
* selected variable types
- * @remaining_variable_storage_size: remaining size of storage are for the
+ * @remain_variable_storage_size: remaining size of storage are for the
* selected variable types
- * @maximum_variable_size: maximum size of a variable of the
+ * @max_variable_size: maximum size of a variable of the
* selected type
* Return: status code
*/
@@ -1210,7 +1433,33 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
u64 *remain_variable_storage_size,
u64 *max_variable_size)
{
- return EFI_UNSUPPORTED;
+ struct smm_variable_query_info *mm_query_info;
+ efi_uintn_t payload_size;
+ efi_status_t ret;
+ u8 *comm_buf;
+
+ if (!max_variable_storage_size ||
+ !remain_variable_storage_size ||
+ !max_variable_size || !attributes)
+ return EFI_INVALID_PARAMETER;
+
+ payload_size = sizeof(*mm_query_info);
+ comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
+ SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ mm_query_info->attr = attributes;
+ ret = mm_communicate_runtime(comm_buf, payload_size);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ *max_variable_storage_size = mm_query_info->max_variable_storage;
+ *remain_variable_storage_size =
+ mm_query_info->remaining_variable_storage;
+ *max_variable_size = mm_query_info->max_variable_size;
+
+ return ret;
}
/**
@@ -1228,7 +1477,70 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
u32 attributes, efi_uintn_t data_size,
const void *data)
{
- return EFI_UNSUPPORTED;
+ efi_status_t ret, mm_communicate_ret = EFI_SUCCESS;
+ struct var_check_property var_property;
+ struct smm_variable_access *var_acc;
+ efi_uintn_t payload_size;
+ efi_uintn_t name_size;
+ u8 *comm_buf = NULL;
+ bool ro;
+
+ if (!variable_name || variable_name[0] == 0 || !guid)
+ return EFI_INVALID_PARAMETER;
+
+ if (data_size > 0 && !data)
+ return EFI_INVALID_PARAMETER;
+
+ /* Check payload size */
+ name_size = u16_strsize(variable_name);
+ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
+ if (payload_size > max_payload_size)
+ return EFI_INVALID_PARAMETER;
+
+ ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
+ attributes &= EFI_VARIABLE_MASK;
+
+ ret = get_property_int_runtime(variable_name, name_size, guid,
+ &var_property);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ /*
+ * Allocate the buffer early, before switching to RW (if needed)
+ * so we won't need to account for any failures in reading/setting
+ * the properties, if the allocation fails
+ */
+ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
+ SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
+ if (!comm_buf)
+ return ret;
+
+ if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
+ return EFI_WRITE_PROTECTED;
+
+ /* Fill in contents */
+ efi_memcpy_runtime(&var_acc->guid, guid, sizeof(*guid));
+ var_acc->data_size = data_size;
+ var_acc->name_size = name_size;
+ var_acc->attr = attributes;
+ efi_memcpy_runtime(var_acc->name, variable_name, name_size);
+ efi_memcpy_runtime((u8 *)var_acc->name + name_size, data, data_size);
+
+ /* Communicate */
+ ret = mm_communicate_runtime(comm_buf, payload_size);
+ if (ret != EFI_SUCCESS)
+ mm_communicate_ret = ret;
+
+ if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
+ var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ var_property.attributes = attributes;
+ var_property.minsize = 1;
+ var_property.maxsize = var_acc->data_size;
+ ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
+ }
+
+ return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
}
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (3 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 12:03 ` Ilias Apalodimas
2026-04-28 18:25 ` Simon Glass
2026-04-24 17:31 ` [PATCH 06/12] corstone1000: enable bootefi selftest Harsimran Singh Tungal
` (9 subsequent siblings)
14 siblings, 2 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Consolidate runtime GetVariable helpers to avoid duplicates
The functions efi_get_variable_runtime() and
efi_get_next_variable_name_runtime() were implemented in
efi_variable_tee.c as part of the FF-A runtime variable handling work.
However, default implementations for these same runtime helpers also
exist in efi_var_common.c. This results in duplicate symbol definitions.
To resolve the conflict and centralize the runtime API, this patch moves
the default implementations of the two runtime GetVariable() helpers
from efi_var_common.c to efi_variable.c. This ensures that:
- only a single definition of each runtime helper exists,
- backend-specific implementations can override these cleanly,
- the EFI runtime variable service table continues to reference the
correct functions.
No functional changes are introduced; this is a structural cleanup to
avoid build-time conflicts and consolidate EFI runtime variable support
in the appropriate file.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
lib/efi_loader/efi_var_common.c | 24 ------------------------
lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
2 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
index d63c2d1b1cd..7cbf098c64a 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -173,30 +173,6 @@ efi_status_t EFIAPI efi_query_variable_info(
return EFI_EXIT(ret);
}
-efi_status_t __efi_runtime EFIAPI
-efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
- u32 *attributes, efi_uintn_t *data_size, void *data)
-{
- efi_status_t ret;
-
- ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
- data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
-
- /* Remove EFI_VARIABLE_READ_ONLY flag */
- if (attributes)
- *attributes &= EFI_VARIABLE_MASK;
-
- return ret;
-}
-
-efi_status_t __efi_runtime EFIAPI
-efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
- u16 *variable_name, efi_guid_t *guid)
-{
- return efi_get_next_variable_name_mem(variable_name_size, variable_name,
- guid, EFI_VARIABLE_RUNTIME_ACCESS);
-}
-
/**
* efi_set_secure_state - modify secure boot state variables
* @secure_boot: value of SecureBoot
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 9923936c1b5..f2e0e1ad4e2 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -579,6 +579,30 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
return EFI_SUCCESS;
}
+efi_status_t __efi_runtime EFIAPI
+efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
+ u32 *attributes, efi_uintn_t *data_size, void *data)
+{
+ efi_status_t ret;
+
+ ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
+ data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
+
+ /* Remove EFI_VARIABLE_READ_ONLY flag */
+ if (attributes)
+ *attributes &= EFI_VARIABLE_MASK;
+
+ return ret;
+}
+
+efi_status_t __efi_runtime EFIAPI
+efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
+ u16 *variable_name, efi_guid_t *guid)
+{
+ return efi_get_next_variable_name_mem(variable_name_size, variable_name,
+ guid, EFI_VARIABLE_RUNTIME_ACCESS);
+}
+
/**
* efi_variables_boot_exit_notify() - notify ExitBootServices() is called
*/
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 06/12] corstone1000: enable bootefi selftest
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (4 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-27 7:56 ` Ilias Apalodimas
2026-04-28 18:01 ` Simon Glass
2026-04-24 17:31 ` [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
` (8 subsequent siblings)
14 siblings, 2 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Enable UEFI selftest command in Corstone-1000 defconfig
Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
so the board can run the built-in UEFI self-test suite during
development and validation.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
configs/corstone1000_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
index 527a679b785..b5fb4868e0f 100644
--- a/configs/corstone1000_defconfig
+++ b/configs/corstone1000_defconfig
@@ -32,6 +32,8 @@ CONFIG_SYS_PROMPT="corstone1000# "
# CONFIG_CMD_CONSOLE is not set
CONFIG_CMD_FWU_METADATA=y
CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_BOOTEFI_HELLO is not set
+CONFIG_CMD_BOOTEFI_SELFTEST=y
# CONFIG_CMD_XIMG is not set
CONFIG_CMD_GPT=y
CONFIG_CMD_LOADM=y
@@ -63,6 +65,7 @@ CONFIG_SYSRESET=y
CONFIG_SYSRESET_PSCI=y
CONFIG_TEE=y
CONFIG_OPTEE=y
+# CONFIG_CMD_POWEROFF is not set
CONFIG_USB=y
CONFIG_USB_ISP1760=y
# CONFIG_RANDOM_UUID is not set
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (5 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 06/12] corstone1000: enable bootefi selftest Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:04 ` Simon Glass
2026-04-24 17:31 ` [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
` (7 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Extend runtime variable tests for persistent storage
Previously, EFI selftesting of runtime variables was only supported
under CONFIG_EFI_RT_VOLATILE_STORE, which uses VarToFile to simulate
non-volatile variable storage. This commit adds new test cases that
exercise runtime variable operations for persistent storage.
Features tested:
- Creation of runtime-accessible variables (set)
- Retrieval of runtime variables (get)
- Deletion using SetVariable() with size = 0
- Append operation using EFI_VARIABLE_APPEND_WRITE
This improves EFI compliance validation for non-volatile runtime storage
scenarios and ensures proper attribute enforcement and variable
management.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
.../efi_selftest_variables_runtime.c | 106 +++++++++++++++++-
1 file changed, 104 insertions(+), 2 deletions(-)
diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
index fd570d673f0..9a7ab18bc90 100644
--- a/lib/efi_selftest/efi_selftest_variables_runtime.c
+++ b/lib/efi_selftest/efi_selftest_variables_runtime.c
@@ -3,6 +3,7 @@
* efi_selftest_variables_runtime
*
* Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ * Copyright (c) 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* This unit test checks the runtime services for variables after
* ExitBootServices():
@@ -22,7 +23,13 @@ static const efi_guid_t efi_rt_var_guid = U_BOOT_EFI_RT_VAR_FILE_GUID;
/**
* execute() - execute unit test
*
- * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned.
+ * For EFI variables in non-volatile storage, these tests have to be executed in two phases
+ * 1. During first phase, run these tests and it creates EFI variable in persistent storage.
+ * 2. Then reboot and run the test again to verify if the variable created above is still
+ * available in non-volatile storage. If available, validate the EFI variable, append
+ * it, and validate it again. If validation is successful, delete the same variable.
+ *
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
*/
static int execute(void)
{
@@ -39,6 +46,80 @@ static int execute(void)
u64 max_storage, rem_storage, max_size;
int test_ret;
+ /* Compare the value of EFI variable if it already exists in non volatile storage */
+ if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
+ len = sizeof(v) / 2;
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
+ &attr, &len, data);
+ if (ret == EFI_SUCCESS) {
+ efi_st_printf("EFI Variable efi_st_var0 found. Executing Second Phase\n");
+ if (len != sizeof(v) / 2) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ if (memcmp(data, v, len)) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Append an existing variable */
+ append_len = sizeof(v) - len;
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_APPEND_WRITE |
+ EFI_VARIABLE_NON_VOLATILE,
+ append_len, (v + len));
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ len = sizeof(v);
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
+ &attr, &len, data);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ if (len != sizeof(v)) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ if (memcmp(data, v, len)) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Delete it by setting the size to 0 */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 0, NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
+ &attr, &len, data);
+ if (ret != EFI_NOT_FOUND) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+ } else {
+ if (ret == EFI_NOT_FOUND) {
+ efi_st_printf("EFI Variable efi_st_var0 not found. "
+ "Executing First Phase\n");
+ }
+ }
+ }
+
memset(v2, 0x1, sizeof(v2));
if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE)) {
@@ -279,7 +360,28 @@ static int execute(void)
return EFI_ST_FAILURE;
}
} else {
- if (ret != EFI_UNSUPPORTED) {
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Delete it by setting the size to 0 */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 0, NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Add an 8byte aligned variable */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof(v) / 2, v);
+ if (ret != EFI_SUCCESS) {
efi_st_error("SetVariable failed\n");
return EFI_ST_FAILURE;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (6 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:05 ` Simon Glass
2026-04-24 17:31 ` [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros Harsimran Singh Tungal
` (6 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Exercise FF-A runtime helpers via sandbox DM tests
Add driver-model unit tests that exercise the FF-A runtime helpers on
sandbox. The new tests reuse the sandbox emulator to validate both the
positive direct-request flow and failure handling, priming the emulator
state so the runtime path can be executed.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 ++++-
test/dm/Makefile | 3 +-
test/dm/ffa_runtime.c | 82 ++++++++++++++++++++++
3 files changed, 99 insertions(+), 2 deletions(-)
create mode 100644 test/dm/ffa_runtime.c
diff --git a/arch/sandbox/include/asm/sandbox_arm_ffa.h b/arch/sandbox/include/asm/sandbox_arm_ffa.h
index be2790f4960..a20eb159b73 100644
--- a/arch/sandbox/include/asm/sandbox_arm_ffa.h
+++ b/arch/sandbox/include/asm/sandbox_arm_ffa.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -26,6 +26,20 @@
#define SANDBOX_SP3_ID 0x6452
#define SANDBOX_SP4_ID 0x7814
+/*
+ * The sandbox FF-A emulator uses fixed, synthetic execution-context counts and
+ * property bitfields for each partition.
+ */
+#define SANDBOX_SP1_EXEC_CTXT 0x5687
+#define SANDBOX_SP2_EXEC_CTXT 0x9587
+#define SANDBOX_SP3_EXEC_CTXT 0x7687
+#define SANDBOX_SP4_EXEC_CTXT 0x1487
+
+#define SANDBOX_SP1_PROPERTIES 0x89325621
+#define SANDBOX_SP2_PROPERTIES 0x45325621
+#define SANDBOX_SP3_PROPERTIES 0x23325621
+#define SANDBOX_SP4_PROPERTIES 0x70325621
+
/* Invalid service UUID (no matching SP) */
#define SANDBOX_SERVICE3_UUID "55d532ed-0942-e699-722d-c09ca798d9cd"
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 771b703b737..ee1298ba572 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2013 Google, Inc
-# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+# Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
# Tests for particular subsystems - when enabling driver model for a new
# subsystem you must add sandbox tests here.
@@ -96,6 +96,7 @@ obj-$(CONFIG_ACPI_PMC) += pmc.o
obj-$(CONFIG_DM_PMIC) += pmic.o
obj-$(CONFIG_DM_PWM) += pwm.o
obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa.o
+obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa_runtime.o
obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_RAM) += ram.o
obj-y += regmap.o
diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
new file mode 100644
index 00000000000..4ba859fa314
--- /dev/null
+++ b/test/dm/ffa_runtime.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Functional tests for FF-A runtime helpers
+ *
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
+ */
+
+#include <dm.h>
+#include <dm/test.h>
+#include <asm/sandbox_arm_ffa.h>
+#include <asm/sandbox_arm_ffa_priv.h>
+#include <arm_ffa_runtime.h>
+#include <test/ut.h>
+
+static int ffa_runtime_get_sp_id(struct unit_test_state *uts, u16 *sp_id)
+{
+ struct ffa_partition_desc *descs;
+ u32 count;
+ struct udevice *dev;
+ const char *svc_uuid = SANDBOX_SERVICE1_UUID;
+
+ ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
+ ut_assertok(ffa_partition_info_get(dev, svc_uuid, &count, &descs));
+ ut_assert(count > 0);
+
+ *sp_id = descs[0].info.id;
+ return 0;
+}
+
+static int dm_test_ffa_runtime_ack(struct unit_test_state *uts)
+{
+ struct ffa_send_direct_data msg = {0};
+ u16 sp_id;
+ u8 cnt;
+
+ ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
+
+ ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
+ .id = NS_PHYS_ENDPOINT_ID,
+ });
+ ffa_enable_runtime_context();
+
+ /* Ensure runtime context is available before attempting runtime-only paths */
+ ut_assert(ffa_get_status_runtime_context());
+
+ /* Runtime messaging should reuse the sandbox emulator and return 0xff pattern */
+ ut_assertok(ffa_sync_send_receive_runtime(sp_id, &msg, true));
+ for (cnt = 0; cnt < sizeof(struct ffa_send_direct_data) / sizeof(u64); cnt++)
+ ut_asserteq_64(-1UL, ((u64 *)&msg)[cnt]);
+
+ /* Validate FF-A error to errno translation helpers */
+ ut_asserteq(-EINVAL, ffa_to_std_errno(-INVALID_PARAMETERS));
+ ut_asserteq(-EOPNOTSUPP, ffa_to_std_errno(-NOT_SUPPORTED));
+
+ return 0;
+}
+DM_TEST(dm_test_ffa_runtime_ack, UTF_SCAN_FDT | UTF_CONSOLE);
+
+static int dm_test_ffa_runtime_nack(struct unit_test_state *uts)
+{
+ struct ffa_send_direct_data msg = {0};
+ u16 sp_id;
+
+ ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
+
+ ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
+ .id = NS_PHYS_ENDPOINT_ID,
+ });
+ ffa_enable_runtime_context();
+
+ /* Ensure runtime context is available before attempting runtime-only paths */
+ ut_assert(ffa_get_status_runtime_context());
+
+ /* Invalid partition IDs must be rejected and mapped to -EINVAL */
+ ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0, &msg, true));
+
+ return 0;
+}
+DM_TEST(dm_test_ffa_runtime_nack, UTF_SCAN_FDT | UTF_CONSOLE);
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (7 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:07 ` Simon Glass
2026-04-24 17:31 ` [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
` (5 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Reuse sandbox FF-A partition constants in emulator tests
Allow the sandbox FF-A emulator test to use execution-context and property
constants defined in sandbox_arm_ffa.h
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 ++++++++++++++++------
1 file changed, 26 insertions(+), 10 deletions(-)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
index d270f7b614e..219286971dd 100644
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -19,41 +19,57 @@
/* The partitions (SPs) table */
static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
{
- .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
+ .info = {
+ .id = SANDBOX_SP1_ID,
+ .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
+ .properties = SANDBOX_SP1_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE1_UUID_A1,
.a2 = SANDBOX_SERVICE1_UUID_A2,
.a3 = SANDBOX_SERVICE1_UUID_A3,
.a4 = SANDBOX_SERVICE1_UUID_A4,
- }
+ },
},
{
- .info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
+ .info = {
+ .id = SANDBOX_SP2_ID,
+ .exec_ctxt = SANDBOX_SP2_EXEC_CTXT,
+ .properties = SANDBOX_SP2_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE2_UUID_A1,
.a2 = SANDBOX_SERVICE2_UUID_A2,
.a3 = SANDBOX_SERVICE2_UUID_A3,
.a4 = SANDBOX_SERVICE2_UUID_A4,
- }
+ },
},
{
- .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
+ .info = {
+ .id = SANDBOX_SP3_ID,
+ .exec_ctxt = SANDBOX_SP3_EXEC_CTXT,
+ .properties = SANDBOX_SP3_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE1_UUID_A1,
.a2 = SANDBOX_SERVICE1_UUID_A2,
.a3 = SANDBOX_SERVICE1_UUID_A3,
.a4 = SANDBOX_SERVICE1_UUID_A4,
- }
+ },
},
{
- .info = { .id = SANDBOX_SP4_ID, .exec_ctxt = 0x1487, .properties = 0x70325621 },
+ .info = {
+ .id = SANDBOX_SP4_ID,
+ .exec_ctxt = SANDBOX_SP4_EXEC_CTXT,
+ .properties = SANDBOX_SP4_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE2_UUID_A1,
.a2 = SANDBOX_SERVICE2_UUID_A2,
.a3 = SANDBOX_SERVICE2_UUID_A3,
.a4 = SANDBOX_SERVICE2_UUID_A4,
- }
- }
+ },
+ },
};
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (8 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:08 ` Simon Glass
2026-05-08 10:40 ` Abdellatif El Khlifi
2026-04-24 17:31 ` [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
` (4 subsequent siblings)
14 siblings, 2 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Document how EFI runtime variables use FF-A MM communication
Describe the FF-A runtime layer on arm64 and how EFI variable
runtime services use the FF-A transport and shared MM buffer.
Also clarify armffa command scope and link to the FF-A doc.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
doc/arch/arm64.ffa.rst | 92 +++++++++++++++++++++++++++++++++++++---
doc/usage/cmd/armffa.rst | 11 +++++
2 files changed, 96 insertions(+), 7 deletions(-)
diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
index f966f8ba6af..ff0efb7da1d 100644
--- a/doc/arch/arm64.ffa.rst
+++ b/doc/arch/arm64.ffa.rst
@@ -15,10 +15,10 @@ application in S-EL0, or a Trusted OS in S-EL1.
The U-Boot FF-A support (the bus) implements the interfaces to communicate
with partitions in the Secure world aka Secure partitions (SPs).
-The FF-A support specifically focuses on communicating with SPs that
-isolate portions of EFI runtime services that must run in a protected
-environment which is inaccessible by the Host OS or Hypervisor.
-Examples of such services are set/get variables.
+U-Boot's FF-A bus support exposes an optional transport that EFI runtime
+services can use to communicate with Secure Partitions. Through this
+interface, EFI services (such as variable access) can request or exchange
+data with the Secure World using FF-A.
The FF-A support uses the SMC ABIs defined by the FF-A specification to:
@@ -26,13 +26,13 @@ The FF-A support uses the SMC ABIs defined by the FF-A specification to:
- Access an SP's service through communication protocols
e.g. EFI MM communication protocol
-At this stage of development only EFI boot-time services are supported.
-Runtime support will be added in future developments.
-
The U-Boot FF-A support provides the following parts:
- A Uclass driver providing generic FF-A methods.
- An Arm FF-A device driver providing Arm-specific methods and reusing the Uclass methods.
+- An optional runtime FF-A transport (toggled via CONFIG_ARM_FFA_RT_MODE) that is
+ resident after ExitBootServices() and enables EFI runtime variable services
+ via FF-A helpers and a shared MM communication buffer.
- A sandbox emulator for Arm FF-A, emulates the FF-A side of the Secure World and provides
FF-A ABIs inspection methods.
- An FF-A sandbox device driver for FF-A communication with the emulated Secure World.
@@ -69,6 +69,12 @@ CONFIG_ARM_FFA_TRANSPORT
When using an Arm 64-bit platform, the Arm FF-A driver will be used.
When using sandbox, the sandbox FF-A emulator and FF-A sandbox driver will be used.
+CONFIG_ARM_FFA_RT_MODE
+ Enables the FF-A runtime transport. This option depends on
+ CONFIG_ARM_FFA_TRANSPORT and CONFIG_EFI_LOADER, and is enabled by default.
+ When enabled, a minimal set of FF-A operations remains available after
+ ExitBootServices().
+
FF-A ABIs under the hood
------------------------
@@ -158,6 +164,77 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
the 32-bit or 64-bit version of FFA_MSG_SEND_DIRECT_{REQ, RESP}.
The calling convention between U-Boot and the secure world stays the same: SMC32.
+FF-A runtime support for EFI variables
+--------------------------------------
+
+U-Boot provides an FF-A runtime transport to keep a minimal set of FF-A operations
+available after ExitBootServices(). This runtime transport is enabled with
+CONFIG_ARM_FFA_RT_MODE. The runtime helpers and data are marked with
+``__efi_runtime`` / ``__efi_runtime_data`` through the
+``__ffa_runtime`` / ``__ffa_runtime_data`` aliases in
+``include/arm_ffa_runtime.h``.
+
+Runtime context is enabled at ExitBootServices(), and the following prerequisites
+are prepared during FF-A bus probe:
+
+- The U-Boot FF-A endpoint ID is discovered at boot time with FFA_ID_GET and
+ stored in the runtime private data.
+- An ExitBootServices() event is registered by the runtime transport to enable
+ the runtime context with ffa_enable_runtime_context() when EFI transitions
+ to runtime.
+
+At runtime, the driver model is no longer available. Runtime users should
+use the runtime interface ffa_sync_send_receive_runtime(), which internally
+verifies the runtime context before issuing FF-A calls.
+
+EFI variable services over FF-A
+-------------------------------
+
+When CONFIG_EFI_MM_COMM_TEE and CONFIG_ARM_FFA_TRANSPORT are enabled, U-Boot
+routes EFI variable services to an MM Secure Partition (SP) over FF-A.
+The MM SP is discovered at boot time using FFA_PARTITION_INFO_GET and its
+partition ID is cached in runtime data.
+
+The data path uses a shared MM communication buffer and a door-bell style
+direct message:
+
+- The communication buffer is located at CONFIG_FFA_SHARED_MM_BUF_ADDR and
+ sized by CONFIG_FFA_SHARED_MM_BUF_SIZE.
+- CONFIG_FFA_SHARED_MM_BUF_OFFSET is sent in the FF-A direct message payload
+ to indicate where the data begins.
+- The buffer is filled by memcpy(), the cache is flushed before notifying the
+ MM SP, and later the buffer is reused directly with only the shared-buffer
+ range invalidated (invalidate_dcache_range()) to avoid whole-cache
+ invalidation.
+
+After ExitBootServices(), EFI SetVariable()/GetVariable() call paths use the
+runtime MM communication helpers:
+
+- get_comm_buf() switches to the static shared buffer
+- mm_communicate_runtime() selects FF-A transport when the runtime context
+ is enabled
+- ffa_mm_communicate_runtime() issues FFA_MSG_SEND_DIRECT_{REQ,RESP} through
+ ffa_sync_send_receive_runtime()
+
+Configuration notes
+-------------------
+
+Enable FF-A transport and MM communication:
+
+- CONFIG_ARM_FFA_TRANSPORT
+- CONFIG_ARM_FFA_RT_MODE
+- CONFIG_EFI_MM_COMM_TEE
+
+CONFIG_ARM_FFA_RT_MODE is enabled by default. It turns on MM communication for
+EFI runtime and may be disabled when EFI services over FF-A are not required
+after ExitBootServices().
+
+Configure the shared MM communication buffer:
+
+- CONFIG_FFA_SHARED_MM_BUF_ADDR
+- CONFIG_FFA_SHARED_MM_BUF_SIZE
+- CONFIG_FFA_SHARED_MM_BUF_OFFSET
+
Requirements for user drivers
-----------------------------
@@ -256,6 +333,7 @@ For example, when using FF-A with Corstone-1000, debug logs enabled, the output
Contributors
------------
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
.. _`FF-A v1.0 specification`: https://documentation-service.arm.com/static/5fb7e8a6ca04df4095c1d65e
.. _`SMC Calling Convention v1.2 specification`: https://documentation-service.arm.com/static/5f8edaeff86e16515cdbe4c6
diff --git a/doc/usage/cmd/armffa.rst b/doc/usage/cmd/armffa.rst
index dbe4d5bc842..2b865f88015 100644
--- a/doc/usage/cmd/armffa.rst
+++ b/doc/usage/cmd/armffa.rst
@@ -39,6 +39,17 @@ The command also allows to gather secure partitions information and ping these
The command is also helpful in testing the communication with secure partitions.
+Notes
+-----
+
+armffa is a boot-time test command. It relies on the FF-A driver model device
+(UCLASS_FFA) and is not intended for EFI runtime use after
+ExitBootServices().
+
+armffa does not provide EFI variable operations. For more information about
+using EFI runtime SetVariable() and GetVariable() over FF-A please see
+:doc:`../../arch/arm64.ffa`.
+
Example
-------
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (9 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:14 ` Simon Glass
2026-04-24 17:31 ` [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path Harsimran Singh Tungal
` (3 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Explain how the runtime variable selftest runs in two phases
Document that the "variables at runtime" selftest runs in two
phases when CONFIG_EFI_RT_VOLATILE_STORE is not enabled, and
show how to select it with efi_selftest.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
doc/usage/cmd/bootefi.rst | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
index 7c5448586b7..91aebf1a4b5 100644
--- a/doc/usage/cmd/bootefi.rst
+++ b/doc/usage/cmd/bootefi.rst
@@ -160,6 +160,16 @@ environment variable to match one of the listed identifiers
Some of the tests execute the ExitBootServices() UEFI boot service and will not
return to the command line but require a board reset.
+The test *variables at runtime* runs in two phases when
+CONFIG_EFI_RT_VOLATILE_STORE is not enabled. Run it once to create a
+runtime-accessible variable in non-volatile storage, reboot, then run it
+again to validate, append, and delete that variable.
+
+::
+
+ => setenv efi_selftest 'variables at runtime'
+ => bootefi selftest
+
Configuration
-------------
@@ -167,6 +177,8 @@ To use the *bootefi* command you must specify CONFIG_CMD_BOOTEFI=y.
The *bootefi bootmgr* sub-command requries CMD_BOOTEFI_BOOTMGR=y.
The *bootefi hello* sub-command requries CMD_BOOTEFI_HELLO=y.
The *bootefi selftest* sub-command depends on CMD_BOOTEFI_SELFTEST=y.
+The *variables at runtime* selftest runs in two phases when
+CONFIG\_EFI\_RT\_VOLATILE\_STORE is not enabled.
See also
--------
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (10 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
@ 2026-04-24 17:31 ` Harsimran Singh Tungal
2026-04-28 18:14 ` Simon Glass
2026-04-24 22:18 ` [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Heinrich Schuchardt
` (2 subsequent siblings)
14 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-04-24 17:31 UTC (permalink / raw)
To: u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass,
Harsimran Singh Tungal
Match boot-time FF-A cache handling to runtime behavior
The boot-time FF-A MM communication path used invalidate_dcache_all()
after copying the message into the shared buffer. This differs from the
runtime path, which performs range-based maintenance to avoid global cache
operations.
Update ffa_mm_communicate() to use the same pattern as the runtime helper:
clean the shared buffer range before the SMC and invalidate the same range
after the response. This keeps boot-time and runtime behavior consistent
and avoids whole-cache invalidation.
Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
lib/efi_loader/efi_variable_tee.c | 33 ++++++++++++++++++++++++-------
1 file changed, 26 insertions(+), 7 deletions(-)
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 30687c21b8e..df509a435b1 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
memcpy(virt_shared_buf, comm_buf, tx_data_size);
/*
- * The secure world might have cache disabled for
- * the device region used for shared buffer (which is the case for Optee).
- * In this case, the secure world reads the data from DRAM.
- * Let's flush the cache so the DRAM is updated with the latest data.
+ * Shared buffer cache maintenance for FF-A / OP-TEE communication:
+ *
+ * NS -> S (request path):
+ *
+ * The non-secure side populates the shared buffer. If the buffer is cached
+ * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
+ * visible in DDR. Since the secure world typically reads the shared buffer
+ * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
+ * must clean the corresponding cache lines to the Point of Coherency (PoC)
+ * before entering secure world.
+ *
+ * S -> NS (response path):
+ *
+ * The secure world may update the same shared buffer in DDR. After returning
+ * to non-secure, any cached copies of that region in NS may be stale. We
+ * therefore invalidate the shared buffer range after the FF-A call to drop
+ * those lines and force subsequent reads to fetch the latest data from DDR.
*/
-#ifdef CONFIG_ARM64
- invalidate_dcache_all();
-#endif
+ if (IS_ENABLED(CONFIG_ARM64))
+ flush_dcache_range((unsigned long)virt_shared_buf,
+ (unsigned long)virt_shared_buf +
+ CONFIG_FFA_SHARED_MM_BUF_SIZE);
/* Announce there is data in the shared buffer */
ffa_ret = ffa_notify_mm_sp();
+ if (IS_ENABLED(CONFIG_ARM64))
+ invalidate_dcache_range((unsigned long)virt_shared_buf,
+ (unsigned long)virt_shared_buf +
+ CONFIG_FFA_SHARED_MM_BUF_SIZE);
+
switch (ffa_ret) {
case 0: {
ulong rx_data_size;
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* Re: [PATCH 00/12] arm64: FF-A runtime transport for EFI variables
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (11 preceding siblings ...)
2026-04-24 17:31 ` [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path Harsimran Singh Tungal
@ 2026-04-24 22:18 ` Heinrich Schuchardt
2026-05-05 14:37 ` Harsimran Singh Tungal
2026-04-28 18:16 ` [00/12] " Simon Glass
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
14 siblings, 1 reply; 77+ messages in thread
From: Heinrich Schuchardt @ 2026-04-24 22:18 UTC (permalink / raw)
To: Harsimran Singh Tungal, u-boot
Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Hugues Kamba Mpiana, Simon Glass
Am 24. April 2026 19:31:39 MESZ schrieb Harsimran Singh Tungal <harsimransingh.tungal@arm.com>:
>Hi all,
>
>This series adds FF-A runtime transport support so EFI variable runtime
>services can communicate with the secure world after ExitBootServices().
>It also extends tests, docs, and board configs to validate the runtime
>path and keep boot‑time behavior aligned with the runtime flow.
Hello Harsiman,
Could you, please, explain the motivation for the series.
What is the overall architecture?
Please, describe how to set up a system on QEMU to test your development including the instructions for the secure world.
We would need a test in the CI using QEMU.
Best regards
Heinrich
>
>Changes in this series:
>- Add EFI runtime-safe memset helper and FF-A runtime transport support.
>- Implement FF-A runtime communication in the EFI variable TEE backend.
>- Enable runtime variable operations and move helpers to avoid conflicts.
>- Add sandbox runtime transport tests and metadata reuse.
>- Extend EFI selftests for runtime variables and bootefi selftest config.
>- Document the FF-A runtime transport and selftest behavior.
>- Align boot‑time cache maintenance with the runtime path.
>
>Harsimran Singh Tungal (12):
> efi_loader: add runtime memset helper
> arm-ffa: add FF-A bus runtime support
> efi_loader: add FF-A runtime support in EFI variable TEE driver
> efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A
> transport
> efi_loader: move runtime GetVariable() helpers to efi_variable.c
> corstone1000: enable bootefi selftest
> efi: selftest: add runtime variable tests with non-volatile storage
> test: dm: add sandbox FF-A runtime transport tests
> sandbox: ffa: share synthetic partition metadata via macros
> doc: arm64: document FF-A runtime path for EFI variables
> doc: bootefi: note two-phase runtime variables selftest
> efi_loader: align FF-A cache maintenance with runtime path
>
> arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +-
> configs/corstone1000_defconfig | 3 +
> doc/arch/arm64.ffa.rst | 92 ++-
> doc/usage/cmd/armffa.rst | 11 +
> doc/usage/cmd/bootefi.rst | 12 +
> drivers/firmware/arm-ffa/Kconfig | 11 +
> drivers/firmware/arm-ffa/Makefile | 4 +-
> drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 ++++++++
> drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 +--
> drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
> drivers/firmware/arm-ffa/ffa-emul-uclass.c | 48 +-
> include/arm_ffa.h | 16 +-
> include/arm_ffa_priv.h | 24 +-
> include/arm_ffa_runtime.h | 183 +++++
> include/efi_loader.h | 3 +
> lib/charset.c | 2 +-
> lib/efi_loader/efi_runtime.c | 21 +
> lib/efi_loader/efi_var_common.c | 24 -
> lib/efi_loader/efi_variable.c | 24 +
> lib/efi_loader/efi_variable_tee.c | 686 +++++++++++++++++-
> .../efi_selftest_variables_runtime.c | 106 ++-
> test/dm/Makefile | 3 +-
> test/dm/ffa.c | 6 +-
> test/dm/ffa_runtime.c | 82 +++
> 24 files changed, 1602 insertions(+), 189 deletions(-)
> create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
> create mode 100644 include/arm_ffa_runtime.h
> create mode 100644 test/dm/ffa_runtime.c
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 01/12] efi_loader: add runtime memset helper
2026-04-24 17:31 ` [PATCH 01/12] efi_loader: add runtime memset helper Harsimran Singh Tungal
@ 2026-04-27 7:54 ` Ilias Apalodimas
2026-04-28 18:08 ` Simon Glass
1 sibling, 0 replies; 77+ messages in thread
From: Ilias Apalodimas @ 2026-04-27 7:54 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
Hugues Kamba Mpiana, Simon Glass
On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> Add efi_memset_runtime() for EFI runtime paths
>
> This keeps buffer initialization in runtime-resident code after
> ExitBootServices() and avoids relying on non-runtime helpers.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> ---
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> include/efi_loader.h | 3 +++
> lib/efi_loader/efi_runtime.c | 21 +++++++++++++++++++++
> 2 files changed, 24 insertions(+)
>
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> index 3a4d502631c..63944192aeb 100644
> --- a/include/efi_loader.h
> +++ b/include/efi_loader.h
> @@ -1151,6 +1151,9 @@ void efi_memcpy_runtime(void *dest, const void *src, size_t n);
> /* runtime implementation of memcmp() */
> int efi_memcmp_runtime(const void *s1, const void *s2, size_t n);
>
> +/* runtime implementation of memset */
> +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n);
> +
> /* commonly used helper functions */
> u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
> unsigned int index);
> diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
> index 73d4097464c..d9604399209 100644
> --- a/lib/efi_loader/efi_runtime.c
> +++ b/lib/efi_loader/efi_runtime.c
> @@ -233,6 +233,27 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
> return 0;
> }
>
> +/**
> + * efi_memset_runtime() - fill a memory region with a byte value
> + *
> + * At runtime memset() is not available.
> + *
> + * @dest: pointer to the block of memory to fill.
> + * @c: value to be set. The value is passed as an int, but the
> + * function fills the block of memory using the u8 conversion of this value.
> + * @n: number of bytes to be set to the value.
> + * Return: dest is returned
> + */
> +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
> +{
> + u8 *d = dest;
> +
> + for (; n; --n)
> + *d++ = c;
> +
> + return dest;
> +}
> +
> /**
> * efi_update_table_header_crc32() - Update crc32 in table header
> *
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 06/12] corstone1000: enable bootefi selftest
2026-04-24 17:31 ` [PATCH 06/12] corstone1000: enable bootefi selftest Harsimran Singh Tungal
@ 2026-04-27 7:56 ` Ilias Apalodimas
2026-04-28 18:01 ` Simon Glass
1 sibling, 0 replies; 77+ messages in thread
From: Ilias Apalodimas @ 2026-04-27 7:56 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
Hugues Kamba Mpiana, Simon Glass
On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> Enable UEFI selftest command in Corstone-1000 defconfig
>
> Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> so the board can run the built-in UEFI self-test suite during
> development and validation.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> ---
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> configs/corstone1000_defconfig | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> index 527a679b785..b5fb4868e0f 100644
> --- a/configs/corstone1000_defconfig
> +++ b/configs/corstone1000_defconfig
> @@ -32,6 +32,8 @@ CONFIG_SYS_PROMPT="corstone1000# "
> # CONFIG_CMD_CONSOLE is not set
> CONFIG_CMD_FWU_METADATA=y
> CONFIG_CMD_BOOTZ=y
> +# CONFIG_CMD_BOOTEFI_HELLO is not set
> +CONFIG_CMD_BOOTEFI_SELFTEST=y
> # CONFIG_CMD_XIMG is not set
> CONFIG_CMD_GPT=y
> CONFIG_CMD_LOADM=y
> @@ -63,6 +65,7 @@ CONFIG_SYSRESET=y
> CONFIG_SYSRESET_PSCI=y
> CONFIG_TEE=y
> CONFIG_OPTEE=y
> +# CONFIG_CMD_POWEROFF is not set
> CONFIG_USB=y
> CONFIG_USB_ISP1760=y
> # CONFIG_RANDOM_UUID is not set
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-04-24 17:31 ` [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
@ 2026-04-27 16:21 ` Ilias Apalodimas
2026-05-04 20:40 ` Harsimran Singh Tungal
2026-05-08 10:23 ` Abdellatif El Khlifi
2026-04-28 18:12 ` Simon Glass
1 sibling, 2 replies; 77+ messages in thread
From: Ilias Apalodimas @ 2026-04-27 16:21 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> Enable MM variable services over FF-A after ExitBootServices
>
> This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
> communication with the secure world during EFI runtime. It enables EFI
> runtime variable access and MM communication using FF-A transport when
> ExitBootServices() has already been called.
>
> Key changes:
> ------------
> - Introduce runtime-safe implementations for MM communication,
> notification, and variable access using FF-A driver.
> - Introduce communication-buffer helper (get_comm_buf()) that switches
> between dynamic allocation (boot phase) and the fixed FF-A shared
> buffer (runtime phase).
> - Mark persistent data and code with __efi_runtime and
> __efi_runtime_data attributes.
> - Use direct physical address mapping for shared buffers since
> U-Boot operates with 1:1 physical-to-virtual mapping.
> - Only per-buffer cache maintenance is performed at runtime,
> as whole D-cache invalidation would violate the OS coherency model
> after ExitBootServices().
> - Add runtime-phase tracking (efi_runtime_enabled).
Why is this needed? For the memory allocations?
[...]
> *
> * Authors:
> * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> @@ -14,6 +14,7 @@
>
> #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> #include <arm_ffa.h>
> +#include <arm_ffa_runtime.h>
> #endif
> #include <cpu_func.h>
> #include <dm.h>
> @@ -34,20 +35,47 @@
> #define MM_DENIED (-3)
> #define MM_NO_MEMORY (-5)
>
> +static const int __efi_runtime_rodata mm_sp_errmap[] = {
> + [-MM_NOT_SUPPORTED] = -EINVAL,
> + [-MM_INVALID_PARAMETER] = -EPERM,
> + [-MM_DENIED] = -EACCES,
> + [-MM_NO_MEMORY] = -EBUSY,
> +};
> +
These are already defined above and used in ffa_notify_mm_sp(). If you
plan to convert them, do it for the entire file.
[...]
> +/**
> + * efi_is_runtime_enabled() - Indicate whether the system is in the UEFI runtime phase
> + *
> + * This helper returns whether the firmware has transitioned into the
> + * UEFI runtime phase, meaning that ExitBootServices() has been invoked.
> + *
> + * Return:
> + * true - The system is operating in UEFI runtime mode.
> + * false - The system is still in the boot services phase.
> + */
> +static bool __efi_runtime efi_is_runtime_enabled(void)
> +{
> + return efi_runtime_enabled;
> +}
Enabled is a bit confusing. efi_at_runtime() should be enough. The
efi_tcg.c code calls this 'ebs_called'
> +
> /**
> * get_connection() - Retrieve OP-TEE session for a specific UUID.
> *
> @@ -169,6 +197,28 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
> }
>
> #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> +/**
> + * ffa_map_sp_event_runtime() - Map MM SP response to errno (runtime-safe)
> + * @sp_event_ret: MM SP return code from ffa_notify_mm_sp_runtime()
> + *
> + * Convert the MM SP return code into a standard U-Boot errno. This helper
> + * is marked __efi_runtime to ensure it is safe to call after
> + * ExitBootServices().
> + *
> + * Return: 0 on success, negative errno on failure
> + */
> +static __efi_runtime int ffa_map_sp_event_runtime(int sp_event_ret)
> +{
> + int idx = -sp_event_ret;
> +
> + if (sp_event_ret == MM_SUCCESS)
> + return 0;
> + if (idx > 0 && idx < (int)ARRAY_SIZE(mm_sp_errmap) &&
> + mm_sp_errmap[idx])
> + return mm_sp_errmap[idx];
> + return -EACCES;
> +}
> +
> /**
> * ffa_notify_mm_sp() - Announce there is data in the shared buffer
> *
> @@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
> return ret;
> }
>
> +/**
> + * ffa_notify_mm_sp_runtime() - Runtime implementation of
> + * ffa_notify_mm_sp()
> + *
> + * Notify the MM partition in the trusted world that
> + * data is available in the shared buffer.
> + * This is a blocking call during which trusted world has exclusive access
> + * to the MM shared buffer.
> + *
> + * Return:
> + *
> + * 0 on success
> + */
> +static int __efi_runtime ffa_notify_mm_sp_runtime(void)
> +{
> + struct ffa_send_direct_data msg = {0};
> + int ret;
> + int sp_event_ret;
> +
> + msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
> +
> + ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
> + if (ret)
> + return ret;
> +
> + ret = ffa_map_sp_event_runtime(sp_event_ret);
> + return ret;
> +}
> +
> /**
> * ffa_discover_mm_sp_id() - Query the MM partition ID
> *
> @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> return efi_ret;
> }
>
> +/**
> + * ffa_mm_communicate_runtime() - Runtime implementation of ffa_mm_communicate()
> + * @comm_buf: locally allocated communication buffer used for rx/tx
> + * @comm_buf_size: communication buffer size
> + *
> + * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
> + * that there is data to read from the shared buffer.
> + * Communication with the MM SP is performed using FF-A transport.
> + * On the event, MM SP can read the data from the buffer and
> + * update the MM shared buffer with response data.
> + * The response data is copied back to the communication buffer.
> + *
> + * Return:
> + *
> + * EFI status code
> + */
> +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> + ulong comm_buf_size)
> +{
There's a lot of code duplication between the boottime and runtime
variants, but I don;t see why we need it. Can't we have a single
function that works both boottime and runtime?
[...]
> + * must clean the corresponding cache lines to the Point of Coherency (PoC)
> + * before entering secure world.
> + *
> + * S -> NS (response path):
> + *
> + * The secure world may update the same shared buffer in DDR. After returning
> + * to non-secure, any cached copies of that region in NS may be stale. We
> + * therefore invalidate the shared buffer range after the FF-A call to drop
> + * those lines and force subsequent reads to fetch the latest data from DDR.
> + *
> + * Note: Whole-cache invalidation must not be used in EFI runtime context.
> + * After ExitBootServices(), the OS owns the cache hierarchy; global invalidation
> + * could drop OS dirty lines and violate the OS coherency model. Always operate
> + * on the shared buffer range only.
> + */
> + if (IS_ENABLED(CONFIG_ARM64))
> + flush_dcache_range((unsigned long)comm_buf,
This doesn't seem to be marked as efi_runtime. How was this patchset tested?
> + (unsigned long)((u8 *)comm_buf +
> + CONFIG_FFA_SHARED_MM_BUF_SIZE));
> +
> + /* Announce there is data in the shared buffer */
> +
> + ffa_ret = ffa_notify_mm_sp_runtime();
> +
> + if (IS_ENABLED(CONFIG_ARM64))
> + invalidate_dcache_range((unsigned long)comm_buf,
> + (unsigned long)((u8 *)comm_buf +
> + CONFIG_FFA_SHARED_MM_BUF_SIZE));
> +
> + switch (ffa_ret) {
> + case 0: {
[...]
>
> /**
> @@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> return var_hdr->ret_status;
> }
>
> +/**
> + * mm_communicate_runtime() - Runtime implementation of mm_communicate()
> + *
> + * @comm_buf: locally allocated communication buffer
> + * @dsize: buffer size
> + *
> + * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
> + * The comm_buf format is the same for both partitions.
> + * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
> + * When using the u-boot FF-A driver, any MM SP is supported.
> + *
> + * Return: status code
> + */
> +static efi_status_t __efi_runtime mm_communicate_runtime(u8 *comm_buf, efi_uintn_t dsize)
> +{
> + efi_status_t ret = EFI_UNSUPPORTED;
> + struct efi_mm_communicate_header *mm_hdr;
> + struct smm_variable_communicate_header *var_hdr;
> + enum mm_comms_select mm_comms;
> +
> + dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
> + mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
> + var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
> +
> + if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) {
> + mm_comms = get_mm_comms_runtime();
> + if (mm_comms == MM_COMMS_FFA)
> + ret = ffa_mm_communicate_runtime(comm_buf, dsize);
Same remarks here. I think having a single variant instead of an
_runtime one is going to be easier to maintain. Especially for the
functions that are very similar.
> + }
> +
> + if (ret != EFI_SUCCESS)
> + return ret;
> +
> + return var_hdr->ret_status;
> +}
> +
> +/**
[...]
> - efi_uintn_t func, efi_status_t *ret)
> +static __efi_runtime u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
> + efi_uintn_t func, efi_status_t *ret)
> {
> - const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
> struct efi_mm_communicate_header *mm_hdr;
> struct smm_variable_communicate_header *var_hdr;
> u8 *comm_buf;
> @@ -465,16 +751,15 @@ static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
> return NULL;
> }
>
> - comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
> - MM_VARIABLE_COMMUNICATE_SIZE +
> - payload_size);
> + comm_buf = get_comm_buf(payload_size);
> if (!comm_buf) {
> *ret = EFI_OUT_OF_RESOURCES;
> return NULL;
> }
>
> mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
> - guidcpy(&mm_hdr->header_guid, &mm_var_guid);
> + efi_memcpy_runtime(&mm_hdr->header_guid, &mm_var_guid_runtime,
> + sizeof(mm_hdr->header_guid));
> mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
>
> var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
> @@ -982,6 +1267,9 @@ void efi_variables_boot_exit_notify(void)
> efi_get_next_variable_name_runtime;
> efi_runtime_services.set_variable = efi_set_variable_runtime;
> efi_update_table_header_crc32(&efi_runtime_services.hdr);
> +
> + /* Set efi_runtime_enabled as true after ExitBootServices */
> + efi_runtime_enabled = true;
> }
>
> /**
> @@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
> {
> efi_status_t ret;
>
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + /*
> + * The FF-A shared buffer is accessed by EFI runtime services, so it must
> + * be marked as runtime memory in the EFI memory map.
> + */
> + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> + ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
> + CONFIG_FFA_SHARED_MM_BUF_SIZE,
> + EFI_RUNTIME_SERVICES_DATA);
> + if (ret != EFI_SUCCESS) {
> + log_err("EFI: failed to add FF-A shared buffer to runtime map (%lu)\n",
> + ret);
> + return ret;
> + }
> + log_info("EFI: FF-A shared buffer runtime map: addr=0x%lx size=0x%lx\n",
> + (ulong)CONFIG_FFA_SHARED_MM_BUF_ADDR,
> + (ulong)CONFIG_FFA_SHARED_MM_BUF_SIZE);
> + }
> +
You should remove the memory map reservation if any of the code below fails.
> /* Create a cached copy of the variables that will be enabled on ExitBootServices() */
> ret = efi_var_mem_init();
> if (ret != EFI_SUCCESS)
> --
> 2.34.1
>
Thanks
/Ilias
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c
2026-04-24 17:31 ` [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c Harsimran Singh Tungal
@ 2026-04-28 12:03 ` Ilias Apalodimas
2026-05-06 10:30 ` Harsimran Singh Tungal
2026-04-28 18:25 ` Simon Glass
1 sibling, 1 reply; 77+ messages in thread
From: Ilias Apalodimas @ 2026-04-28 12:03 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
Hugues Kamba Mpiana, Simon Glass
Hi Harsiman,
On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> Consolidate runtime GetVariable helpers to avoid duplicates
>
> The functions efi_get_variable_runtime() and
> efi_get_next_variable_name_runtime() were implemented in
> efi_variable_tee.c as part of the FF-A runtime variable handling work.
> However, default implementations for these same runtime helpers also
> exist in efi_var_common.c.
efi_variable.c is there to deal with variables stored in the
non-secure world and efi_variable_tee.c for the variables stored on
the non secure world.
You can't compile both. By moving efi_get_next_variable_name_runtime
out of common you will break efi_variable_tee.c for example.
The reason these are in common is that U-Boot exposes the memory
backend to the kernel for get/setvariable. Then the kernel at runtime
decides to ignore the u-boot runtime functions and rewires them to
internal op-tee functions. If you want a variable variant for FF-A
that belongs into efi_variable_tee.c
Thanks
/Ilias
> This results in duplicate symbol definitions.
> To resolve the conflict and centralize the runtime API, this patch moves
> the default implementations of the two runtime GetVariable() helpers
> from efi_var_common.c to efi_variable.c. This ensures that:
>
> - only a single definition of each runtime helper exists,
> - backend-specific implementations can override these cleanly,
> - the EFI runtime variable service table continues to reference the
> correct functions.
>
> No functional changes are introduced; this is a structural cleanup to
> avoid build-time conflicts and consolidate EFI runtime variable support
> in the appropriate file.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> ---
> lib/efi_loader/efi_var_common.c | 24 ------------------------
> lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
> 2 files changed, 24 insertions(+), 24 deletions(-)
>
> diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
> index d63c2d1b1cd..7cbf098c64a 100644
> --- a/lib/efi_loader/efi_var_common.c
> +++ b/lib/efi_loader/efi_var_common.c
> @@ -173,30 +173,6 @@ efi_status_t EFIAPI efi_query_variable_info(
> return EFI_EXIT(ret);
> }
>
> -efi_status_t __efi_runtime EFIAPI
> -efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> - u32 *attributes, efi_uintn_t *data_size, void *data)
> -{
> - efi_status_t ret;
> -
> - ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
> - data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
> -
> - /* Remove EFI_VARIABLE_READ_ONLY flag */
> - if (attributes)
> - *attributes &= EFI_VARIABLE_MASK;
> -
> - return ret;
> -}
> -
> -efi_status_t __efi_runtime EFIAPI
> -efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
> - u16 *variable_name, efi_guid_t *guid)
> -{
> - return efi_get_next_variable_name_mem(variable_name_size, variable_name,
> - guid, EFI_VARIABLE_RUNTIME_ACCESS);
> -}
> -
> /**
> * efi_set_secure_state - modify secure boot state variables
> * @secure_boot: value of SecureBoot
> diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
> index 9923936c1b5..f2e0e1ad4e2 100644
> --- a/lib/efi_loader/efi_variable.c
> +++ b/lib/efi_loader/efi_variable.c
> @@ -579,6 +579,30 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
> return EFI_SUCCESS;
> }
>
> +efi_status_t __efi_runtime EFIAPI
> +efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> + u32 *attributes, efi_uintn_t *data_size, void *data)
> +{
> + efi_status_t ret;
> +
> + ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
> + data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
> +
> + /* Remove EFI_VARIABLE_READ_ONLY flag */
> + if (attributes)
> + *attributes &= EFI_VARIABLE_MASK;
> +
> + return ret;
> +}
> +
> +efi_status_t __efi_runtime EFIAPI
> +efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
> + u16 *variable_name, efi_guid_t *guid)
> +{
> + return efi_get_next_variable_name_mem(variable_name_size, variable_name,
> + guid, EFI_VARIABLE_RUNTIME_ACCESS);
> +}
> +
> /**
> * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
> */
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 06/12] corstone1000: enable bootefi selftest
2026-04-24 17:31 ` [PATCH 06/12] corstone1000: enable bootefi selftest Harsimran Singh Tungal
2026-04-27 7:56 ` Ilias Apalodimas
@ 2026-04-28 18:01 ` Simon Glass
2026-05-06 12:20 ` Harsimran Singh Tungal
1 sibling, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:01 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> corstone1000: enable bootefi selftest
>
> Enable UEFI selftest command in Corstone-1000 defconfig
>
> Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> so the board can run the built-in UEFI self-test suite during
> development and validation.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> configs/corstone1000_defconfig | 3 +++
> 1 file changed, 3 insertions(+)
> diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> @@ -63,6 +65,7 @@ CONFIG_SYSRESET=y
> CONFIG_SYSRESET_PSCI=y
> CONFIG_TEE=y
> CONFIG_OPTEE=y
> +# CONFIG_CMD_POWEROFF is not set
> CONFIG_USB=y
Why is this disabled? It's not mentioned in the commit message and
looks unrelated to enabling the bootefi selftest. If it's a stray
byproduct of 'make savedefconfig' please drop it; if intentional it
should be a separate patch with its own justification.
> diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> @@ -32,6 +32,8 @@ CONFIG_SYS_PROMPT="corstone1000# "
> # CONFIG_CMD_CONSOLE is not set
> CONFIG_CMD_FWU_METADATA=y
> CONFIG_CMD_BOOTZ=y
> +# CONFIG_CMD_BOOTEFI_HELLO is not set
> +CONFIG_CMD_BOOTEFI_SELFTEST=y
The commit message says only that selftest is being enabled, but
you're also explicitly disabling CMD_BOOTEFI_HELLO (which would
otherwise default to y once SELFTEST is set). Please mention this, and
ideally state the real motivation - that this is needed so patch 7 of
the series can run the runtime variable selftest on this board, right?
> Enable UEFI selftest command in Corstone-1000 defconfig
>
> Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> so the board can run the built-in UEFI self-test suite during
> development and validation.
The first paragraph just restates the subject. Please drop it and keep
the second paragraph, which actually explains the change. Referencing
the runtime-variable selftest added later in the series would also
help, since that is the real reason for enabling it now.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage
2026-04-24 17:31 ` [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
@ 2026-04-28 18:04 ` Simon Glass
2026-05-06 15:14 ` Harsimran Singh Tungal
0 siblings, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:04 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi: selftest: add runtime variable tests with non-volatile storage
>
> Extend runtime variable tests for persistent storage
>
> Previously, EFI selftesting of runtime variables was only supported
> under CONFIG_EFI_RT_VOLATILE_STORE, which uses VarToFile to simulate
> non-volatile variable storage. This commit adds new test cases that
> exercise runtime variable operations for persistent storage.
>
> Features tested:
> - Creation of runtime-accessible variables (set)
> - Retrieval of runtime variables (get)
> - Deletion using SetVariable() with size = 0
> - Append operation using EFI_VARIABLE_APPEND_WRITE
>
> This improves EFI compliance validation for non-volatile runtime storage
> scenarios and ensures proper attribute enforcement and variable
> management.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> lib/efi_selftest/efi_selftest_variables_runtime.c | 106 +++++++++++++++++++++-
> 1 file changed, 104 insertions(+), 2 deletions(-)
> diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> @@ -39,6 +46,80 @@ static int execute(void)
> + /* Compare the value of EFI variable if it already exists in non volatile storage */
> + if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
> + len = sizeof(v) / 2;
> + ret = st_runtime->get_variable(u'efi_st_var0', &guid_vendor0,
> + &attr, &len, data);
> + if (ret == EFI_SUCCESS) {
The two-phase split worries me. As written, phase 1 creates a
non-volatile variable and immediately returns EFI_ST_SUCCESS, so a
single 'bootefi selftest' run reports a green test even though none of
the new assertions (append, delete, re-get) actually ran. It also
leaves 'efi_st_var0' behind in NV storage if the user never reboots
(or if phase 2 fails on an early assertion before the final delete).
Could you split this into two distinct EFI_UNIT_TEST entries - say
'variables at runtime (setup)' and 'variables at runtime (verify)'.
Then the user (and CI) explicitly select each phase, and the
persistent state across the two is part of the contract rather than a
hidden side-effect. At minimum, phase 1 needs to print a clear 'test
incomplete, please reboot and rerun' rather than EFI_ST_SUCCESS.
> diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> @@ -39,6 +46,80 @@ static int execute(void)
> + return EFI_ST_SUCCESS;
> + } else {
> + if (ret == EFI_NOT_FOUND) {
> + efi_st_printf("EFI Variable efi_st_var0 not found. "
> + "Executing First Phase\n");
> + }
> + }
> + }
Any return value other than EFI_SUCCESS or EFI_NOT_FOUND
(EFI_DEVICE_ERROR, EFI_UNSUPPORTED on a platform without an FF-A
backend, etc.) silently falls through to the volatile-store path below
and mis-diagnoses the failure. Please fail explicitly when ret is not
one of the two expected values.
> diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> @@ -279,7 +360,28 @@ static int execute(void)
> } else {
> - if (ret != EFI_UNSUPPORTED) {
> + if (ret != EFI_SUCCESS) {
This flips the contract: previously the !CONFIG_EFI_RT_VOLATILE_STORE
branch asserted that runtime SetVariable() returns EFI_UNSUPPORTED,
which is what every board without a runtime variable backend still
does. After this patch any such board fails 'variables at runtime'.
Please gate the new behaviour on something like CONFIG_EFI_MM_COMM_TEE
(or whatever indicates a working runtime backend) and keep the
EFI_UNSUPPORTED expectation otherwise.
> diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> @@ -39,6 +46,80 @@ static int execute(void)
> + /* Append an existing variable */
> + append_len = sizeof(v) - len;
> + ret = st_runtime->set_variable(u'efi_st_var0', &guid_vendor0,
> + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> + EFI_VARIABLE_RUNTIME_ACCESS |
> + EFI_VARIABLE_APPEND_WRITE |
> + EFI_VARIABLE_NON_VOLATILE,
> + append_len, (v + len));
Not sure if it is possible to align these lines properly? Not related
to this patch, but the EFI_VARIABLE_... prefix is really too long.
Drop redundant parens around v + len
> diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> @@ -39,6 +46,80 @@ static int execute(void)
> + if (memcmp(data, v, len)) {
> + efi_st_error("GetVariable failed\n");
> + return EFI_ST_FAILURE;
> + }
Quite a lot of separate sites in this hunk print 'GetVariable failed'
or 'SetVariable failed' with no further context - when one trips in CI
it's impossible to tell which assertion fired without rebuilding with
prints. Please make each message identify the step (e.g. 'phase 2:
append SetVariable failed', 'phase 2: post-delete GetVariable did not
return EFI_NOT_FOUND') so a log line is enough to localise the
failure.
> diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> @@ -3,6 +3,7 @@
> + * Copyright (c) 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
> + *
> * This unit test checks the runtime services for variables after
> * ExitBootServices():
> @@ -22,7 +23,13 @@ static const efi_guid_t efi_rt_var_guid = U_BOOT_EFI_RT_VAR_FILE_GUID;
> + * For EFI variables in non-volatile storage, these tests have to be executed in two phases
Please use 'non-volatile' (hyphenated) consistently in the doc comment
and in the inline comment a few lines down ('non volatile storage');
the rest of the file already spells it that way. Same nit for the
commit message body. The commit message also opens with 'Extend
runtime variable tests for persistent storage' that just paraphrases
the subject - please just drop it. 'Previously, EFI selftesting … was
only supported …' should be present tense per U-Boot conventions ('EFI
selftesting of runtime variables is currently only supported …').
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests
2026-04-24 17:31 ` [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
@ 2026-04-28 18:05 ` Simon Glass
2026-05-14 14:58 ` Harsimran Singh Tungal
0 siblings, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:05 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> test: dm: add sandbox FF-A runtime transport tests
>
> Exercise FF-A runtime helpers via sandbox DM tests
>
> Add driver-model unit tests that exercise the FF-A runtime helpers on
> sandbox. The new tests reuse the sandbox emulator to validate both the
> positive direct-request flow and failure handling, priming the emulator
> state so the runtime path can be executed.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +++++-
> test/dm/Makefile | 3 +-
> test/dm/ffa_runtime.c | 82 ++++++++++++++++++++++++++++++
> 3 files changed, 99 insertions(+), 2 deletions(-)
> diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> @@ -0,0 +1,82 @@
> +static int dm_test_ffa_runtime_nack(struct unit_test_state *uts)
> +{
> + struct ffa_send_direct_data msg = {0};
> + u16 sp_id;
> +
> + ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
> +
> + ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
> + .id = NS_PHYS_ENDPOINT_ID,
> + });
> + ffa_enable_runtime_context();
> +
> + /* Ensure runtime context is available before attempting runtime-only paths */
> + ut_assert(ffa_get_status_runtime_context());
> +
> + /* Invalid partition IDs must be rejected and mapped to -EINVAL */
> + ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0, &msg, true));
sp_id is fetched here but never used - the test sends to id 0
directly. Please drop the call to ffa_runtime_get_sp_id() in this
test, or use the discovered id for a positive comparison.
> diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> @@ -0,0 +1,82 @@
> +static int dm_test_ffa_runtime_ack(struct unit_test_state *uts)
> +{
> + struct ffa_send_direct_data msg = {0};
> + u16 sp_id;
> + u8 cnt;
> +
> + ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
> +
> + ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
> + .id = NS_PHYS_ENDPOINT_ID,
> + });
> + ffa_enable_runtime_context();
ffa_enable_runtime_context() flips a global static flag in
arm-ffa-runtime.c that is never reset. Once either test has run,
ffa_get_status_runtime_context() returns true for the rest of the
process, which leaks state into other tests and means a
missing-context path can never be reached. Please add a case that
calls ffa_sync_send_receive_runtime() before enabling the context and
verifies it returns -EPERM (that branch is currently untested) and
provide a way to reset the runtime priv between tests.
> diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> @@ -0,0 +1,82 @@
> + /* Validate FF-A error to errno translation helpers */
> + ut_asserteq(-EINVAL, ffa_to_std_errno(-INVALID_PARAMETERS));
> + ut_asserteq(-EOPNOTSUPP, ffa_to_std_errno(-NOT_SUPPORTED));
Just to clarify, ffa_to_std_errno() is a pure helper unrelated to the
messaging round-trip - please split this into its own dm_test, so a
regression in the table doesn't look like a transport failure, and add
coverage for at least the boundary cases (e.g. 0, MAX_NUMBER_FFA_ERR,
an out-of-range value) which all should map to -EINVAL.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros
2026-04-24 17:31 ` [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros Harsimran Singh Tungal
@ 2026-04-28 18:07 ` Simon Glass
2026-05-14 15:00 ` Harsimran Singh Tungal
0 siblings, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:07 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> sandbox: ffa: share synthetic partition metadata via macros
>
> Reuse sandbox FF-A partition constants in emulator tests
>
> Allow the sandbox FF-A emulator test to use execution-context and property
> constants defined in sandbox_arm_ffa.h
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 +++++++++++++++++++++---------
> 1 file changed, 26 insertions(+), 10 deletions(-)
> diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> @@ -19,41 +19,57 @@
> /* The partitions (SPs) table */
> static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
> {
> - .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
> + .info = {
> + .id = SANDBOX_SP1_ID,
> + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> + .properties = SANDBOX_SP1_PROPERTIES,
> + },
> .sp_uuid = {
> .a1 = SANDBOX_SERVICE1_UUID_A1,
> ...
> {
> - .info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
> + .info = {
> + .id = SANDBOX_SP2_ID,
> + .exec_ctxt = SANDBOX_SP2_EXEC_CTXT,
> + .properties = SANDBOX_SP2_PROPERTIES,
> + },
> .sp_uuid = {
> .a1 = SANDBOX_SERVICE2_UUID_A1,
> ...
> {
> - .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
> + .info = {
> + .id = SANDBOX_SP3_ID,
> + .exec_ctxt = SANDBOX_SP3_EXEC_CTXT,
> + .properties = SANDBOX_SP3_PROPERTIES,
> + },
> .sp_uuid = {
> .a1 = SANDBOX_SERVICE1_UUID_A1,
This is not a pure refactor. Index 1 and 2 swap, so SP2 moves from
SERVICE1 to SERVICE2, and SP3 moves from SERVICE2 to SERVICE1. The
existing test in test/dm/ffa.c queries by UUID and walks the matching
SPs, so the set of IDs returned for each service changes.
If the reorder is deliberate (e.g. so the table reads SP1..SP4 in
numeric order), please call it out in the commit message and confirm
no downstream test relies on the previous SP-to-UUID mapping.
Otherwise keep the .id fields where they were and only substitute in
the macros.
> diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> @@ -19,41 +19,57 @@
> + .info = {
> + .id = SANDBOX_SP1_ID,
> + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> + .properties = SANDBOX_SP1_PROPERTIES,
> + },
The macros being substituted in here are added in patch 8, and nothing
else in this patch uses them - they exist solely to be consumed by
this patch. Can you squash 9 into 8 so the macro definitions and their
first user land together.
> Author: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> sandbox: ffa: share synthetic partition metadata via macros
>
> Reuse sandbox FF-A partition constants in emulator tests
>
> Allow the sandbox FF-A emulator test to use execution-context and property
> constants defined in sandbox_arm_ffa.h
The body reads like two competing subject lines followed by a one-line
restatement, and none of it explains the motivation. Also, the file
changed is the emulator itself (ffa-emul-uclass.c), not a test, so 'in
emulator tests' / 'emulator test' is misleading. Please rewrite to say
what problem is being solved (e.g. the runtime tests added in 8 need
to reference the same exec_ctxt/properties values, so the magic
numbers are pulled out into shared macros) and drop the duplicate
sentence.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables
2026-04-24 17:31 ` [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
@ 2026-04-28 18:08 ` Simon Glass
2026-05-14 15:05 ` Harsimran Singh Tungal
2026-05-08 10:40 ` Abdellatif El Khlifi
1 sibling, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:08 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> doc: arm64: document FF-A runtime path for EFI variables
>
> Document how EFI runtime variables use FF-A MM communication
>
> Describe the FF-A runtime layer on arm64 and how EFI variable
> runtime services use the FF-A transport and shared MM buffer.
> Also clarify armffa command scope and link to the FF-A doc.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> doc/arch/arm64.ffa.rst | 92 ++++++++++++++++++++++++++++++++++++++++++++----
> doc/usage/cmd/armffa.rst | 11 ++++++
> 2 files changed, 96 insertions(+), 7 deletions(-)
> diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> @@ -15,10 +15,10 @@ application in S-EL0, or a Trusted OS in S-EL1.
> +U-Boot's FF-A bus support exposes an optional transport that EFI runtime
> +services can use to communicate with Secure Partitions. Through this
> +interface, EFI services (such as variable access) can request or exchange
> +data with the Secure World using FF-A.
The rest of this file uses lower-case 'Secure world' (see lines 12 and
16). Please keep the capitalisation consistent throughout the new
prose — also at the 'Secure World' in the runtime section below.
> diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> @@ -158,6 +164,77 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
> +- The communication buffer is located at CONFIG_FFA_SHARED_MM_BUF_ADDR and
> + sized by CONFIG_FFA_SHARED_MM_BUF_SIZE.
> +- CONFIG_FFA_SHARED_MM_BUF_OFFSET is sent in the FF-A direct message payload
> + to indicate where the data begins.
> +- The buffer is filled by memcpy(), the cache is flushed before notifying the
> + MM SP, and later the buffer is reused directly with only the shared-buffer
> + range invalidated (invalidate_dcache_range()) to avoid whole-cache
> + invalidation.
This level of cache-maintenance detail is an implementation note and
will go stale the moment the code is touched (and patch 12 is already
touching it in this very series). I'd drop the third bullet and let
the source comments have that, or move it under a clearly marked
'Implementation notes' sub-heading so readers know it is informative
rather than contractual.
> diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> @@ -158,6 +164,77 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
> +- get_comm_buf() switches to the static shared buffer
> +- mm_communicate_runtime() selects FF-A transport when the runtime context
> + is enabled
> +- ffa_mm_communicate_runtime() issues FFA_MSG_SEND_DIRECT_{REQ,RESP} through
> + ffa_sync_send_receive_runtime()
Naming specific static helpers in a public document ties the doc to
current internal names. If one is renamed or refactored later, the doc
silently lies. Please describe the flow at one level higher (e.g. 'the
runtime path uses a static shared buffer and dispatches direct FF-A
messages') and leave the function names to the source.
>
> doc: arm64: document FF-A runtime path for EFI variables
>
> Document how EFI runtime variables use FF-A MM communication
>
> Describe the FF-A runtime layer on arm64 and how EFI variable
> runtime services use the FF-A transport and shared MM buffer.
> Also clarify armffa command scope and link to the FF-A doc.
The single-line paragraph just restates the subject and the next
paragraph. U-Boot convention is to open with the motivation/problem -
please replace this with a sentence explaining why the doc was
previously incomplete (the previous text said runtime support was a
future development) and what readers gain from the new sections.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 01/12] efi_loader: add runtime memset helper
2026-04-24 17:31 ` [PATCH 01/12] efi_loader: add runtime memset helper Harsimran Singh Tungal
2026-04-27 7:54 ` Ilias Apalodimas
@ 2026-04-28 18:08 ` Simon Glass
2026-05-04 20:03 ` Harsimran Singh Tungal
1 sibling, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:08 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: add runtime memset helper
>
> Add efi_memset_runtime() for EFI runtime paths
>
> This keeps buffer initialization in runtime-resident code after
> ExitBootServices() and avoids relying on non-runtime helpers.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> include/efi_loader.h | 3 +++
> lib/efi_loader/efi_runtime.c | 21 +++++++++++++++++++++
> 2 files changed, 24 insertions(+)
> diff --git a/include/efi_loader.h b/include/efi_loader.h
> @@ -1151,6 +1151,9 @@ void efi_memcpy_runtime(void *dest, const void *src, size_t n);
> /* runtime implementation of memcmp() */
> int efi_memcmp_runtime(const void *s1, const void *s2, size_t n);
>
> +/* runtime implementation of memset */
> +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n);
> +
Two inconsistencies with the neighbouring declarations: the comment
should say memset() to match memcpy() / memcmp() above, and the
section attribute does not belong in the prototype, as
efi_memcpy_runtime() and efi_memcmp_runtime() carry __efi_runtime only
on the definition. Please drop it from the header.
> diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
> @@ -233,6 +233,27 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
> +/**
> + * efi_memset_runtime() - fill a memory region with a byte value
> + *
> + * At runtime memset() is not available.
> + *
> + * @dest: pointer to the block of memory to fill.
> + * @c: value to be set. The value is passed as an int, but the
> + * function fills the block of memory using the u8 conversion of this value.
> + * @n: number of bytes to be set to the value.
> + * Return: dest is returned
> + */
> +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
Please match the kernel-doc style of the two helpers above: tabs after
the ':' in the parameter list, no trailing periods, one-line @c
description. The @c line is also over 80 columns. Flip the attribute
to 'void * __efi_runtime efi_memset_runtime(...)' to match
efi_memcpy_runtime() / efi_memcmp_runtime() in this same file.
> diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
> @@ -233,6 +233,27 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
> +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
> +{
> + u8 *d = dest;
> +
> + for (; n; --n)
> + *d++ = c;
> +
> + return dest;
> +}
Just to check, was there a reason not to mask 'c' to a byte (i.e.
'*d++ = (u8)c') as the doc comment promises? An explicit cast matches
the comment and silences future -Wconversion noise.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 02/12] arm-ffa: add FF-A bus runtime support
2026-04-24 17:31 ` [PATCH 02/12] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
@ 2026-04-28 18:10 ` Simon Glass
2026-05-04 20:25 ` Harsimran Singh Tungal
2026-05-08 10:18 ` Abdellatif El Khlifi
0 siblings, 2 replies; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:10 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> arm-ffa: add FF-A bus runtime support
>
> Enable FF-A runtime transport for EFI services
>
> This patch introduces the FF-A runtime infrastructure that enables
> U-Boot to use the Arm Firmware Framework for Arm A-profile (FF-A)
> transport layer after ExitBootServices().
> The runtime transport provides persistent, runtime-safe
> implementations of key FF-A functions used by EFI runtime services.
>
> Summary of key changes:
> -----------------------
> - Add drivers/firmware/arm-ffa/arm-ffa-runtime.c implementing FF-A
> runtime operations.
> - Introduce include/arm_ffa_runtime.h exporting FF-A runtime
> functions and data structures.
> - Move FF-A error mapping into runtime context.
> - Introduce invoke_ffa_fn_runtime() as runtime safe SMC wrapper.
> - Add runtime SMC wrapper for sandbox emulation.
> - Add ARM_FFA_RT_MODE Kconfig to enable runtime support.
> [...]
>
> drivers/firmware/arm-ffa/Kconfig | 11 ++
> drivers/firmware/arm-ffa/Makefile | 4 +-
> drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 +++++++++++++++++++++++++++++
> drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 ++---------
> drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
> drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 ++
> include/arm_ffa.h | 16 +-
> include/arm_ffa_priv.h | 24 ++-
> include/arm_ffa_runtime.h | 183 ++++++++++++++++++
> test/dm/ffa.c | 6 +-
> 10 files changed, 551 insertions(+), 119 deletions(-)
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,287 @@
> + if (priv)
> + ffa_copy_runtime_priv(&priv->rt);
> + else
> + log_err("FF-A: Entering RT mode without FF-A runtime data information\n");
> +
> + ffa_enable_runtime_context();
This enables the runtime context unconditionally, even after logging
the priv data is missing. The runtime then comes up with id == 0 and
fwk_version == 0 and any later FF-A call silently uses bogus values.
Please return after the log_err() so ffa_get_status_runtime_context()
keeps returning false on the failure path.
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,287 @@
> +#include <arm_ffa_runtime.h>
> +#include <arm_ffa_priv.h>
> +#include <log.h>
> +#include <asm/global_data.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
gd doesn't seem to be referenced in this file?
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,287 @@
> + * after the FF-A bus device has successfully probed and U-Boot’s FF-A
This (and the same line in arm_ffa_runtime.h) should use a normal '
instead of the UTF-8 right single quotation mark.
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,287 @@
> +#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
> +static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
> + void *context)
CONFIG_IS_ENABLED() is only meaningful for symbols with an SPL twin.
ARM_FFA_RT_MODE has none, and the uclass side already uses
IS_ENABLED(CONFIG_ARM_FFA_RT_MODE) - please use IS_ENABLED() here and
in arm_ffa_runtime.h.
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,287 @@
> + if (is_smc64) {
> + req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
> + } else {
> + req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
> + }
Single-statement bodies should not be braced. Please run patman or
checkpatch.pl on your patches. Also, the two efi_memset_runtime()
calls below clear fresh stack variables. Please initialise them at
declaration ('ffa_value_t ffa_args_rt = {}') and drop the explicit
memset()s; the compiler's zero-init is just as runtime-safe and is
what the boot path already does.
Also could you run checkpatch / patman over your patches for v2?
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
> @@ -1047,6 +961,11 @@ static int ffa_do_probe(struct udevice *dev)
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
> + if (ret)
> + return ret;
> + }
If event creation fails here, the RX/TX buffers mapped above and the
partition cache are leaked, i,e. the existing failure path for
ffa_cache_partitions_info() at least calls
ffa_unmap_rxtx_buffers_hdlr(). Please follow the same pattern, or move
event registration before resource allocation.
> diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
> @@ -41,3 +44,11 @@ config ARM_FFA_TRANSPORT
> +config ARM_FFA_RT_MODE
> + bool "Enable FF-A runtime support"
> + depends on ARM_FFA_TRANSPORT && EFI_LOADER
> + default y
Just to check, does every existing FF-A user want this on? 'default y'
silently enables a new transport path (and the ExitBootServices
callback) for everyone with ARM_FFA_TRANSPORT && EFI_LOADER. I'd
suggest defaulting, or at minimum 'default y if CORSTONE1000' or
similar, until other boards have opted in.
> diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
> @@ -212,9 +227,8 @@ struct ffa_partitions {
> - u32 fwk_version;
> + struct ffa_priv_runtime rt;
> struct udevice *emul;
> - u16 id;
Just to clarify the model: 'struct ffa_priv' now embeds 'struct
ffa_priv_runtime rt' at boot, and at ExitBootServices we copy the
whole sub-struct (including 'use_ffa_runtime', always false here) into
the resident 'ffa_priv_rt', then immediately overwrite use_ffa_runtime
via ffa_enable_runtime_context(). Layering would be clearer if
'use_ffa_runtime' lived only on the resident copy and ffa_priv_runtime
carried just the data shipped across the boundary (fwk_version, id).
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-04-24 17:31 ` [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
2026-04-27 16:21 ` Ilias Apalodimas
@ 2026-04-28 18:12 ` Simon Glass
2026-05-05 8:55 ` Harsimran Singh Tungal
1 sibling, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:12 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: add FF-A runtime support in EFI variable TEE driver
>
> Enable MM variable services over FF-A after ExitBootServices
>
> This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
> communication with the secure world during EFI runtime. It enables EFI
> runtime variable access and MM communication using FF-A transport when
> ExitBootServices() has already been called.
>
> Key changes:
> ------------
> - Introduce runtime-safe implementations for MM communication,
> notification, and variable access using FF-A driver.
> - Introduce communication-buffer helper (get_comm_buf()) that switches
> between dynamic allocation (boot phase) and the fixed FF-A shared
> buffer (runtime phase).
> - Mark persistent data and code with __efi_runtime and
> __efi_runtime_data attributes.
> - Use direct physical address mapping for shared buffers since
> U-Boot operates with 1:1 physical-to-virtual mapping.
> [...]
>
> lib/efi_loader/efi_variable_tee.c | 331 ++++++++++++++++++++++++++++++++++++--
> 1 file changed, 319 insertions(+), 12 deletions(-)
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
> +static int __efi_runtime ffa_notify_mm_sp_runtime(void)
> +{
> + struct ffa_send_direct_data msg = {0};
> + int ret;
> + int sp_event_ret;
> +
> + msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
> +
> + ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
> + if (ret)
> + return ret;
> +
> + ret = ffa_map_sp_event_runtime(sp_event_ret);
> + return ret;
> +}
It looks like ''sp_event_ret' is uninitialised. The boot-time twin
sets sp_event_ret = msg.data0 after the FF-A call before mapping it;
that line is missing here, so the runtime path branches on whatever
was on the stack and returns -EACCES (or worse, success) regardless of
the SP reply. Please add the assignment, and ideally a selftest
exercising an SP error return so this would have been caught.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> + ulong comm_buf_size)
> +{
...
> + if (!comm_buf)
> + return EFI_INVALID_PARAMETER;
> +
> + /* Discover MM partition ID at boot time */
> + if (!mm_sp_id)
> + return EFI_UNSUPPORTED;
The comment is copied verbatim from ffa_mm_communicate() but at
runtime we cannot discover anything - we can only check that boot-time
discovery happened. Please rewrite as e.g. 'MM partition ID must have
been discovered at boot time'.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> + ulong comm_buf_size)
> +{
...
> + switch (ffa_ret) {
> + case 0: {
...
> + case -EINVAL:
> + efi_ret = EFI_DEVICE_ERROR;
> + break;
Almost the entire body is a copy of ffa_mm_communicate(), including
the long cache-maintenance comment block which patch 12 then
duplicates again into the boot helper. Please factor the shared logic
into one helper that takes a 'runtime' bool (or function pointers for
the FF-A and notify hooks) so we don't carry three near-identical
copies. The current arrangement makes future fixes (like the missing
sp_event_ret assignment above) easy to apply to only one twin.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -386,6 +575,27 @@ static enum mm_comms_select get_mm_comms(void)
> +static enum mm_comms_select __efi_runtime get_mm_comms_runtime(void)
> +{
> + bool ret;
> +
> + ret = efi_is_runtime_enabled();
> + if (!ret)
> + return MM_COMMS_UNDEFINED;
> +
> + return MM_COMMS_FFA;
> +}
But get_mm_comms_runtime() is only reached via the runtime services
table, which is only wired up after efi_variables_boot_exit_notify()
sets efi_runtime_enabled=true, so it always returns MM_COMMS_FFA,
right? Either drop the wrapper and call ffa_mm_communicate_runtime()
directly from mm_communicate_runtime(), or keep an explicit runtime
sanity check, but please don't dress it up as transport selection.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> +static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
> +{
> + u8 *comm_buf;
> +
> + /* After ExitBootServices(), dynamic allocation is no longer permitted.
> + * Use the predefined FF-A shared buffer at runtime; otherwise allocate
> + * a fresh buffer during the boot phase.
> + */
> + if (efi_is_runtime_enabled()) {
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + comm_buf = ffa_shared_buf;
> + if (!comm_buf)
> + return NULL;
> + efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
> + } else {
> + return NULL;
> + }
> + } else {
At runtime there is no validation that 'payload_size + headers' fits
inside CONFIG_FFA_SHARED_MM_BUF_SIZE - the max_buffer_size check in
setup_mm_hdr() compares against the SP-reported limit, which is not
necessarily the same as the static shared buffer size, so an oversized
payload can silently overflow the FF-A buffer when setup_mm_hdr()
writes the header and the caller fills the data. Please add an
explicit size check here, or assert that max_buffer_size <=
CONFIG_FFA_SHARED_MM_BUF_SIZE at init time.
Also: the multi-line comment uses kernel-doc style ('/*' on its own
then '*' lines) elsewhere in this file, but here the first text line
follows '/*' immediately.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -444,10 +731,9 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> /**
> * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
> - * header data.
> + * header data. It is runtime safe.
The function no longer 'allocates' at runtime. It hands back a slot in
the static shared buffer - so the summary is misleading. Please
rewrite the description and drop the trailing 'It is runtime safe'
(already implied by the new __efi_runtime tag).
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -34,20 +35,47 @@
> +static const efi_guid_t __efi_runtime_rodata mm_var_guid_runtime =
> + EFI_MM_VARIABLE_GUID;
Why a separate '_runtime' copy of this GUID? The original mm_var_guid
was a function-local in setup_mm_hdr(), so you can just promote it to
file scope with __efi_runtime_rodata and use it for both phases.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + /*
> + * The FF-A shared buffer is accessed by EFI runtime services, so it must
> + * be marked as runtime memory in the EFI memory map.
> + */
> + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> + ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
> + CONFIG_FFA_SHARED_MM_BUF_SIZE,
> + EFI_RUNTIME_SERVICES_DATA);
efi_add_memory_map() takes a size in bytes but the underlying
implementation expects a page-count argument in some call sites. Can
you please double-check that CONFIG_FFA_SHARED_MM_BUF_SIZE is
interpreted as bytes here and that the buffer base is page-aligned,
otherwise the OS will see a misdescribed runtime region. Worth a
comment stating the alignment assumption.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -34,20 +35,47 @@
> +static bool __efi_runtime_data efi_runtime_enabled;
We already have a global indicator that boot services have exited:
systab.boottime being set to NULL in efi_exit_boot_services()
Adding a second flag here (and a wrapper efi_is_runtime_enabled() over
it) means we need to keep them in sync. I'd prefer either hooking off
systab.boottime (already __efi_runtime_data) or exposing a single
global helper from efi_runtime.c that everyone uses.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -4,7 +4,7 @@
> * Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
> * Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
> - * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
> + * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
How about 2022-2026 ?
The commit message also opens with 'This patch extends ...'; please
use the imperative ('Extend lib/efi_loader/efi_variable_tee.c to ...')
and drop 'This patch'. Same for 'Key changes:' / 'The change reuses
...' - describe what the code does in present tense.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest
2026-04-24 17:31 ` [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
@ 2026-04-28 18:14 ` Simon Glass
2026-05-14 15:07 ` Harsimran Singh Tungal
0 siblings, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:14 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> doc: bootefi: note two-phase runtime variables selftest
>
> Explain how the runtime variable selftest runs in two phases
>
> Document that the "variables at runtime" selftest runs in two
> phases when CONFIG_EFI_RT_VOLATILE_STORE is not enabled, and
> show how to select it with efi_selftest.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> doc/usage/cmd/bootefi.rst | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
> diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
> @@ -167,6 +177,8 @@ To use the *bootefi* command you must specify CONFIG_CMD_BOOTEFI=y.
> The *bootefi bootmgr* sub-command requries CMD_BOOTEFI_BOOTMGR=y.
> The *bootefi hello* sub-command requries CMD_BOOTEFI_HELLO=y.
> The *bootefi selftest* sub-command depends on CMD_BOOTEFI_SELFTEST=y.
> +The *variables at runtime* selftest runs in two phases when
> +CONFIG\_EFI\_RT\_VOLATILE\_STORE is not enabled.
Please drop this addition. It duplicates what you wrote a few lines
above and the Configuration section is for build-time CONFIG_ options,
not runtime test behaviour. Also the backslash-escaped underscores are
not needed in rST and produce inconsistent rendering compared to the
plain CONFIG_EFI_RT_VOLATILE_STORE used in the paragraph above.
> diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
> @@ -160,6 +160,16 @@ environment variable to match one of the listed identifiers
> Some of the tests execute the ExitBootServices() UEFI boot service and will not
> return to the command line but require a board reset.
>
> +The test *variables at runtime* runs in two phases when
> +CONFIG_EFI_RT_VOLATILE_STORE is not enabled. Run it once to create a
> +runtime-accessible variable in non-volatile storage, reboot, then run it
> +again to validate, append, and delete that variable.
It would help to also say what happens when
CONFIG_EFI_RT_VOLATILE_STORE is enabled (single phase, no reboot
needed) so readers know which path applies to their build. A one-line
note is enough.
> Explain how the runtime variable selftest runs in two phases
>
> Document that the "variables at runtime" selftest runs in two
> phases when CONFIG_EFI_RT_VOLATILE_STORE is not enabled, and
> show how to select it with efi_selftest.
The first paragraph just restates the subject - please drop it and
lead with the motivation, then describe what the patch adds. Lines are
also wrapping well short of 72 columns.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path
2026-04-24 17:31 ` [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path Harsimran Singh Tungal
@ 2026-04-28 18:14 ` Simon Glass
2026-05-08 10:34 ` Abdellatif El Khlifi
2026-05-14 15:11 ` Harsimran Singh Tungal
0 siblings, 2 replies; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:14 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: align FF-A cache maintenance with runtime path
>
> Match boot-time FF-A cache handling to runtime behavior
>
> The boot-time FF-A MM communication path used invalidate_dcache_all()
> after copying the message into the shared buffer. This differs from the
> runtime path, which performs range-based maintenance to avoid global cache
> operations.
>
> Update ffa_mm_communicate() to use the same pattern as the runtime helper:
> clean the shared buffer range before the SMC and invalidate the same range
> after the response. This keeps boot-time and runtime behavior consistent
> and avoids whole-cache invalidation.
>
> Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> lib/efi_loader/efi_variable_tee.c | 33 ++++++++++++++++++++++++++-------
> 1 file changed, 26 insertions(+), 7 deletions(-)
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> memcpy(virt_shared_buf, comm_buf, tx_data_size);
>
> /*
> - * The secure world might have cache disabled for
> - * the device region used for shared buffer (which is the case for Optee).
> - * In this case, the secure world reads the data from DRAM.
> - * Let's flush the cache so the DRAM is updated with the latest data.
> + * Shared buffer cache maintenance for FF-A / OP-TEE communication:
> + *
> + * NS -> S (request path):
> + *
> + * The non-secure side populates the shared buffer. If the buffer is cached
> + * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
> + * visible in DDR. Since the secure world typically reads the shared buffer
> + * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
> + * must clean the corresponding cache lines to the Point of Coherency (PoC)
> + * before entering secure world.
> + *
> + * S -> NS (response path):
> + *
> + * The secure world may update the same shared buffer in DDR. After returning
> + * to non-secure, any cached copies of that region in NS may be stale. We
> + * therefore invalidate the shared buffer range after the FF-A call to drop
> + * those lines and force subsequent reads to fetch the latest data from DDR.
> */
This 20-line comment is now duplicated verbatim with the one in
ffa_mm_communicate_runtime() introduced earlier in the series. Please
factor the clean-before / invalidate-after sequence into a small
helper (e.g. ffa_mm_buf_pre_call() / ffa_mm_buf_post_call()) so the
commentary lives in one place and the two paths cannot drift. The
runtime helper would add the extra 'no whole-cache invalidation after
ExitBootServices()' note at the call site.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> -#ifdef CONFIG_ARM64
> - invalidate_dcache_all();
> -#endif
> + if (IS_ENABLED(CONFIG_ARM64))
> + flush_dcache_range((unsigned long)virt_shared_buf,
> + (unsigned long)virt_shared_buf +
> + CONFIG_FFA_SHARED_MM_BUF_SIZE);
Just to check - flush_dcache_range() and invalidate_dcache_range() on
arm64 require start and end to be cache-line aligned, otherwise the
arch code warns and falls back to clean+invalidate of the partial
lines. CONFIG_FFA_SHARED_MM_BUF_ADDR and _SIZE need to be at least
CONFIG_SYS_CACHELINE_SIZE aligned - is that documented or enforced
anywhere? You could use BUILD_BUG_ON() near the call, perhaps?
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
The commit message body opens with 'Match boot-time FF-A cache
handling to runtime behavior', which restates the subject. Please drop
that line and start directly with the problem paragraph per the U-Boot
convention of leading with motivation.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
2026-04-24 17:31 ` [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
@ 2026-04-28 18:16 ` Simon Glass
2026-05-05 14:30 ` Harsimran Singh Tungal
0 siblings, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:16 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
>
> Route EFI runtime variable APIs through FF-A MM communication
>
> This patch implements full EFI Runtime Variable Services (GetVariable,
> SetVariable, GetNextVariableName, and QueryVariableInfo) using the
> FF-A/MM communication backend. Once ExitBootServices() has been invoked,
> all variable operations now use the runtime-safe FF-A transport instead
> of the boot-time communication paths.
>
> Key changes:
> ============
>
> - Add runtime-safe variable property handling via FF-A MM SP.
> - Add runtime versions of variable access and property operations.
> - Replace all standard memory operations with EFI-runtime-safe variants.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> lib/charset.c | 2 +-
> lib/efi_loader/efi_variable_tee.c | 322 +++++++++++++++++++++++++++++++++++++-
> 2 files changed, 318 insertions(+), 6 deletions(-)
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -991,6 +1066,92 @@ out:
> + /*
> + * UEFI > 2.7 needs the attributes set even if the buffer is
> + * smaller
> + */
> + if (attributes) {
> + tmp = get_property_int_runtime(variable_name, name_size, vendor,
> + &var_property);
> + if (tmp != EFI_SUCCESS) {
> + ret = tmp;
> + return ret;
> + }
> + *attributes = var_acc->attr;
> + if (var_property.property &
> + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
> + *attributes |= EFI_VARIABLE_READ_ONLY;
> + }
get_property_int_runtime() ends up calling setup_mm_hdr() ->
get_comm_buf(), and at runtime get_comm_buf() does
efi_memset_runtime(ffa_shared_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE)
on the same shared buffer that var_acc points into.
By the time you read var_acc->attr it has been zeroed, so
'*attributes' will only ever come back as 0 (optionally OR'd with
EFI_VARIABLE_READ_ONLY). The boot-time path gets away with this
because get_property_int() calloc()s a fresh buffer; the runtime path
cannot. Please cache var_acc->attr in a local before the call, or move
the get_property_int_runtime() call ahead of the SP exchange.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -1228,7 +1477,70 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> + ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
> + attributes &= EFI_VARIABLE_MASK;
> +
> + ret = get_property_int_runtime(variable_name, name_size, guid,
> + &var_property);
> + if (ret != EFI_SUCCESS)
> + return ret;
> +
> + /*
> + * Allocate the buffer early, before switching to RW (if needed)
> + * so we won't need to account for any failures in reading/setting
> + * the properties, if the allocation fails
> + */
> + comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
> + SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
> + if (!comm_buf)
> + return ret;
> +
> + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
> + return EFI_WRITE_PROTECTED;
The comment is copied from efi_set_variable_int() and no longer
matches the code - there is no RW switch in the runtime path (no
ro_check argument), and the allocation happens after the property
read, the opposite of what the comment claims. Either drop the comment
or, better, do the RO check before calling setup_mm_hdr() so the
early-return is quicker.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -859,6 +859,38 @@ out:
> +static efi_status_t __efi_runtime set_property_int_runtime(const u16 *variable_name,
> + efi_uintn_t name_size,
> + const efi_guid_t *vendor,
> + struct var_check_property *var_property)
As mentioned elsewhere, the four new functions
(set_property_int_runtime, get_property_int_runtime,
efi_get_variable_runtime, efi_get_next_variable_name_runtime) are
near-line-for-line copies of their boot-time counterparts with
memcpy/guidcpy/memset swapped for the efi_*_runtime helpers and a
different mm_communicate(). Since setup_mm_hdr() was made runtime-safe
in patch 3, can the boot-time helpers be reused directly (with
mm_communicate() picking the right transport based on
efi_is_runtime_enabled())? It would also avoid the special-case free()
path.
> diff --git a/lib/charset.c b/lib/charset.c
> @@ -407,7 +407,7 @@ size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
> -size_t u16_strsize(const void *in)
> +size_t __efi_runtime u16_strsize(const void *in)
This change should really be in its own patch with a one-line note
that it's needed by the new runtime callers. It is unrelated to the
SetVariable/GetVariable wiring and is easy to lose in this 320-line
diff.
> Key changes:
> ============
>
> - Add runtime-safe variable property handling via FF-A MM SP.
> - Add runtime versions of variable access and property operations.
> - Replace all standard memory operations with EFI-runtime-safe variants.
The'============' underline is more for rST documentation than commit
messages - please drop it. The third bullet is also misleading: only
the new runtime functions use the runtime-safe variants; the existing
boot-time helpers are unchanged. It is generally better to use prose
than bullet points in a commit message.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [00/12] arm64: FF-A runtime transport for EFI variables
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (12 preceding siblings ...)
2026-04-24 22:18 ` [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Heinrich Schuchardt
@ 2026-04-28 18:16 ` Simon Glass
2026-05-14 15:37 ` Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
14 siblings, 1 reply; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:16 UTC (permalink / raw)
To: harsimransingh.tungal; +Cc: u-boot
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: align FF-A cache maintenance with runtime path
Patch 12 changes the boot-time path to match the runtime path, but
sits at the end of the series. Between patch 3 (which introduces the
runtime cache pattern) and patch 12 the two paths are deliberately
inconsistent. I'd prefer this alignment before patch 3, so patch 3
simply adopts the established pattern. It would also make the
rationale in patch 12's commit message read more naturally. What do
you think?
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c
2026-04-24 17:31 ` [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c Harsimran Singh Tungal
2026-04-28 12:03 ` Ilias Apalodimas
@ 2026-04-28 18:25 ` Simon Glass
1 sibling, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-04-28 18:25 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: move runtime GetVariable() helpers to efi_variable.c
>
> Consolidate runtime GetVariable helpers to avoid duplicates
>
> The functions efi_get_variable_runtime() and
> efi_get_next_variable_name_runtime() were implemented in
> efi_variable_tee.c as part of the FF-A runtime variable handling work.
> However, default implementations for these same runtime helpers also
> exist in efi_var_common.c. This results in duplicate symbol definitions.
> To resolve the conflict and centralize the runtime API, this patch moves
> the default implementations of the two runtime GetVariable() helpers
> from efi_var_common.c to efi_variable.c. This ensures that:
>
> - only a single definition of each runtime helper exists,
> - backend-specific implementations can override these cleanly,
> - the EFI runtime variable service table continues to reference the
> correct functions.
>
> No functional changes are introduced; this is a structural cleanup to
> avoid build-time conflicts and consolidate EFI runtime variable support
> [...]
>
> lib/efi_loader/efi_var_common.c | 24 ------------------------
> lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
> 2 files changed, 24 insertions(+), 24 deletions(-)
> diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
> @@ -579,6 +579,30 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
> +efi_status_t __efi_runtime EFIAPI
> +efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> + u32 *attributes, efi_uintn_t *data_size, void *data)
Just to clarify the commit message: this is a relocation, not pure
deduplication. efi_var_common.c is always built, while efi_variable.c
is only built when CONFIG_EFI_MM_COMM_TEE is unset, so the move is
what actually resolves the conflict with the new efi_variable_tee.c
definitions. Please reword to make that clear, and drop 'default
implementations for these same runtime helpers also exist in
efi_var_common.c. This results in duplicate symbol definitions' -
there is no duplicate today; the duplicate is what patches 3 and 4
introduce earlier in this series, right?
> efi_loader: move runtime GetVariable() helpers to efi_variable.c
>
> Consolidate runtime GetVariable helpers to avoid duplicates
The subject and the one-line summary mention only GetVariable(), but
efi_get_next_variable_name_runtime() is also moved. Please broaden the
wording e.g. 'move runtime variable read helpers'.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 01/12] efi_loader: add runtime memset helper
2026-04-28 18:08 ` Simon Glass
@ 2026-05-04 20:03 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-04 20:03 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:08 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > efi_loader: add runtime memset helper
> >
> > Add efi_memset_runtime() for EFI runtime paths
> >
> > This keeps buffer initialization in runtime-resident code after
> > ExitBootServices() and avoids relying on non-runtime helpers.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > include/efi_loader.h | 3 +++
> > lib/efi_loader/efi_runtime.c | 21 +++++++++++++++++++++
> > 2 files changed, 24 insertions(+)
>
> > diff --git a/include/efi_loader.h b/include/efi_loader.h
> > @@ -1151,6 +1151,9 @@ void efi_memcpy_runtime(void *dest, const void *src, size_t n);
> > /* runtime implementation of memcmp() */
> > int efi_memcmp_runtime(const void *s1, const void *s2, size_t n);
> >
> > +/* runtime implementation of memset */
> > +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n);
> > +
>
> Two inconsistencies with the neighbouring declarations: the comment
> should say memset() to match memcpy() / memcmp() above, and the
> section attribute does not belong in the prototype, as
> efi_memcpy_runtime() and efi_memcmp_runtime() carry __efi_runtime only
> on the definition. Please drop it from the header.
>
Thanks for your feedback.
I will fix this in patchset v2.
Regards
Harsimran Singh Tungal
> > diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
> > @@ -233,6 +233,27 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
> > +/**
> > + * efi_memset_runtime() - fill a memory region with a byte value
> > + *
> > + * At runtime memset() is not available.
> > + *
> > + * @dest: pointer to the block of memory to fill.
> > + * @c: value to be set. The value is passed as an int, but the
> > + * function fills the block of memory using the u8 conversion of this value.
> > + * @n: number of bytes to be set to the value.
> > + * Return: dest is returned
> > + */
> > +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
>
> Please match the kernel-doc style of the two helpers above: tabs after
> the ':' in the parameter list, no trailing periods, one-line @c
> description. The @c line is also over 80 columns. Flip the attribute
> to 'void * __efi_runtime efi_memset_runtime(...)' to match
> efi_memcpy_runtime() / efi_memcmp_runtime() in this same file.
>
Sure, I will fix this in patchset v2.
Regards
Harsimran Singh Tungal
> > diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
> > @@ -233,6 +233,27 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
> > +__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
> > +{
> > + u8 *d = dest;
> > +
> > + for (; n; --n)
> > + *d++ = c;
> > +
> > + return dest;
> > +}
>
> Just to check, was there a reason not to mask 'c' to a byte (i.e.
> '*d++ = (u8)c') as the doc comment promises? An explicit cast matches
> the comment and silences future -Wconversion noise.
>
Thanks for noticing this.
No, there was no specific reason to not to mask 'c' to a byte.
I will do the suggested change in patchset v2.
Regards
Harsimran Singh Tungal
> Regards,
> Simon
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 02/12] arm-ffa: add FF-A bus runtime support
2026-04-28 18:10 ` Simon Glass
@ 2026-05-04 20:25 ` Harsimran Singh Tungal
2026-05-08 10:18 ` Abdellatif El Khlifi
1 sibling, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-04 20:25 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:10 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > arm-ffa: add FF-A bus runtime support
> >
> > Enable FF-A runtime transport for EFI services
> >
> > This patch introduces the FF-A runtime infrastructure that enables
> > U-Boot to use the Arm Firmware Framework for Arm A-profile (FF-A)
> > transport layer after ExitBootServices().
> > The runtime transport provides persistent, runtime-safe
> > implementations of key FF-A functions used by EFI runtime services.
> >
> > Summary of key changes:
> > -----------------------
> > - Add drivers/firmware/arm-ffa/arm-ffa-runtime.c implementing FF-A
> > runtime operations.
> > - Introduce include/arm_ffa_runtime.h exporting FF-A runtime
> > functions and data structures.
> > - Move FF-A error mapping into runtime context.
> > - Introduce invoke_ffa_fn_runtime() as runtime safe SMC wrapper.
> > - Add runtime SMC wrapper for sandbox emulation.
> > - Add ARM_FFA_RT_MODE Kconfig to enable runtime support.
> > [...]
> >
> > drivers/firmware/arm-ffa/Kconfig | 11 ++
> > drivers/firmware/arm-ffa/Makefile | 4 +-
> > drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 +++++++++++++++++++++++++++++
> > drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 ++---------
> > drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
> > drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 ++
> > include/arm_ffa.h | 16 +-
> > include/arm_ffa_priv.h | 24 ++-
> > include/arm_ffa_runtime.h | 183 ++++++++++++++++++
> > test/dm/ffa.c | 6 +-
> > 10 files changed, 551 insertions(+), 119 deletions(-)
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > + if (priv)
> > + ffa_copy_runtime_priv(&priv->rt);
> > + else
> > + log_err("FF-A: Entering RT mode without FF-A runtime data information\n");
> > +
> > + ffa_enable_runtime_context();
>
> This enables the runtime context unconditionally, even after logging
> the priv data is missing. The runtime then comes up with id == 0 and
> fwk_version == 0 and any later FF-A call silently uses bogus values.
> Please return after the log_err() so ffa_get_status_runtime_context()
> keeps returning false on the failure path.
>
Thanks for pointing this out.
I will fix this in patchset v2.
Regards
Harsimran Singh Tungal
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > +#include <arm_ffa_runtime.h>
> > +#include <arm_ffa_priv.h>
> > +#include <log.h>
> > +#include <asm/global_data.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
>
> gd doesn't seem to be referenced in this file?
>
No. gd is not being referenced.
gd declaration will be removed in patchset v2.
Regards
Harsimran Singh Tungal
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > + * after the FF-A bus device has successfully probed and U-Boot’s FF-A
>
> This (and the same line in arm_ffa_runtime.h) should use a normal '
> instead of the UTF-8 right single quotation mark.
>
Sure.
I will fix this in v2.
Regards
Harsimran Singh Tungal
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > +#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
> > +static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
> > + void *context)
>
> CONFIG_IS_ENABLED() is only meaningful for symbols with an SPL twin.
> ARM_FFA_RT_MODE has none, and the uclass side already uses
> IS_ENABLED(CONFIG_ARM_FFA_RT_MODE) - please use IS_ENABLED() here and
> in arm_ffa_runtime.h.
>
Sure. I will be making suggested change in patchset v2.
Regards
Harsimran Singh Tungal
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > + if (is_smc64) {
> > + req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
> > + } else {
> > + req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
> > + }
>
> Single-statement bodies should not be braced. Please run patman or
> checkpatch.pl on your patches. Also, the two efi_memset_runtime()
> calls below clear fresh stack variables. Please initialise them at
> declaration ('ffa_value_t ffa_args_rt = {}') and drop the explicit
> memset()s; the compiler's zero-init is just as runtime-safe and is
> what the boot path already does.
>
> Also could you run checkpatch / patman over your patches for v2?
>
I will keep the brace cleanup in v2, but I can't keep the `= {}`
initialization for the two local `ffa_value_t` variables.
I tested that variant and it triggers a Linux boot-time runtime warning
for this EFI runtime path, because the generated code is no longer
runtime-safe and initializing the way you are suggesting is not allowing
to map those variable in runtime memory. So, I suggest to restore the
explicit efi_memset_runtime() calls for those fresh stack variables.
Regards
Harsimran Singh Tungal
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
> > @@ -1047,6 +961,11 @@ static int ffa_do_probe(struct udevice *dev)
> > + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> > + ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
> > + if (ret)
> > + return ret;
> > + }
>
> If event creation fails here, the RX/TX buffers mapped above and the
> partition cache are leaked, i,e. the existing failure path for
> ffa_cache_partitions_info() at least calls
> ffa_unmap_rxtx_buffers_hdlr(). Please follow the same pattern, or move
> event registration before resource allocation.
>
Thanks for noticing this. This will be fixed in v2.
I will move ffa_setup_efi_exit_boot_services_event() to immediately after
ffa_get_endpoint_id() in ffa_do_probe(), so event-creation failure
happens before the later FF-A resource allocation steps.
Regards
Harsimran Singh Tungal
> > diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
> > @@ -41,3 +44,11 @@ config ARM_FFA_TRANSPORT
> > +config ARM_FFA_RT_MODE
> > + bool "Enable FF-A runtime support"
> > + depends on ARM_FFA_TRANSPORT && EFI_LOADER
> > + default y
>
> Just to check, does every existing FF-A user want this on? 'default y'
> silently enables a new transport path (and the ExitBootServices
> callback) for everyone with ARM_FFA_TRANSPORT && EFI_LOADER. I'd
> suggest defaulting, or at minimum 'default y if CORSTONE1000' or
> similar, until other boards have opted in.
>
The intention is for this to be a generic FF-A + EFI capability, not a
Corstone1000-specific opt-in.
`ARM_FFA_TRANSPORT` already has multiple in-tree users, so I would
prefer not to tie `ARM_FFA_RT_MODE` to a single board. Under
`ARM_FFA_TRANSPORT && EFI_LOADER`, this just enables the FF-A runtime
path and registers the ExitBootServices callback; the runtime transport
is only used by EFI runtime clients.
So I would prefer to keep `default y`.
Regards
Harsimran Singh Tungal
> > diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
> > @@ -212,9 +227,8 @@ struct ffa_partitions {
> > - u32 fwk_version;
> > + struct ffa_priv_runtime rt;
> > struct udevice *emul;
> > - u16 id;
>
> Just to clarify the model: 'struct ffa_priv' now embeds 'struct
> ffa_priv_runtime rt' at boot, and at ExitBootServices we copy the
> whole sub-struct (including 'use_ffa_runtime', always false here) into
> the resident 'ffa_priv_rt', then immediately overwrite use_ffa_runtime
> via ffa_enable_runtime_context(). Layering would be clearer if
> 'use_ffa_runtime' lived only on the resident copy and ffa_priv_runtime
> carried just the data shipped across the boundary (fwk_version, id).
>
> Regards,
> Simon
Agreed.
For v2, I split the runtime-enabled state out of `struct ffa_priv_runtime`.
The copied sub-struct now carries only the boot-time FF-A data that needs
to cross the `ExitBootServices()` boundary (`fwk_version` and `id`), while
the resident runtime-ready flag lives separately in the runtime copy and
is only set by `ffa_enable_runtime_context()`.
This keeps the boundary data limited to what is actually transported into runtime.
This will be fixed in patchset v2.
Regards
Harsimran Singh Tungal
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-04-27 16:21 ` Ilias Apalodimas
@ 2026-05-04 20:40 ` Harsimran Singh Tungal
2026-05-08 10:23 ` Abdellatif El Khlifi
1 sibling, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-04 20:40 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: Harsimran Singh Tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
On 2026-04-27 19:21 +0300, Ilias Apalodimas wrote:
> Hi Harsimran,
>
> On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> >
> > Enable MM variable services over FF-A after ExitBootServices
> >
> > This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
> > communication with the secure world during EFI runtime. It enables EFI
> > runtime variable access and MM communication using FF-A transport when
> > ExitBootServices() has already been called.
> >
> > Key changes:
> > ------------
> > - Introduce runtime-safe implementations for MM communication,
> > notification, and variable access using FF-A driver.
> > - Introduce communication-buffer helper (get_comm_buf()) that switches
> > between dynamic allocation (boot phase) and the fixed FF-A shared
> > buffer (runtime phase).
> > - Mark persistent data and code with __efi_runtime and
> > __efi_runtime_data attributes.
> > - Use direct physical address mapping for shared buffers since
> > U-Boot operates with 1:1 physical-to-virtual mapping.
> > - Only per-buffer cache maintenance is performed at runtime,
> > as whole D-cache invalidation would violate the OS coherency model
> > after ExitBootServices().
> > - Add runtime-phase tracking (efi_runtime_enabled).
>
> Why is this needed? For the memory allocations?
>
> [...]
Mainly yes, but not only.
`efi_runtime_enabled` is the driver-local gate for the post-`ExitBootServices()` path.
In this patch it is used first to make `get_comm_buf()` stop using `calloc()` and
switch to the statically reserved FF-A shared buffer, since dynamic allocation is
no longer valid at runtime.
It also keeps the runtime FF-A/MM path tied to the actual boot-to-runtime handover in
`efi_variables_boot_exit_notify()`
>
> > *
> > * Authors:
> > * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > @@ -14,6 +14,7 @@
> >
> > #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> > #include <arm_ffa.h>
> > +#include <arm_ffa_runtime.h>
> > #endif
> > #include <cpu_func.h>
> > #include <dm.h>
> > @@ -34,20 +35,47 @@
> > #define MM_DENIED (-3)
> > #define MM_NO_MEMORY (-5)
> >
> > +static const int __efi_runtime_rodata mm_sp_errmap[] = {
> > + [-MM_NOT_SUPPORTED] = -EINVAL,
> > + [-MM_INVALID_PARAMETER] = -EPERM,
> > + [-MM_DENIED] = -EACCES,
> > + [-MM_NO_MEMORY] = -EBUSY,
> > +};
> > +
>
> These are already defined above and used in ffa_notify_mm_sp(). If you
> plan to convert them, do it for the entire file.
>
> [...]
>
Agreed. For v2, I will change this to use a single MM SP return-code mapper for both the
boot and runtime FF-A notification paths, instead of keeping the table/helper only
for runtime.
This will be fixed in v2.
> > +/**
> > + * efi_is_runtime_enabled() - Indicate whether the system is in the UEFI runtime phase
> > + *
> > + * This helper returns whether the firmware has transitioned into the
> > + * UEFI runtime phase, meaning that ExitBootServices() has been invoked.
> > + *
> > + * Return:
> > + * true - The system is operating in UEFI runtime mode.
> > + * false - The system is still in the boot services phase.
> > + */
> > +static bool __efi_runtime efi_is_runtime_enabled(void)
> > +{
> > + return efi_runtime_enabled;
> > +}
>
> Enabled is a bit confusing. efi_at_runtime() should be enough. The
> efi_tcg.c code calls this 'ebs_called'
>
Agreed.
For v2, I will rename the helper to `efi_at_runtime()` and changed the backing state
to `ebs_called`, so the naming reflects the actual `ExitBootServices()` transition
rather than a generic "enabled" state.
That also matches the naming already used in `efi_tcg2.c`.
Your suggested changes will be in patchset v2.
> > +
> > /**
> > * get_connection() - Retrieve OP-TEE session for a specific UUID.
> > *
> > @@ -169,6 +197,28 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
> > }
> >
> > #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> > +/**
> > + * ffa_map_sp_event_runtime() - Map MM SP response to errno (runtime-safe)
> > + * @sp_event_ret: MM SP return code from ffa_notify_mm_sp_runtime()
> > + *
> > + * Convert the MM SP return code into a standard U-Boot errno. This helper
> > + * is marked __efi_runtime to ensure it is safe to call after
> > + * ExitBootServices().
> > + *
> > + * Return: 0 on success, negative errno on failure
> > + */
> > +static __efi_runtime int ffa_map_sp_event_runtime(int sp_event_ret)
> > +{
> > + int idx = -sp_event_ret;
> > +
> > + if (sp_event_ret == MM_SUCCESS)
> > + return 0;
> > + if (idx > 0 && idx < (int)ARRAY_SIZE(mm_sp_errmap) &&
> > + mm_sp_errmap[idx])
> > + return mm_sp_errmap[idx];
> > + return -EACCES;
> > +}
> > +
> > /**
> > * ffa_notify_mm_sp() - Announce there is data in the shared buffer
> > *
> > @@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
> > return ret;
> > }
> >
> > +/**
> > + * ffa_notify_mm_sp_runtime() - Runtime implementation of
> > + * ffa_notify_mm_sp()
> > + *
> > + * Notify the MM partition in the trusted world that
> > + * data is available in the shared buffer.
> > + * This is a blocking call during which trusted world has exclusive access
> > + * to the MM shared buffer.
> > + *
> > + * Return:
> > + *
> > + * 0 on success
> > + */
> > +static int __efi_runtime ffa_notify_mm_sp_runtime(void)
> > +{
> > + struct ffa_send_direct_data msg = {0};
> > + int ret;
> > + int sp_event_ret;
> > +
> > + msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
> > +
> > + ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
> > + if (ret)
> > + return ret;
> > +
> > + ret = ffa_map_sp_event_runtime(sp_event_ret);
> > + return ret;
> > +}
> > +
> > /**
> > * ffa_discover_mm_sp_id() - Query the MM partition ID
> > *
> > @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > return efi_ret;
> > }
> >
> > +/**
> > + * ffa_mm_communicate_runtime() - Runtime implementation of ffa_mm_communicate()
> > + * @comm_buf: locally allocated communication buffer used for rx/tx
> > + * @comm_buf_size: communication buffer size
> > + *
> > + * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
> > + * that there is data to read from the shared buffer.
> > + * Communication with the MM SP is performed using FF-A transport.
> > + * On the event, MM SP can read the data from the buffer and
> > + * update the MM shared buffer with response data.
> > + * The response data is copied back to the communication buffer.
> > + *
> > + * Return:
> > + *
> > + * EFI status code
> > + */
> > +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> > + ulong comm_buf_size)
> > +{
>
> There's a lot of code duplication between the boottime and runtime
> variants, but I don;t see why we need it. Can't we have a single
> function that works both boottime and runtime?
>
> [...]
Agreed.
For v2, I will collapse the separate `_runtime` helpers into the common implementations.
`get_mm_comms()`, `mm_communicate()`, `ffa_mm_communicate()`, and `ffa_notify_mm_sp()`
will handle both boot and runtime, with only a small `efi_at_runtime()` branch for the
phase-specific parts.
This removes the duplicated flow and keeps the runtime-specific handling in one place.
This will be implemented in Patchset v2.
> > + * must clean the corresponding cache lines to the Point of Coherency (PoC)
> > + * before entering secure world.
> > + *
> > + * S -> NS (response path):
> > + *
> > + * The secure world may update the same shared buffer in DDR. After returning
> > + * to non-secure, any cached copies of that region in NS may be stale. We
> > + * therefore invalidate the shared buffer range after the FF-A call to drop
> > + * those lines and force subsequent reads to fetch the latest data from DDR.
> > + *
> > + * Note: Whole-cache invalidation must not be used in EFI runtime context.
> > + * After ExitBootServices(), the OS owns the cache hierarchy; global invalidation
> > + * could drop OS dirty lines and violate the OS coherency model. Always operate
> > + * on the shared buffer range only.
> > + */
> > + if (IS_ENABLED(CONFIG_ARM64))
> > + flush_dcache_range((unsigned long)comm_buf,
>
> This doesn't seem to be marked as efi_runtime. How was this patchset tested?
>
Thanks, good catch.
I tested it by booting Linux and exercising the EFI runtime variable path, so on my setup the
call chain was still reachable and worked in practice.
I will rework this in v2.
Instead of adding EFI-specific cache helpers, I will reuse the existing arm64
`flush_dcache_range()` / `invalidate_dcache_range()` path and make it runtime-resident.
> > + (unsigned long)((u8 *)comm_buf +
> > + CONFIG_FFA_SHARED_MM_BUF_SIZE));
> > +
> > + /* Announce there is data in the shared buffer */
> > +
> > + ffa_ret = ffa_notify_mm_sp_runtime();
> > +
> > + if (IS_ENABLED(CONFIG_ARM64))
> > + invalidate_dcache_range((unsigned long)comm_buf,
> > + (unsigned long)((u8 *)comm_buf +
> > + CONFIG_FFA_SHARED_MM_BUF_SIZE));
> > +
> > + switch (ffa_ret) {
> > + case 0: {
>
> [...]
>
>
> >
> > /**
> > @@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> > return var_hdr->ret_status;
> > }
> >
> > +/**
> > + * mm_communicate_runtime() - Runtime implementation of mm_communicate()
> > + *
> > + * @comm_buf: locally allocated communication buffer
> > + * @dsize: buffer size
> > + *
> > + * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
> > + * The comm_buf format is the same for both partitions.
> > + * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
> > + * When using the u-boot FF-A driver, any MM SP is supported.
> > + *
> > + * Return: status code
> > + */
> > +static efi_status_t __efi_runtime mm_communicate_runtime(u8 *comm_buf, efi_uintn_t dsize)
> > +{
> > + efi_status_t ret = EFI_UNSUPPORTED;
> > + struct efi_mm_communicate_header *mm_hdr;
> > + struct smm_variable_communicate_header *var_hdr;
> > + enum mm_comms_select mm_comms;
> > +
> > + dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
> > + mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
> > + var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
> > +
> > + if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) {
> > + mm_comms = get_mm_comms_runtime();
> > + if (mm_comms == MM_COMMS_FFA)
> > + ret = ffa_mm_communicate_runtime(comm_buf, dsize);
>
> Same remarks here. I think having a single variant instead of an
> _runtime one is going to be easier to maintain. Especially for the
> functions that are very similar.
>
Agreed.
For v2, I will collapse the separate `_runtime` helpers into the common implementations.
`get_mm_comms()`, `mm_communicate()`, `ffa_mm_communicate()`, and `ffa_notify_mm_sp()`
will handle both boot and runtime, with only a small `efi_at_runtime()` branch for the
phase-specific parts.
This removes the duplicated flow and keeps the runtime-specific handling in one place.
This will be implemented in Patchset v2.
> > + }
> > +
> > + if (ret != EFI_SUCCESS)
> > + return ret;
> > +
> > + return var_hdr->ret_status;
> > +}
> > +
> > +/**
>
> [...]
>
> > - efi_uintn_t func, efi_status_t *ret)
> > +static __efi_runtime u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
> > + efi_uintn_t func, efi_status_t *ret)
> > {
> > - const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
> > struct efi_mm_communicate_header *mm_hdr;
> > struct smm_variable_communicate_header *var_hdr;
> > u8 *comm_buf;
> > @@ -465,16 +751,15 @@ static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
> > return NULL;
> > }
> >
> > - comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
> > - MM_VARIABLE_COMMUNICATE_SIZE +
> > - payload_size);
> > + comm_buf = get_comm_buf(payload_size);
> > if (!comm_buf) {
> > *ret = EFI_OUT_OF_RESOURCES;
> > return NULL;
> > }
> >
> > mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
> > - guidcpy(&mm_hdr->header_guid, &mm_var_guid);
> > + efi_memcpy_runtime(&mm_hdr->header_guid, &mm_var_guid_runtime,
> > + sizeof(mm_hdr->header_guid));
> > mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
> >
> > var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
> > @@ -982,6 +1267,9 @@ void efi_variables_boot_exit_notify(void)
> > efi_get_next_variable_name_runtime;
> > efi_runtime_services.set_variable = efi_set_variable_runtime;
> > efi_update_table_header_crc32(&efi_runtime_services.hdr);
> > +
> > + /* Set efi_runtime_enabled as true after ExitBootServices */
> > + efi_runtime_enabled = true;
> > }
> >
> > /**
> > @@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
> > {
> > efi_status_t ret;
> >
> > + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> > + /*
> > + * The FF-A shared buffer is accessed by EFI runtime services, so it must
> > + * be marked as runtime memory in the EFI memory map.
> > + */
> > + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> > + ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
> > + CONFIG_FFA_SHARED_MM_BUF_SIZE,
> > + EFI_RUNTIME_SERVICES_DATA);
> > + if (ret != EFI_SUCCESS) {
> > + log_err("EFI: failed to add FF-A shared buffer to runtime map (%lu)\n",
> > + ret);
> > + return ret;
> > + }
> > + log_info("EFI: FF-A shared buffer runtime map: addr=0x%lx size=0x%lx\n",
> > + (ulong)CONFIG_FFA_SHARED_MM_BUF_ADDR,
> > + (ulong)CONFIG_FFA_SHARED_MM_BUF_SIZE);
> > + }
> > +
>
> You should remove the memory map reservation if any of the code below fails.
>
> > /* Create a cached copy of the variables that will be enabled on ExitBootServices() */
> > ret = efi_var_mem_init();
> > if (ret != EFI_SUCCESS)
> > --
> > 2.34.1
> >
>
> Thanks
> /Ilias
>
Agreed. I will rework this in v2.
For v2, I will move the FF-A shared-buffer `efi_add_memory_map()` call to the end of
`efi_init_variables()`.
That way the runtime reservation is only created after the earlier initialization steps have
succeeded, so there is no extra rollback path needed if one of those steps fails.
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-04-28 18:12 ` Simon Glass
@ 2026-05-05 8:55 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-05 8:55 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:12 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > efi_loader: add FF-A runtime support in EFI variable TEE driver
> >
> > Enable MM variable services over FF-A after ExitBootServices
> >
> > This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
> > communication with the secure world during EFI runtime. It enables EFI
> > runtime variable access and MM communication using FF-A transport when
> > ExitBootServices() has already been called.
> >
> > Key changes:
> > ------------
> > - Introduce runtime-safe implementations for MM communication,
> > notification, and variable access using FF-A driver.
> > - Introduce communication-buffer helper (get_comm_buf()) that switches
> > between dynamic allocation (boot phase) and the fixed FF-A shared
> > buffer (runtime phase).
> > - Mark persistent data and code with __efi_runtime and
> > __efi_runtime_data attributes.
> > - Use direct physical address mapping for shared buffers since
> > U-Boot operates with 1:1 physical-to-virtual mapping.
> > [...]
> >
> > lib/efi_loader/efi_variable_tee.c | 331 ++++++++++++++++++++++++++++++++++++--
> > 1 file changed, 319 insertions(+), 12 deletions(-)
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
> > +static int __efi_runtime ffa_notify_mm_sp_runtime(void)
> > +{
> > + struct ffa_send_direct_data msg = {0};
> > + int ret;
> > + int sp_event_ret;
> > +
> > + msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
> > +
> > + ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
> > + if (ret)
> > + return ret;
> > +
> > + ret = ffa_map_sp_event_runtime(sp_event_ret);
> > + return ret;
> > +}
>
> It looks like ''sp_event_ret' is uninitialised. The boot-time twin
> sets sp_event_ret = msg.data0 after the FF-A call before mapping it;
> that line is missing here, so the runtime path branches on whatever
> was on the stack and returns -EACCES (or worse, success) regardless of
> the SP reply. Please add the assignment, and ideally a selftest
> exercising an SP error return so this would have been caught.
>
Agreed.
For v2, I will collapse the separate `_runtime` helpers into the common implementations
and `ffa_notify_mm_sp()` is one of them. So, this will be fixed
eventually in patchset v2.
Thanks
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> > + ulong comm_buf_size)
> > +{
>
> ...
> > + if (!comm_buf)
> > + return EFI_INVALID_PARAMETER;
> > +
> > + /* Discover MM partition ID at boot time */
> > + if (!mm_sp_id)
> > + return EFI_UNSUPPORTED;
>
> The comment is copied verbatim from ffa_mm_communicate() but at
> runtime we cannot discover anything - we can only check that boot-time
> discovery happened. Please rewrite as e.g. 'MM partition ID must have
> been discovered at boot time'.
>
For v2, I will collapse the separate `_runtime` helpers into the common implementations
and `ffa_mm_communicate()` is one of them. So, this will be fixed
eventually in patchset v2.
Thanks
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> > + ulong comm_buf_size)
> > +{
>
> ...
> > + switch (ffa_ret) {
> > + case 0: {
> ...
> > + case -EINVAL:
> > + efi_ret = EFI_DEVICE_ERROR;
> > + break;
>
> Almost the entire body is a copy of ffa_mm_communicate(), including
> the long cache-maintenance comment block which patch 12 then
> duplicates again into the boot helper. Please factor the shared logic
> into one helper that takes a 'runtime' bool (or function pointers for
> the FF-A and notify hooks) so we don't carry three near-identical
> copies. The current arrangement makes future fixes (like the missing
> sp_event_ret assignment above) easy to apply to only one twin.
>
Agreed.
For v2, I will collapse the separate `_runtime` helpers into the common implementations.
`get_mm_comms()`, `mm_communicate()`, `ffa_mm_communicate()`, and `ffa_notify_mm_sp()`
will handle both boot and runtime, with only a small `efi_at_runtime()` branch for the
phase-specific parts.
This removes the duplicated flow and keeps the runtime-specific handling in one place.
I will rework this in patchset v2.
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -386,6 +575,27 @@ static enum mm_comms_select get_mm_comms(void)
> > +static enum mm_comms_select __efi_runtime get_mm_comms_runtime(void)
> > +{
> > + bool ret;
> > +
> > + ret = efi_is_runtime_enabled();
> > + if (!ret)
> > + return MM_COMMS_UNDEFINED;
> > +
> > + return MM_COMMS_FFA;
> > +}
>
> But get_mm_comms_runtime() is only reached via the runtime services
> table, which is only wired up after efi_variables_boot_exit_notify()
> sets efi_runtime_enabled=true, so it always returns MM_COMMS_FFA,
> right? Either drop the wrapper and call ffa_mm_communicate_runtime()
> directly from mm_communicate_runtime(), or keep an explicit runtime
> sanity check, but please don't dress it up as transport selection.
>
For v2, I will collapse the separate `_runtime` helpers into the common implementations.
and `get_mm_comms()` is one of them. So, MM_COMMS_FFA will be returned
if CONFIG_ARM_FFA_RT_MODE is enabled.
Please let me know if you agree with this approach.
Thanks
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> > +static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
> > +{
> > + u8 *comm_buf;
> > +
> > + /* After ExitBootServices(), dynamic allocation is no longer permitted.
> > + * Use the predefined FF-A shared buffer at runtime; otherwise allocate
> > + * a fresh buffer during the boot phase.
> > + */
> > + if (efi_is_runtime_enabled()) {
> > + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> > + comm_buf = ffa_shared_buf;
> > + if (!comm_buf)
> > + return NULL;
> > + efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
> > + } else {
> > + return NULL;
> > + }
> > + } else {
>
> At runtime there is no validation that 'payload_size + headers' fits
> inside CONFIG_FFA_SHARED_MM_BUF_SIZE - the max_buffer_size check in
> setup_mm_hdr() compares against the SP-reported limit, which is not
> necessarily the same as the static shared buffer size, so an oversized
> payload can silently overflow the FF-A buffer when setup_mm_hdr()
> writes the header and the caller fills the data. Please add an
> explicit size check here, or assert that max_buffer_size <=
> CONFIG_FFA_SHARED_MM_BUF_SIZE at init time.
>
> Also: the multi-line comment uses kernel-doc style ('/*' on its own
> then '*' lines) elsewhere in this file, but here the first text line
> follows '/*' immediately.
Agreed.
For v2, I will add an explicit runtime check in `get_comm_buf()` so the full MM buffer
size (`headers + payload`) must fit inside `CONFIG_FFA_SHARED_MM_BUF_SIZE` before
the shared FF-A buffer is used.
I will also fix the nearby multi-line comment style in v2.
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -444,10 +731,9 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> > /**
> > * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
> > - * header data.
> > + * header data. It is runtime safe.
>
> The function no longer 'allocates' at runtime. It hands back a slot in
> the static shared buffer - so the summary is misleading. Please
> rewrite the description and drop the trailing 'It is runtime safe'
> (already implied by the new __efi_runtime tag).
>
Sure, I will rewrite the `setup_mm_hdr()` summary in patchset v2.
Thanks
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -34,20 +35,47 @@
> > +static const efi_guid_t __efi_runtime_rodata mm_var_guid_runtime =
> > + EFI_MM_VARIABLE_GUID;
>
> Why a separate '_runtime' copy of this GUID? The original mm_var_guid
> was a function-local in setup_mm_hdr(), so you can just promote it to
> file scope with __efi_runtime_rodata and use it for both phases.
>
Agreed.
For v2, I will keep the GUID local to `setup_mm_hdr()` and change it to a
`static const __efi_runtime_rodata` object there, since that is the only place it is used.
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
> > + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> > + /*
> > + * The FF-A shared buffer is accessed by EFI runtime services, so it must
> > + * be marked as runtime memory in the EFI memory map.
> > + */
> > + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> > + ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
> > + CONFIG_FFA_SHARED_MM_BUF_SIZE,
> > + EFI_RUNTIME_SERVICES_DATA);
>
> efi_add_memory_map() takes a size in bytes but the underlying
> implementation expects a page-count argument in some call sites. Can
> you please double-check that CONFIG_FFA_SHARED_MM_BUF_SIZE is
> interpreted as bytes here and that the buffer base is page-aligned,
> otherwise the OS will see a misdescribed runtime region. Worth a
> comment stating the alignment assumption.
>
I double-checked this path.
The shared buffer base is page-aligned in the current Corstone-1000
configuration, and for v2 I will add a comment at the efi_add_memory_map() call site documenting that
CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
CONFIG_FFA_SHARED_MM_BUF_SIZE is also interpreted as bytes.
Thanks
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -34,20 +35,47 @@
> > +static bool __efi_runtime_data efi_runtime_enabled;
>
> We already have a global indicator that boot services have exited:
> systab.boottime being set to NULL in efi_exit_boot_services()
>
> Adding a second flag here (and a wrapper efi_is_runtime_enabled() over
> it) means we need to keep them in sync. I'd prefer either hooking off
> systab.boottime (already __efi_runtime_data) or exposing a single
> global helper from efi_runtime.c that everyone uses.
>
Fair point. I kept a local ExitBootServices latch here because the same pattern already exists in
efi_tcg2.c with ebs_called, and I wanted to keep this FF-A runtime series aligned with that existing usage.
In this path the flag is only latched once on the ExitBootServices transition, so there is no separate
state machine beyond that handoff.
Does this approach sound reasonable to you?
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -4,7 +4,7 @@
> > * Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
> > * Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
> > - * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
> > + * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
>
> How about 2022-2026 ?
>
> The commit message also opens with 'This patch extends ...'; please
> use the imperative ('Extend lib/efi_loader/efi_variable_tee.c to ...')
> and drop 'This patch'. Same for 'Key changes:' / 'The change reuses
> ...' - describe what the code does in present tense.
>
> Regards,
> Simon
>
Thanks, I'll fix both in v2: update the copyright line to 2022-2026 and rewrite the commit message.
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
2026-04-28 18:16 ` Simon Glass
@ 2026-05-05 14:30 ` Harsimran Singh Tungal
2026-05-07 15:31 ` Simon Glass
0 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-05 14:30 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:16 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
> >
> > Route EFI runtime variable APIs through FF-A MM communication
> >
> > This patch implements full EFI Runtime Variable Services (GetVariable,
> > SetVariable, GetNextVariableName, and QueryVariableInfo) using the
> > FF-A/MM communication backend. Once ExitBootServices() has been invoked,
> > all variable operations now use the runtime-safe FF-A transport instead
> > of the boot-time communication paths.
> >
> > Key changes:
> > ============
> >
> > - Add runtime-safe variable property handling via FF-A MM SP.
> > - Add runtime versions of variable access and property operations.
> > - Replace all standard memory operations with EFI-runtime-safe variants.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > lib/charset.c | 2 +-
> > lib/efi_loader/efi_variable_tee.c | 322 +++++++++++++++++++++++++++++++++++++-
> > 2 files changed, 318 insertions(+), 6 deletions(-)
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -991,6 +1066,92 @@ out:
> > + /*
> > + * UEFI > 2.7 needs the attributes set even if the buffer is
> > + * smaller
> > + */
> > + if (attributes) {
> > + tmp = get_property_int_runtime(variable_name, name_size, vendor,
> > + &var_property);
> > + if (tmp != EFI_SUCCESS) {
> > + ret = tmp;
> > + return ret;
> > + }
> > + *attributes = var_acc->attr;
> > + if (var_property.property &
> > + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
> > + *attributes |= EFI_VARIABLE_READ_ONLY;
> > + }
>
> get_property_int_runtime() ends up calling setup_mm_hdr() ->
> get_comm_buf(), and at runtime get_comm_buf() does
> efi_memset_runtime(ffa_shared_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE)
> on the same shared buffer that var_acc points into.
>
> By the time you read var_acc->attr it has been zeroed, so
> '*attributes' will only ever come back as 0 (optionally OR'd with
> EFI_VARIABLE_READ_ONLY). The boot-time path gets away with this
> because get_property_int() calloc()s a fresh buffer; the runtime path
> cannot. Please cache var_acc->attr in a local before the call, or move
> the get_property_int_runtime() call ahead of the SP exchange.
>
Agreed, you're right.
`get_property_int_runtime()` reuses the same runtime FF-A shared buffer, so
the second call can clear the buffer backing `var_acc` before `var_acc->attr`
is copied out.
For v2, I will cache `var_acc->attr` in a local before calling
`get_property_int_runtime()` and then used that cached value when updating
`*attributes`.
Thanks
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -1228,7 +1477,70 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> > + ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
> > + attributes &= EFI_VARIABLE_MASK;
> > +
> > + ret = get_property_int_runtime(variable_name, name_size, guid,
> > + &var_property);
> > + if (ret != EFI_SUCCESS)
> > + return ret;
> > +
> > + /*
> > + * Allocate the buffer early, before switching to RW (if needed)
> > + * so we won't need to account for any failures in reading/setting
> > + * the properties, if the allocation fails
> > + */
> > + comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
> > + SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
> > + if (!comm_buf)
> > + return ret;
> > +
> > + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
> > + return EFI_WRITE_PROTECTED;
>
> The comment is copied from efi_set_variable_int() and no longer
> matches the code - there is no RW switch in the runtime path (no
> ro_check argument), and the allocation happens after the property
> read, the opposite of what the comment claims. Either drop the comment
> or, better, do the RO check before calling setup_mm_hdr() so the
> early-return is quicker.
>
Agreed.
That comment was copied from the boot-time path.
For v2, I will drop it and move the `VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY`
check ahead of `setup_mm_hdr()`, so the runtime path returns
`EFI_WRITE_PROTECTED` before allocating the MM communication buffer.
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -859,6 +859,38 @@ out:
> > +static efi_status_t __efi_runtime set_property_int_runtime(const u16 *variable_name,
> > + efi_uintn_t name_size,
> > + const efi_guid_t *vendor,
> > + struct var_check_property *var_property)
>
> As mentioned elsewhere, the four new functions
> (set_property_int_runtime, get_property_int_runtime,
> efi_get_variable_runtime, efi_get_next_variable_name_runtime) are
> near-line-for-line copies of their boot-time counterparts with
> memcpy/guidcpy/memset swapped for the efi_*_runtime helpers and a
> different mm_communicate(). Since setup_mm_hdr() was made runtime-safe
> in patch 3, can the boot-time helpers be reused directly (with
> mm_communicate() picking the right transport based on
> efi_is_runtime_enabled())? It would also avoid the special-case free()
> path.
>
I kept the separate runtime wrappers intentionally so the
post-ExitBootServices call graph stays explicit and auditable: only
runtime-safe helpers, no driver-model assumptions, and no boot-time heap
cleanup semantics.
I also tried to match the existing EFI variable structure: `efi_variable.c`
(Done by Heinrich Schuchardt) already has separate boot-time and runtime
service entry points, so I kept the same split here instead of introducing a
different pattern only for the TEE/FF-A backend.
Apart from these runtime variants, I will collapse the other `_runtime` helpers
into the common implementations in v2 patchset. `get_mm_comms()`, `mm_communicate()`,
`ffa_mm_communicate()`, and `ffa_notify_mm_sp()` will handle both boot and runtime,
with only a small `efi_at_runtime()` branch for the phase-specific parts.
Does this explanation sound reasonable to you?
Thanks
> > diff --git a/lib/charset.c b/lib/charset.c
> > @@ -407,7 +407,7 @@ size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
> > -size_t u16_strsize(const void *in)
> > +size_t __efi_runtime u16_strsize(const void *in)
>
> This change should really be in its own patch with a one-line note
> that it's needed by the new runtime callers. It is unrelated to the
> SetVariable/GetVariable wiring and is easy to lose in this 320-line
> diff.
>
For v2, I'll split the `u16_strsize()` `__efi_runtime` annotation into a
separate small patch with a short note that it is needed by
the new runtime variable callers. That should keep this patch focused on
the SetVariable/GetVariable runtime wiring.
> > Key changes:
> > ============
>
> >
> > - Add runtime-safe variable property handling via FF-A MM SP.
> > - Add runtime versions of variable access and property operations.
> > - Replace all standard memory operations with EFI-runtime-safe variants.
>
> The'============' underline is more for rST documentation than commit
> messages - please drop it. The third bullet is also misleading: only
> the new runtime functions use the runtime-safe variants; the existing
> boot-time helpers are unchanged. It is generally better to use prose
> than bullet points in a commit message.
>
> Regards,
> Simon
>
Sure, I will update this in v2.
Regards
Harsimran Singh
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 00/12] arm64: FF-A runtime transport for EFI variables
2026-04-24 22:18 ` [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Heinrich Schuchardt
@ 2026-05-05 14:37 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-05 14:37 UTC (permalink / raw)
To: Heinrich Schuchardt
Cc: Harsimran Singh Tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Hugues Kamba Mpiana, Simon Glass
On 2026-04-25 00:18 +0200, Heinrich Schuchardt wrote:
> Am 24. April 2026 19:31:39 MESZ schrieb Harsimran Singh Tungal <harsimransingh.tungal@arm.com>:
> >Hi all,
> >
> >This series adds FF-A runtime transport support so EFI variable runtime
> >services can communicate with the secure world after ExitBootServices().
> >It also extends tests, docs, and board configs to validate the runtime
> >path and keep boot‑time behavior aligned with the runtime flow.
>
> Hello Harsiman,
>
> Could you, please, explain the motivation for the series.
>
> What is the overall architecture?
>
> Please, describe how to set up a system on QEMU to test your development including the instructions for the secure world.
>
> We would need a test in the CI using QEMU.
>
> Best regards
>
> Heinrich
>
>
Hi Heinrich,
The motivation for the series is that, when EFI variables are backed by an
MM Secure Partition reached over FF-A, U-Boot can use that path during boot,
but after ExitBootServices() the normal FF-A/DM path is no longer suitable.
As a result, EFI runtime variable services can no longer reach the secure
partition. The goal of this series is to keep only the minimal FF-A transport
needed for EFI runtime variable services available after ExitBootServices().
The overall architecture is:
- During boot, the FF-A bus probes normally, discovers the U-Boot endpoint ID
and the MM SP partition ID, and registers an ExitBootServices() callback.
- At ExitBootServices(), U-Boot copies the minimal FF-A state needed at
runtime into resident runtime data and enables the runtime context.
- After that, EFI runtime variable operations
(SetVariable/GetVariable/GetNextVariableName/QueryVariableInfo) use the
runtime-safe path in efi_variable_tee.c, reuse the fixed FF-A shared buffer,
perform range-based cache maintenance on that buffer only, and notify the
MM SP using FF-A direct messaging.
So the runtime side is intentionally narrow: it keeps just enough FF-A support
for EFI runtime variables, rather than trying to preserve the full FF-A bus
or driver-model stack after ExitBootServices().
On testing, the current series adds sandbox DM tests for the FF-A runtime
helpers and EFI selftests for the runtime variable path, and my end-to-end
validation so far has been on Corstone-1000. I do not have a proper QEMU
setup with the corresponding secure-world/MM SP side packaged as part of this
series, so I cannot provide good QEMU instructions.
More details on building and running Corstone-1000 FVP can be found here:
https://corstone1000.docs.arm.com/en/latest/user-guide.html
Please let me know if this overall direction makes sense to you.
Regards
Harsimran Singh Tungal
> >
> >Changes in this series:
> >- Add EFI runtime-safe memset helper and FF-A runtime transport support.
> >- Implement FF-A runtime communication in the EFI variable TEE backend.
> >- Enable runtime variable operations and move helpers to avoid conflicts.
> >- Add sandbox runtime transport tests and metadata reuse.
> >- Extend EFI selftests for runtime variables and bootefi selftest config.
> >- Document the FF-A runtime transport and selftest behavior.
> >- Align boot‑time cache maintenance with the runtime path.
> >
> >Harsimran Singh Tungal (12):
> > efi_loader: add runtime memset helper
> > arm-ffa: add FF-A bus runtime support
> > efi_loader: add FF-A runtime support in EFI variable TEE driver
> > efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A
> > transport
> > efi_loader: move runtime GetVariable() helpers to efi_variable.c
> > corstone1000: enable bootefi selftest
> > efi: selftest: add runtime variable tests with non-volatile storage
> > test: dm: add sandbox FF-A runtime transport tests
> > sandbox: ffa: share synthetic partition metadata via macros
> > doc: arm64: document FF-A runtime path for EFI variables
> > doc: bootefi: note two-phase runtime variables selftest
> > efi_loader: align FF-A cache maintenance with runtime path
> >
> > arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +-
> > configs/corstone1000_defconfig | 3 +
> > doc/arch/arm64.ffa.rst | 92 ++-
> > doc/usage/cmd/armffa.rst | 11 +
> > doc/usage/cmd/bootefi.rst | 12 +
> > drivers/firmware/arm-ffa/Kconfig | 11 +
> > drivers/firmware/arm-ffa/Makefile | 4 +-
> > drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 ++++++++
> > drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 +--
> > drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
> > drivers/firmware/arm-ffa/ffa-emul-uclass.c | 48 +-
> > include/arm_ffa.h | 16 +-
> > include/arm_ffa_priv.h | 24 +-
> > include/arm_ffa_runtime.h | 183 +++++
> > include/efi_loader.h | 3 +
> > lib/charset.c | 2 +-
> > lib/efi_loader/efi_runtime.c | 21 +
> > lib/efi_loader/efi_var_common.c | 24 -
> > lib/efi_loader/efi_variable.c | 24 +
> > lib/efi_loader/efi_variable_tee.c | 686 +++++++++++++++++-
> > .../efi_selftest_variables_runtime.c | 106 ++-
> > test/dm/Makefile | 3 +-
> > test/dm/ffa.c | 6 +-
> > test/dm/ffa_runtime.c | 82 +++
> > 24 files changed, 1602 insertions(+), 189 deletions(-)
> > create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > create mode 100644 include/arm_ffa_runtime.h
> > create mode 100644 test/dm/ffa_runtime.c
> >
>
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c
2026-04-28 12:03 ` Ilias Apalodimas
@ 2026-05-06 10:30 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-06 10:30 UTC (permalink / raw)
To: Ilias Apalodimas
Cc: Harsimran Singh Tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Heinrich Schuchardt, Hugues Kamba Mpiana, Simon Glass
On 2026-04-28 15:03 +0300, Ilias Apalodimas wrote:
> Hi Harsiman,
>
> On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> >
> > Consolidate runtime GetVariable helpers to avoid duplicates
> >
> > The functions efi_get_variable_runtime() and
> > efi_get_next_variable_name_runtime() were implemented in
> > efi_variable_tee.c as part of the FF-A runtime variable handling work.
> > However, default implementations for these same runtime helpers also
> > exist in efi_var_common.c.
>
> efi_variable.c is there to deal with variables stored in the
> non-secure world and efi_variable_tee.c for the variables stored on
> the non secure world.
> You can't compile both. By moving efi_get_next_variable_name_runtime
> out of common you will break efi_variable_tee.c for example.
>
> The reason these are in common is that U-Boot exposes the memory
> backend to the kernel for get/setvariable. Then the kernel at runtime
> decides to ignore the u-boot runtime functions and rewires them to
> internal op-tee functions. If you want a variable variant for FF-A
> that belongs into efi_variable_tee.c
>
> Thanks
> /Ilias
>
>
Thanks, that is the intent here as well.
This patch is not trying to move the FF-A-specific runtime path out of
efi_variable_tee.c. The TEE/FF-A runtime variants stay in
efi_variable_tee.c.
What this patch does is relocate the generic runtime read helpers out of
efi_var_common.c, which is always built, into efi_variable.c, which is
only built for the non-TEE backend. That way the non-TEE backend keeps
the generic memory-backed runtime implementations, while the TEE/FF-A
backend can provide its own runtime read helpers in efi_variable_tee.c
without a symbol clash.
I'll reword the commit message in v2 to make that clearer.
Regards
Harsimran Singh Tungal
> > This results in duplicate symbol definitions.
> > To resolve the conflict and centralize the runtime API, this patch moves
> > the default implementations of the two runtime GetVariable() helpers
> > from efi_var_common.c to efi_variable.c. This ensures that:
> >
> > - only a single definition of each runtime helper exists,
> > - backend-specific implementations can override these cleanly,
> > - the EFI runtime variable service table continues to reference the
> > correct functions.
> >
> > No functional changes are introduced; this is a structural cleanup to
> > avoid build-time conflicts and consolidate EFI runtime variable support
> > in the appropriate file.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> > ---
> > lib/efi_loader/efi_var_common.c | 24 ------------------------
> > lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
> > 2 files changed, 24 insertions(+), 24 deletions(-)
> >
> > diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
> > index d63c2d1b1cd..7cbf098c64a 100644
> > --- a/lib/efi_loader/efi_var_common.c
> > +++ b/lib/efi_loader/efi_var_common.c
> > @@ -173,30 +173,6 @@ efi_status_t EFIAPI efi_query_variable_info(
> > return EFI_EXIT(ret);
> > }
> >
> > -efi_status_t __efi_runtime EFIAPI
> > -efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> > - u32 *attributes, efi_uintn_t *data_size, void *data)
> > -{
> > - efi_status_t ret;
> > -
> > - ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
> > - data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
> > -
> > - /* Remove EFI_VARIABLE_READ_ONLY flag */
> > - if (attributes)
> > - *attributes &= EFI_VARIABLE_MASK;
> > -
> > - return ret;
> > -}
> > -
> > -efi_status_t __efi_runtime EFIAPI
> > -efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
> > - u16 *variable_name, efi_guid_t *guid)
> > -{
> > - return efi_get_next_variable_name_mem(variable_name_size, variable_name,
> > - guid, EFI_VARIABLE_RUNTIME_ACCESS);
> > -}
> > -
> > /**
> > * efi_set_secure_state - modify secure boot state variables
> > * @secure_boot: value of SecureBoot
> > diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
> > index 9923936c1b5..f2e0e1ad4e2 100644
> > --- a/lib/efi_loader/efi_variable.c
> > +++ b/lib/efi_loader/efi_variable.c
> > @@ -579,6 +579,30 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
> > return EFI_SUCCESS;
> > }
> >
> > +efi_status_t __efi_runtime EFIAPI
> > +efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> > + u32 *attributes, efi_uintn_t *data_size, void *data)
> > +{
> > + efi_status_t ret;
> > +
> > + ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
> > + data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
> > +
> > + /* Remove EFI_VARIABLE_READ_ONLY flag */
> > + if (attributes)
> > + *attributes &= EFI_VARIABLE_MASK;
> > +
> > + return ret;
> > +}
> > +
> > +efi_status_t __efi_runtime EFIAPI
> > +efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
> > + u16 *variable_name, efi_guid_t *guid)
> > +{
> > + return efi_get_next_variable_name_mem(variable_name_size, variable_name,
> > + guid, EFI_VARIABLE_RUNTIME_ACCESS);
> > +}
> > +
> > /**
> > * efi_variables_boot_exit_notify() - notify ExitBootServices() is called
> > */
> > --
> > 2.34.1
> >
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 06/12] corstone1000: enable bootefi selftest
2026-04-28 18:01 ` Simon Glass
@ 2026-05-06 12:20 ` Harsimran Singh Tungal
2026-05-07 15:32 ` Simon Glass
0 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-06 12:20 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:01 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > corstone1000: enable bootefi selftest
> >
> > Enable UEFI selftest command in Corstone-1000 defconfig
> >
> > Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> > so the board can run the built-in UEFI self-test suite during
> > development and validation.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > configs/corstone1000_defconfig | 3 +++
> > 1 file changed, 3 insertions(+)
>
> > diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> > @@ -63,6 +65,7 @@ CONFIG_SYSRESET=y
> > CONFIG_SYSRESET_PSCI=y
> > CONFIG_TEE=y
> > CONFIG_OPTEE=y
> > +# CONFIG_CMD_POWEROFF is not set
> > CONFIG_USB=y
>
> Why is this disabled? It's not mentioned in the commit message and
> looks unrelated to enabling the bootefi selftest. If it's a stray
> byproduct of 'make savedefconfig' please drop it; if intentional it
> should be a separate patch with its own justification.
>
Thanks, these two lines are intentional rather than stray
`savedefconfig` fallout.
On Corstone-1000, enabling `CMD_BOOTEFI_SELFTEST` causes
`CMD_BOOTEFI_HELLO` to default to `y`, and `CMD_POWEROFF` is also
pulled in on this PSCI-based defconfig. I wanted to enable only the
selftest command here, without broadening the rest of the board command
set, so both are kept explicitly disabled.
I can make that explicit in the commit message in v2.
Does this sound reasonable to you?
> > diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> > @@ -32,6 +32,8 @@ CONFIG_SYS_PROMPT="corstone1000# "
> > # CONFIG_CMD_CONSOLE is not set
> > CONFIG_CMD_FWU_METADATA=y
> > CONFIG_CMD_BOOTZ=y
> > +# CONFIG_CMD_BOOTEFI_HELLO is not set
> > +CONFIG_CMD_BOOTEFI_SELFTEST=y
>
> The commit message says only that selftest is being enabled, but
> you're also explicitly disabling CMD_BOOTEFI_HELLO (which would
> otherwise default to y once SELFTEST is set). Please mention this, and
> ideally state the real motivation - that this is needed so patch 7 of
> the series can run the runtime variable selftest on this board, right?
>
Thanks, agreed.
The explicit `CMD_BOOTEFI_HELLO=n` is intentional. On this board,
enabling `CMD_BOOTEFI_SELFTEST` would otherwise make
`CMD_BOOTEFI_HELLO` default to `y`. The goal here is to enable the
selftest command so the later runtime-variable selftest patch in this
series can be exercised on Corstone-1000, without broadening the rest
of the board command set at the same time.
I'll make that motivation explicit in the commit message in v2.
Regards
Harsimran Singh Tungal
> > Enable UEFI selftest command in Corstone-1000 defconfig
>
> >
> > Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> > so the board can run the built-in UEFI self-test suite during
> > development and validation.
>
> The first paragraph just restates the subject. Please drop it and keep
> the second paragraph, which actually explains the change. Referencing
> the runtime-variable selftest added later in the series would also
> help, since that is the real reason for enabling it now.
>
> Regards,
> Simon
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage
2026-04-28 18:04 ` Simon Glass
@ 2026-05-06 15:14 ` Harsimran Singh Tungal
2026-05-07 15:32 ` Simon Glass
0 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-06 15:14 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:04 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > efi: selftest: add runtime variable tests with non-volatile storage
> >
> > Extend runtime variable tests for persistent storage
> >
> > Previously, EFI selftesting of runtime variables was only supported
> > under CONFIG_EFI_RT_VOLATILE_STORE, which uses VarToFile to simulate
> > non-volatile variable storage. This commit adds new test cases that
> > exercise runtime variable operations for persistent storage.
> >
> > Features tested:
> > - Creation of runtime-accessible variables (set)
> > - Retrieval of runtime variables (get)
> > - Deletion using SetVariable() with size = 0
> > - Append operation using EFI_VARIABLE_APPEND_WRITE
> >
> > This improves EFI compliance validation for non-volatile runtime storage
> > scenarios and ensures proper attribute enforcement and variable
> > management.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > lib/efi_selftest/efi_selftest_variables_runtime.c | 106 +++++++++++++++++++++-
> > 1 file changed, 104 insertions(+), 2 deletions(-)
>
> > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > @@ -39,6 +46,80 @@ static int execute(void)
> > + /* Compare the value of EFI variable if it already exists in non volatile storage */
> > + if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
> > + len = sizeof(v) / 2;
> > + ret = st_runtime->get_variable(u'efi_st_var0', &guid_vendor0,
> > + &attr, &len, data);
> > + if (ret == EFI_SUCCESS) {
>
> The two-phase split worries me. As written, phase 1 creates a
> non-volatile variable and immediately returns EFI_ST_SUCCESS, so a
> single 'bootefi selftest' run reports a green test even though none of
> the new assertions (append, delete, re-get) actually ran. It also
> leaves 'efi_st_var0' behind in NV storage if the user never reboots
> (or if phase 2 fails on an early assertion before the final delete).
> Could you split this into two distinct EFI_UNIT_TEST entries - say
> 'variables at runtime (setup)' and 'variables at runtime (verify)'.
> Then the user (and CI) explicitly select each phase, and the
> persistent state across the two is part of the contract rather than a
> hidden side-effect. At minimum, phase 1 needs to print a clear 'test
> incomplete, please reboot and rerun' rather than EFI_ST_SUCCESS.
>
Hi Simon, Heinrich,
I would like to confirm the design direction for this selftest change before I send v2.
The proposal is:
- Keep the existing automatic `variables at runtime` test for `CONFIG_EFI_RT_VOLATILE_STORE=y`, so the volatile-store runtime coverage stays in the current single-run form.
- For the non-volatile case, replace the previous implicit two-phase flow with two explicit on-request tests:
`variables at runtime setup`
EFI_UNIT_TEST(variables_run_setup) = {
.name = "variables at runtime setup",
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute_setup,
.on_request = true,
};
`variables at runtime verify`
EFI_UNIT_TEST(variables_run_verify) = {
.name = "variables at runtime verify",
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
.setup = setup,
.execute = execute_verify,
.on_request = true,
};
- `execute_setup` would:
run the runtime `QueryVariableInfo()` checks,
exercise create/delete of a runtime variable,
create `efi_st_var0` in non-volatile storage with the first half of the payload,
print that the system should be rebooted and `variables at runtime verify` should be run next.
- `execute_verify` would:
validate the prepared variable from `setup`,
append the remaining payload,
validate the full contents,
delete the variable,
confirm that it is gone.
- If `setup` finds an existing `efi_st_var0` already containing the expected half-payload, it would report that setup is already complete and ask the user to run `verify`.
If the existing variable does not match, it would delete the stale variable and recreate the expected setup state.
- The failure logs would also be made step-specific, so local runs and CI logs show exactly which runtime operation fails, and `verify` would print an explicit success line.
The intention is to make the reboot-dependent non-volatile flow explicit, while keeping the current volatile-store runtime test structure unchanged.
Does this design look reasonable to both of you for v2?
Regards
Harsimran Singh Tungal
> > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > @@ -39,6 +46,80 @@ static int execute(void)
> > + return EFI_ST_SUCCESS;
> > + } else {
> > + if (ret == EFI_NOT_FOUND) {
> > + efi_st_printf("EFI Variable efi_st_var0 not found. "
> > + "Executing First Phase\n");
> > + }
> > + }
> > + }
>
> Any return value other than EFI_SUCCESS or EFI_NOT_FOUND
> (EFI_DEVICE_ERROR, EFI_UNSUPPORTED on a platform without an FF-A
> backend, etc.) silently falls through to the volatile-store path below
> and mis-diagnoses the failure. Please fail explicitly when ret is not
> one of the two expected values.
>
> > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > @@ -279,7 +360,28 @@ static int execute(void)
> > } else {
> > - if (ret != EFI_UNSUPPORTED) {
> > + if (ret != EFI_SUCCESS) {
>
> This flips the contract: previously the !CONFIG_EFI_RT_VOLATILE_STORE
> branch asserted that runtime SetVariable() returns EFI_UNSUPPORTED,
> which is what every board without a runtime variable backend still
> does. After this patch any such board fails 'variables at runtime'.
> Please gate the new behaviour on something like CONFIG_EFI_MM_COMM_TEE
> (or whatever indicates a working runtime backend) and keep the
> EFI_UNSUPPORTED expectation otherwise.
>
> > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > @@ -39,6 +46,80 @@ static int execute(void)
> > + /* Append an existing variable */
> > + append_len = sizeof(v) - len;
> > + ret = st_runtime->set_variable(u'efi_st_var0', &guid_vendor0,
> > + EFI_VARIABLE_BOOTSERVICE_ACCESS |
> > + EFI_VARIABLE_RUNTIME_ACCESS |
> > + EFI_VARIABLE_APPEND_WRITE |
> > + EFI_VARIABLE_NON_VOLATILE,
> > + append_len, (v + len));
>
> Not sure if it is possible to align these lines properly? Not related
> to this patch, but the EFI_VARIABLE_... prefix is really too long.
>
> Drop redundant parens around v + len
>
> > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > @@ -39,6 +46,80 @@ static int execute(void)
> > + if (memcmp(data, v, len)) {
> > + efi_st_error("GetVariable failed\n");
> > + return EFI_ST_FAILURE;
> > + }
>
> Quite a lot of separate sites in this hunk print 'GetVariable failed'
> or 'SetVariable failed' with no further context - when one trips in CI
> it's impossible to tell which assertion fired without rebuilding with
> prints. Please make each message identify the step (e.g. 'phase 2:
> append SetVariable failed', 'phase 2: post-delete GetVariable did not
> return EFI_NOT_FOUND') so a log line is enough to localise the
> failure.
>
> > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > @@ -3,6 +3,7 @@
> > + * Copyright (c) 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
> > + *
> > * This unit test checks the runtime services for variables after
> > * ExitBootServices():
> > @@ -22,7 +23,13 @@ static const efi_guid_t efi_rt_var_guid = U_BOOT_EFI_RT_VAR_FILE_GUID;
> > + * For EFI variables in non-volatile storage, these tests have to be executed in two phases
>
> Please use 'non-volatile' (hyphenated) consistently in the doc comment
> and in the inline comment a few lines down ('non volatile storage');
> the rest of the file already spells it that way. Same nit for the
> commit message body. The commit message also opens with 'Extend
> runtime variable tests for persistent storage' that just paraphrases
> the subject - please just drop it. 'Previously, EFI selftesting … was
> only supported …' should be present tense per U-Boot conventions ('EFI
> selftesting of runtime variables is currently only supported …').
>
> Regards,
> Simon
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
2026-05-05 14:30 ` Harsimran Singh Tungal
@ 2026-05-07 15:31 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-07 15:31 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana
Hi Harsimran,
On Tue, 5 May 2026 at 08:30, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> On 2026-04-28 12:16 -0600, Simon Glass wrote:
> > Hi Harsimran,
> >
> > On 2026-04-24T17:31:50, Harsimran Singh Tungal
> > <harsimransingh.tungal@arm.com> wrote:
> > > efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
> > >
> > > Route EFI runtime variable APIs through FF-A MM communication
> > >
> > > This patch implements full EFI Runtime Variable Services (GetVariable,
> > > SetVariable, GetNextVariableName, and QueryVariableInfo) using the
> > > FF-A/MM communication backend. Once ExitBootServices() has been invoked,
> > > all variable operations now use the runtime-safe FF-A transport instead
> > > of the boot-time communication paths.
> > >
> > > Key changes:
> > > ============
> > >
> > > - Add runtime-safe variable property handling via FF-A MM SP.
> > > - Add runtime versions of variable access and property operations.
> > > - Replace all standard memory operations with EFI-runtime-safe variants.
> > >
> > > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> > >
> > > lib/charset.c | 2 +-
> > > lib/efi_loader/efi_variable_tee.c | 322 +++++++++++++++++++++++++++++++++++++-
> > > 2 files changed, 318 insertions(+), 6 deletions(-)
> >
> > > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > > @@ -991,6 +1066,92 @@ out:
> > > + /*
> > > + * UEFI > 2.7 needs the attributes set even if the buffer is
> > > + * smaller
> > > + */
> > > + if (attributes) {
> > > + tmp = get_property_int_runtime(variable_name, name_size, vendor,
> > > + &var_property);
> > > + if (tmp != EFI_SUCCESS) {
> > > + ret = tmp;
> > > + return ret;
> > > + }
> > > + *attributes = var_acc->attr;
> > > + if (var_property.property &
> > > + VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
> > > + *attributes |= EFI_VARIABLE_READ_ONLY;
> > > + }
> >
> > get_property_int_runtime() ends up calling setup_mm_hdr() ->
> > get_comm_buf(), and at runtime get_comm_buf() does
> > efi_memset_runtime(ffa_shared_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE)
> > on the same shared buffer that var_acc points into.
> >
> > By the time you read var_acc->attr it has been zeroed, so
> > '*attributes' will only ever come back as 0 (optionally OR'd with
> > EFI_VARIABLE_READ_ONLY). The boot-time path gets away with this
> > because get_property_int() calloc()s a fresh buffer; the runtime path
> > cannot. Please cache var_acc->attr in a local before the call, or move
> > the get_property_int_runtime() call ahead of the SP exchange.
> >
> Agreed, you're right.
>
> `get_property_int_runtime()` reuses the same runtime FF-A shared buffer, so
> the second call can clear the buffer backing `var_acc` before `var_acc->attr`
> is copied out.
>
> For v2, I will cache `var_acc->attr` in a local before calling
> `get_property_int_runtime()` and then used that cached value when updating
> `*attributes`.
>
> Thanks
>
> > > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > > @@ -1228,7 +1477,70 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> > > + ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
> > > + attributes &= EFI_VARIABLE_MASK;
> > > +
> > > + ret = get_property_int_runtime(variable_name, name_size, guid,
> > > + &var_property);
> > > + if (ret != EFI_SUCCESS)
> > > + return ret;
> > > +
> > > + /*
> > > + * Allocate the buffer early, before switching to RW (if needed)
> > > + * so we won't need to account for any failures in reading/setting
> > > + * the properties, if the allocation fails
> > > + */
> > > + comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
> > > + SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
> > > + if (!comm_buf)
> > > + return ret;
> > > +
> > > + if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
> > > + return EFI_WRITE_PROTECTED;
> >
> > The comment is copied from efi_set_variable_int() and no longer
> > matches the code - there is no RW switch in the runtime path (no
> > ro_check argument), and the allocation happens after the property
> > read, the opposite of what the comment claims. Either drop the comment
> > or, better, do the RO check before calling setup_mm_hdr() so the
> > early-return is quicker.
> >
>
> Agreed.
>
> That comment was copied from the boot-time path.
> For v2, I will drop it and move the `VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY`
> check ahead of `setup_mm_hdr()`, so the runtime path returns
> `EFI_WRITE_PROTECTED` before allocating the MM communication buffer.
>
> > > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > > @@ -859,6 +859,38 @@ out:
> > > +static efi_status_t __efi_runtime set_property_int_runtime(const u16 *variable_name,
> > > + efi_uintn_t name_size,
> > > + const efi_guid_t *vendor,
> > > + struct var_check_property *var_property)
> >
> > As mentioned elsewhere, the four new functions
> > (set_property_int_runtime, get_property_int_runtime,
> > efi_get_variable_runtime, efi_get_next_variable_name_runtime) are
> > near-line-for-line copies of their boot-time counterparts with
> > memcpy/guidcpy/memset swapped for the efi_*_runtime helpers and a
> > different mm_communicate(). Since setup_mm_hdr() was made runtime-safe
> > in patch 3, can the boot-time helpers be reused directly (with
> > mm_communicate() picking the right transport based on
> > efi_is_runtime_enabled())? It would also avoid the special-case free()
> > path.
> >
>
> I kept the separate runtime wrappers intentionally so the
> post-ExitBootServices call graph stays explicit and auditable: only
> runtime-safe helpers, no driver-model assumptions, and no boot-time heap
> cleanup semantics.
>
> I also tried to match the existing EFI variable structure: `efi_variable.c`
> (Done by Heinrich Schuchardt) already has separate boot-time and runtime
> service entry points, so I kept the same split here instead of introducing a
> different pattern only for the TEE/FF-A backend.
>
> Apart from these runtime variants, I will collapse the other `_runtime` helpers
> into the common implementations in v2 patchset. `get_mm_comms()`, `mm_communicate()`,
> `ffa_mm_communicate()`, and `ffa_notify_mm_sp()` will handle both boot and runtime,
> with only a small `efi_at_runtime()` branch for the phase-specific parts.
>
> Does this explanation sound reasonable to you?
Yes that makes sense, thanks.
>
> Thanks
>
> > > diff --git a/lib/charset.c b/lib/charset.c
> > > @@ -407,7 +407,7 @@ size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
> > > -size_t u16_strsize(const void *in)
> > > +size_t __efi_runtime u16_strsize(const void *in)
> >
> > This change should really be in its own patch with a one-line note
> > that it's needed by the new runtime callers. It is unrelated to the
> > SetVariable/GetVariable wiring and is easy to lose in this 320-line
> > diff.
> >
>
> For v2, I'll split the `u16_strsize()` `__efi_runtime` annotation into a
> separate small patch with a short note that it is needed by
> the new runtime variable callers. That should keep this patch focused on
> the SetVariable/GetVariable runtime wiring.
>
> > > Key changes:
> > > ============
> >
> > >
> > > - Add runtime-safe variable property handling via FF-A MM SP.
> > > - Add runtime versions of variable access and property operations.
> > > - Replace all standard memory operations with EFI-runtime-safe variants.
> >
> > The'============' underline is more for rST documentation than commit
> > messages - please drop it. The third bullet is also misleading: only
> > the new runtime functions use the runtime-safe variants; the existing
> > boot-time helpers are unchanged. It is generally better to use prose
> > than bullet points in a commit message.
> >
>
> Sure, I will update this in v2.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 06/12] corstone1000: enable bootefi selftest
2026-05-06 12:20 ` Harsimran Singh Tungal
@ 2026-05-07 15:32 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-07 15:32 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana
Hi Harsimran,
On Wed, 6 May 2026 at 06:21, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> On 2026-04-28 12:01 -0600, Simon Glass wrote:
> > Hi Harsimran,
> >
> > On 2026-04-24T17:31:50, Harsimran Singh Tungal
> > <harsimransingh.tungal@arm.com> wrote:
> > > corstone1000: enable bootefi selftest
> > >
> > > Enable UEFI selftest command in Corstone-1000 defconfig
> > >
> > > Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> > > so the board can run the built-in UEFI self-test suite during
> > > development and validation.
> > >
> > > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> > >
> > > configs/corstone1000_defconfig | 3 +++
> > > 1 file changed, 3 insertions(+)
> >
> > > diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> > > @@ -63,6 +65,7 @@ CONFIG_SYSRESET=y
> > > CONFIG_SYSRESET_PSCI=y
> > > CONFIG_TEE=y
> > > CONFIG_OPTEE=y
> > > +# CONFIG_CMD_POWEROFF is not set
> > > CONFIG_USB=y
> >
> > Why is this disabled? It's not mentioned in the commit message and
> > looks unrelated to enabling the bootefi selftest. If it's a stray
> > byproduct of 'make savedefconfig' please drop it; if intentional it
> > should be a separate patch with its own justification.
> >
>
> Thanks, these two lines are intentional rather than stray
> `savedefconfig` fallout.
>
> On Corstone-1000, enabling `CMD_BOOTEFI_SELFTEST` causes
> `CMD_BOOTEFI_HELLO` to default to `y`, and `CMD_POWEROFF` is also
> pulled in on this PSCI-based defconfig. I wanted to enable only the
> selftest command here, without broadening the rest of the board command
> set, so both are kept explicitly disabled.
>
> I can make that explicit in the commit message in v2.
> Does this sound reasonable to you?
Yes that makes sense, thanks.
>
> > > diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
> > > @@ -32,6 +32,8 @@ CONFIG_SYS_PROMPT="corstone1000# "
> > > # CONFIG_CMD_CONSOLE is not set
> > > CONFIG_CMD_FWU_METADATA=y
> > > CONFIG_CMD_BOOTZ=y
> > > +# CONFIG_CMD_BOOTEFI_HELLO is not set
> > > +CONFIG_CMD_BOOTEFI_SELFTEST=y
> >
> > The commit message says only that selftest is being enabled, but
> > you're also explicitly disabling CMD_BOOTEFI_HELLO (which would
> > otherwise default to y once SELFTEST is set). Please mention this, and
> > ideally state the real motivation - that this is needed so patch 7 of
> > the series can run the runtime variable selftest on this board, right?
> >
>
> Thanks, agreed.
>
> The explicit `CMD_BOOTEFI_HELLO=n` is intentional. On this board,
> enabling `CMD_BOOTEFI_SELFTEST` would otherwise make
> `CMD_BOOTEFI_HELLO` default to `y`. The goal here is to enable the
> selftest command so the later runtime-variable selftest patch in this
> series can be exercised on Corstone-1000, without broadening the rest
> of the board command set at the same time.
>
> I'll make that motivation explicit in the commit message in v2.
>
> Regards
> Harsimran Singh Tungal
>
> > > Enable UEFI selftest command in Corstone-1000 defconfig
> >
> > >
> > > Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
> > > so the board can run the built-in UEFI self-test suite during
> > > development and validation.
> >
> > The first paragraph just restates the subject. Please drop it and keep
> > the second paragraph, which actually explains the change. Referencing
> > the runtime-variable selftest added later in the series would also
> > help, since that is the real reason for enabling it now.
Rgards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage
2026-05-06 15:14 ` Harsimran Singh Tungal
@ 2026-05-07 15:32 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-07 15:32 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana
Hi Harsimran,
On Wed, 6 May 2026 at 09:14, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> On 2026-04-28 12:04 -0600, Simon Glass wrote:
> > Hi Harsimran,
> >
> > On 2026-04-24T17:31:50, Harsimran Singh Tungal
> > <harsimransingh.tungal@arm.com> wrote:
> > > efi: selftest: add runtime variable tests with non-volatile storage
> > >
> > > Extend runtime variable tests for persistent storage
> > >
> > > Previously, EFI selftesting of runtime variables was only supported
> > > under CONFIG_EFI_RT_VOLATILE_STORE, which uses VarToFile to simulate
> > > non-volatile variable storage. This commit adds new test cases that
> > > exercise runtime variable operations for persistent storage.
> > >
> > > Features tested:
> > > - Creation of runtime-accessible variables (set)
> > > - Retrieval of runtime variables (get)
> > > - Deletion using SetVariable() with size = 0
> > > - Append operation using EFI_VARIABLE_APPEND_WRITE
> > >
> > > This improves EFI compliance validation for non-volatile runtime storage
> > > scenarios and ensures proper attribute enforcement and variable
> > > management.
> > >
> > > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> > >
> > > lib/efi_selftest/efi_selftest_variables_runtime.c | 106 +++++++++++++++++++++-
> > > 1 file changed, 104 insertions(+), 2 deletions(-)
> >
> > > diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
> > > @@ -39,6 +46,80 @@ static int execute(void)
> > > + /* Compare the value of EFI variable if it already exists in non volatile storage */
> > > + if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
> > > + len = sizeof(v) / 2;
> > > + ret = st_runtime->get_variable(u'efi_st_var0', &guid_vendor0,
> > > + &attr, &len, data);
> > > + if (ret == EFI_SUCCESS) {
> >
> > The two-phase split worries me. As written, phase 1 creates a
> > non-volatile variable and immediately returns EFI_ST_SUCCESS, so a
> > single 'bootefi selftest' run reports a green test even though none of
> > the new assertions (append, delete, re-get) actually ran. It also
> > leaves 'efi_st_var0' behind in NV storage if the user never reboots
> > (or if phase 2 fails on an early assertion before the final delete).
> > Could you split this into two distinct EFI_UNIT_TEST entries - say
> > 'variables at runtime (setup)' and 'variables at runtime (verify)'.
> > Then the user (and CI) explicitly select each phase, and the
> > persistent state across the two is part of the contract rather than a
> > hidden side-effect. At minimum, phase 1 needs to print a clear 'test
> > incomplete, please reboot and rerun' rather than EFI_ST_SUCCESS.
> >
>
> Hi Simon, Heinrich,
>
> I would like to confirm the design direction for this selftest change before I send v2.
>
> The proposal is:
>
> - Keep the existing automatic `variables at runtime` test for `CONFIG_EFI_RT_VOLATILE_STORE=y`, so the volatile-store runtime coverage stays in the current single-run form.
>
> - For the non-volatile case, replace the previous implicit two-phase flow with two explicit on-request tests:
> `variables at runtime setup`
> EFI_UNIT_TEST(variables_run_setup) = {
> .name = "variables at runtime setup",
> .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
> .setup = setup,
> .execute = execute_setup,
> .on_request = true,
> };
>
> `variables at runtime verify`
> EFI_UNIT_TEST(variables_run_verify) = {
> .name = "variables at runtime verify",
> .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
> .setup = setup,
> .execute = execute_verify,
> .on_request = true,
> };
>
> - `execute_setup` would:
> run the runtime `QueryVariableInfo()` checks,
> exercise create/delete of a runtime variable,
> create `efi_st_var0` in non-volatile storage with the first half of the payload,
> print that the system should be rebooted and `variables at runtime verify` should be run next.
>
> - `execute_verify` would:
> validate the prepared variable from `setup`,
> append the remaining payload,
> validate the full contents,
> delete the variable,
> confirm that it is gone.
>
> - If `setup` finds an existing `efi_st_var0` already containing the expected half-payload, it would report that setup is already complete and ask the user to run `verify`.
> If the existing variable does not match, it would delete the stale variable and recreate the expected setup state.
>
> - The failure logs would also be made step-specific, so local runs and CI logs show exactly which runtime operation fails, and `verify` would print an explicit success line.
>
> The intention is to make the reboot-dependent non-volatile flow explicit, while keeping the current volatile-store runtime test structure unchanged.
>
> Does this design look reasonable to both of you for v2?
That seems reasonable to me, yes. This is a little tricky :-)
I have talked to Heinrich about moving these tests to the normal ut
framework, but I have not tried to actually do it yet. In any case it
should not affect your work here.
[..]
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 02/12] arm-ffa: add FF-A bus runtime support
2026-04-28 18:10 ` Simon Glass
2026-05-04 20:25 ` Harsimran Singh Tungal
@ 2026-05-08 10:18 ` Abdellatif El Khlifi
1 sibling, 0 replies; 77+ messages in thread
From: Abdellatif El Khlifi @ 2026-05-08 10:18 UTC (permalink / raw)
To: Simon Glass, harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana
Hi Harsimran,
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > arm-ffa: add FF-A bus runtime support
> >
> > Enable FF-A runtime transport for EFI services
> >
> > This patch introduces the FF-A runtime infrastructure that enables
> > U-Boot to use the Arm Firmware Framework for Arm A-profile (FF-A)
> > transport layer after ExitBootServices().
> > The runtime transport provides persistent, runtime-safe
> > implementations of key FF-A functions used by EFI runtime services.
> >
> > Summary of key changes:
> > -----------------------
> > - Add drivers/firmware/arm-ffa/arm-ffa-runtime.c implementing FF-A
> > runtime operations.
> > - Introduce include/arm_ffa_runtime.h exporting FF-A runtime
> > functions and data structures.
> > - Move FF-A error mapping into runtime context.
> > - Introduce invoke_ffa_fn_runtime() as runtime safe SMC wrapper.
> > - Add runtime SMC wrapper for sandbox emulation.
> > - Add ARM_FFA_RT_MODE Kconfig to enable runtime support.
> > [...]
> >
> > drivers/firmware/arm-ffa/Kconfig | 11 ++
> > drivers/firmware/arm-ffa/Makefile | 4 +-
> > drivers/firmware/arm-ffa/arm-ffa-runtime.c | 287 +++++++++++++++++++++++++++++
> > drivers/firmware/arm-ffa/arm-ffa-uclass.c | 111 ++---------
> > drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
> > drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 ++
> > include/arm_ffa.h | 16 +-
> > include/arm_ffa_priv.h | 24 ++-
> > include/arm_ffa_runtime.h | 183 ++++++++++++++++++
> > test/dm/ffa.c | 6 +-
> > 10 files changed, 551 insertions(+), 119 deletions(-)
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > + if (priv)
> > + ffa_copy_runtime_priv(&priv->rt);
> > + else
> > + log_err("FF-A: Entering RT mode without FF-A runtime data information\n");
> > +
> > + ffa_enable_runtime_context();
>
> This enables the runtime context unconditionally, even after logging
> the priv data is missing. The runtime then comes up with id == 0 and
> fwk_version == 0 and any later FF-A call silently uses bogus values.
> Please return after the log_err() so ffa_get_status_runtime_context()
> keeps returning false on the failure path.
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > +#include <arm_ffa_runtime.h>
> > +#include <arm_ffa_priv.h>
> > +#include <log.h>
> > +#include <asm/global_data.h>
> > +#include <linux/errno.h>
> > +#include <linux/types.h>
> > +
> > +DECLARE_GLOBAL_DATA_PTR;
>
> gd doesn't seem to be referenced in this file?
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > + * after the FF-A bus device has successfully probed and U-Boot’s FF-A
>
> This (and the same line in arm_ffa_runtime.h) should use a normal '
> instead of the UTF-8 right single quotation mark.
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > +#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
> > +static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
> > + void *context)
>
> CONFIG_IS_ENABLED() is only meaningful for symbols with an SPL twin.
> ARM_FFA_RT_MODE has none, and the uclass side already uses
> IS_ENABLED(CONFIG_ARM_FFA_RT_MODE) - please use IS_ENABLED() here and
> in arm_ffa_runtime.h.
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> > @@ -0,0 +1,287 @@
> > + if (is_smc64) {
> > + req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
> > + } else {
> > + req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
> > + }
>
> Single-statement bodies should not be braced. Please run patman or
> checkpatch.pl on your patches. Also, the two efi_memset_runtime()
> calls below clear fresh stack variables. Please initialise them at
> declaration ('ffa_value_t ffa_args_rt = {}') and drop the explicit
> memset()s; the compiler's zero-init is just as runtime-safe and is
> what the boot path already does.
>
> Also could you run checkpatch / patman over your patches for v2?
>
> > diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
> > @@ -1047,6 +961,11 @@ static int ffa_do_probe(struct udevice *dev)
> > + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> > + ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
> > + if (ret)
> > + return ret;
> > + }
>
> If event creation fails here, the RX/TX buffers mapped above and the
> partition cache are leaked, i,e. the existing failure path for
> ffa_cache_partitions_info() at least calls
> ffa_unmap_rxtx_buffers_hdlr(). Please follow the same pattern, or move
> event registration before resource allocation.
>
> > diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
> > @@ -41,3 +44,11 @@ config ARM_FFA_TRANSPORT
> > +config ARM_FFA_RT_MODE
> > + bool "Enable FF-A runtime support"
> > + depends on ARM_FFA_TRANSPORT && EFI_LOADER
> > + default y
>
> Just to check, does every existing FF-A user want this on? 'default y'
> silently enables a new transport path (and the ExitBootServices
> callback) for everyone with ARM_FFA_TRANSPORT && EFI_LOADER. I'd
> suggest defaulting, or at minimum 'default y if CORSTONE1000' or
> similar, until other boards have opted in.
>
> > diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
> > @@ -212,9 +227,8 @@ struct ffa_partitions {
> > - u32 fwk_version;
> > + struct ffa_priv_runtime rt;
> > struct udevice *emul;
> > - u16 id;
>
> Just to clarify the model: 'struct ffa_priv' now embeds 'struct
> ffa_priv_runtime rt' at boot, and at ExitBootServices we copy the
> whole sub-struct (including 'use_ffa_runtime', always false here) into
> the resident 'ffa_priv_rt', then immediately overwrite use_ffa_runtime
> via ffa_enable_runtime_context(). Layering would be clearer if
> 'use_ffa_runtime' lived only on the resident copy and ffa_priv_runtime
> carried just the data shipped across the boundary (fwk_version, id).
>
> Regards,
> Simon
Simon’s comments make sense to me. Please address them.
Aside from that, everything looks good in this commit.
Regards,
Abdellatif
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-04-27 16:21 ` Ilias Apalodimas
2026-05-04 20:40 ` Harsimran Singh Tungal
@ 2026-05-08 10:23 ` Abdellatif El Khlifi
1 sibling, 0 replies; 77+ messages in thread
From: Abdellatif El Khlifi @ 2026-05-08 10:23 UTC (permalink / raw)
To: Ilias Apalodimas, harsimransingh.tungal
Cc: u-boot, trini, xypron.glpk, hugues.kambampiana, sjg
Hi Harsimran,
> On Fri, 24 Apr 2026 at 20:32, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> >
> > Enable MM variable services over FF-A after ExitBootServices
> >
> > This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
> > communication with the secure world during EFI runtime. It enables EFI
> > runtime variable access and MM communication using FF-A transport when
> > ExitBootServices() has already been called.
> >
> > Key changes:
> > ------------
> > - Introduce runtime-safe implementations for MM communication,
> > notification, and variable access using FF-A driver.
> > - Introduce communication-buffer helper (get_comm_buf()) that switches
> > between dynamic allocation (boot phase) and the fixed FF-A shared
> > buffer (runtime phase).
> > - Mark persistent data and code with __efi_runtime and
> > __efi_runtime_data attributes.
> > - Use direct physical address mapping for shared buffers since
> > U-Boot operates with 1:1 physical-to-virtual mapping.
> > - Only per-buffer cache maintenance is performed at runtime,
> > as whole D-cache invalidation would violate the OS coherency model
> > after ExitBootServices().
> > - Add runtime-phase tracking (efi_runtime_enabled).
>
> Why is this needed? For the memory allocations?
>
> [...]
>
> > *
> > * Authors:
> > * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > @@ -14,6 +14,7 @@
> >
> > #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> > #include <arm_ffa.h>
> > +#include <arm_ffa_runtime.h>
> > #endif
> > #include <cpu_func.h>
> > #include <dm.h>
> > @@ -34,20 +35,47 @@
> > #define MM_DENIED (-3)
> > #define MM_NO_MEMORY (-5)
> >
> > +static const int __efi_runtime_rodata mm_sp_errmap[] = {
> > + [-MM_NOT_SUPPORTED] = -EINVAL,
> > + [-MM_INVALID_PARAMETER] = -EPERM,
> > + [-MM_DENIED] = -EACCES,
> > + [-MM_NO_MEMORY] = -EBUSY,
> > +};
> > +
>
> These are already defined above and used in ffa_notify_mm_sp(). If you
> plan to convert them, do it for the entire file.
>
> [...]
>
> > +/**
> > + * efi_is_runtime_enabled() - Indicate whether the system is in the UEFI runtime phase
> > + *
> > + * This helper returns whether the firmware has transitioned into the
> > + * UEFI runtime phase, meaning that ExitBootServices() has been invoked.
> > + *
> > + * Return:
> > + * true - The system is operating in UEFI runtime mode.
> > + * false - The system is still in the boot services phase.
> > + */
> > +static bool __efi_runtime efi_is_runtime_enabled(void)
> > +{
> > + return efi_runtime_enabled;
> > +}
>
> Enabled is a bit confusing. efi_at_runtime() should be enough. The
> efi_tcg.c code calls this 'ebs_called'
>
> > +
> > /**
> > * get_connection() - Retrieve OP-TEE session for a specific UUID.
> > *
> > @@ -169,6 +197,28 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
> > }
> >
> > #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> > +/**
> > + * ffa_map_sp_event_runtime() - Map MM SP response to errno (runtime-safe)
> > + * @sp_event_ret: MM SP return code from ffa_notify_mm_sp_runtime()
> > + *
> > + * Convert the MM SP return code into a standard U-Boot errno. This helper
> > + * is marked __efi_runtime to ensure it is safe to call after
> > + * ExitBootServices().
> > + *
> > + * Return: 0 on success, negative errno on failure
> > + */
> > +static __efi_runtime int ffa_map_sp_event_runtime(int sp_event_ret)
> > +{
> > + int idx = -sp_event_ret;
> > +
> > + if (sp_event_ret == MM_SUCCESS)
> > + return 0;
> > + if (idx > 0 && idx < (int)ARRAY_SIZE(mm_sp_errmap) &&
> > + mm_sp_errmap[idx])
> > + return mm_sp_errmap[idx];
> > + return -EACCES;
> > +}
> > +
> > /**
> > * ffa_notify_mm_sp() - Announce there is data in the shared buffer
> > *
> > @@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
> > return ret;
> > }
> >
> > +/**
> > + * ffa_notify_mm_sp_runtime() - Runtime implementation of
> > + * ffa_notify_mm_sp()
> > + *
> > + * Notify the MM partition in the trusted world that
> > + * data is available in the shared buffer.
> > + * This is a blocking call during which trusted world has exclusive access
> > + * to the MM shared buffer.
> > + *
> > + * Return:
> > + *
> > + * 0 on success
> > + */
> > +static int __efi_runtime ffa_notify_mm_sp_runtime(void)
> > +{
> > + struct ffa_send_direct_data msg = {0};
> > + int ret;
> > + int sp_event_ret;
> > +
> > + msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
> > +
> > + ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
> > + if (ret)
> > + return ret;
> > +
> > + ret = ffa_map_sp_event_runtime(sp_event_ret);
> > + return ret;
> > +}
> > +
> > /**
> > * ffa_discover_mm_sp_id() - Query the MM partition ID
> > *
> > @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > return efi_ret;
> > }
> >
> > +/**
> > + * ffa_mm_communicate_runtime() - Runtime implementation of ffa_mm_communicate()
> > + * @comm_buf: locally allocated communication buffer used for rx/tx
> > + * @comm_buf_size: communication buffer size
> > + *
> > + * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
> > + * that there is data to read from the shared buffer.
> > + * Communication with the MM SP is performed using FF-A transport.
> > + * On the event, MM SP can read the data from the buffer and
> > + * update the MM shared buffer with response data.
> > + * The response data is copied back to the communication buffer.
> > + *
> > + * Return:
> > + *
> > + * EFI status code
> > + */
> > +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> > + ulong comm_buf_size)
> > +{
>
> There's a lot of code duplication between the boottime and runtime
> variants, but I don;t see why we need it. Can't we have a single
> function that works both boottime and runtime?
Ilias suggestion makes sense to me. Please address that.
Regards,
Abdellatif
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path
2026-04-28 18:14 ` Simon Glass
@ 2026-05-08 10:34 ` Abdellatif El Khlifi
2026-05-14 15:11 ` Harsimran Singh Tungal
1 sibling, 0 replies; 77+ messages in thread
From: Abdellatif El Khlifi @ 2026-05-08 10:34 UTC (permalink / raw)
To: Simon Glass, harsimransingh.tungal
Cc: hugues.kambampiana, ilias.apalodimas, trini, u-boot, xypron.glpk
Hi Harsimran,
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > efi_loader: align FF-A cache maintenance with runtime path
> >
> > Match boot-time FF-A cache handling to runtime behavior
> >
> > The boot-time FF-A MM communication path used invalidate_dcache_all()
> > after copying the message into the shared buffer. This differs from the
> > runtime path, which performs range-based maintenance to avoid global cache
> > operations.
> >
> > Update ffa_mm_communicate() to use the same pattern as the runtime helper:
> > clean the shared buffer range before the SMC and invalidate the same range
> > after the response. This keeps boot-time and runtime behavior consistent
> > and avoids whole-cache invalidation.
> >
> > Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > lib/efi_loader/efi_variable_tee.c | 33 ++++++++++++++++++++++++++-------
> > 1 file changed, 26 insertions(+), 7 deletions(-)
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > memcpy(virt_shared_buf, comm_buf, tx_data_size);
> >
> > /*
> > - * The secure world might have cache disabled for
> > - * the device region used for shared buffer (which is the case for Optee).
> > - * In this case, the secure world reads the data from DRAM.
> > - * Let's flush the cache so the DRAM is updated with the latest data.
> > + * Shared buffer cache maintenance for FF-A / OP-TEE communication:
> > + *
> > + * NS -> S (request path):
> > + *
> > + * The non-secure side populates the shared buffer. If the buffer is cached
> > + * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
> > + * visible in DDR. Since the secure world typically reads the shared buffer
> > + * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
> > + * must clean the corresponding cache lines to the Point of Coherency (PoC)
> > + * before entering secure world.
> > + *
> > + * S -> NS (response path):
> > + *
> > + * The secure world may update the same shared buffer in DDR. After returning
> > + * to non-secure, any cached copies of that region in NS may be stale. We
> > + * therefore invalidate the shared buffer range after the FF-A call to drop
> > + * those lines and force subsequent reads to fetch the latest data from DDR.
> > */
>
> This 20-line comment is now duplicated verbatim with the one in
> ffa_mm_communicate_runtime() introduced earlier in the series. Please
> factor the clean-before / invalidate-after sequence into a small
> helper (e.g. ffa_mm_buf_pre_call() / ffa_mm_buf_post_call()) so the
> commentary lives in one place and the two paths cannot drift. The
> runtime helper would add the extra 'no whole-cache invalidation after
> ExitBootServices()' note at the call site.
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > -#ifdef CONFIG_ARM64
> > - invalidate_dcache_all();
> > -#endif
> > + if (IS_ENABLED(CONFIG_ARM64))
> > + flush_dcache_range((unsigned long)virt_shared_buf,
> > + (unsigned long)virt_shared_buf +
> > + CONFIG_FFA_SHARED_MM_BUF_SIZE);
>
> Just to check - flush_dcache_range() and invalidate_dcache_range() on
> arm64 require start and end to be cache-line aligned, otherwise the
> arch code warns and falls back to clean+invalidate of the partial
> lines. CONFIG_FFA_SHARED_MM_BUF_ADDR and _SIZE need to be at least
> CONFIG_SYS_CACHELINE_SIZE aligned - is that documented or enforced
> anywhere? You could use BUILD_BUG_ON() near the call, perhaps?
Let's make sure the CONFIG_FFA_SHARED_MM_BUF_ADDR and _SIZE
are CONFIG_SYS_CACHELINE_SIZE aligned and document that in the Kconfig file.
It is also a good idea to add the BUILD_BUG_ON() check.
Regards,
Abdellatif
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables
2026-04-24 17:31 ` [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
2026-04-28 18:08 ` Simon Glass
@ 2026-05-08 10:40 ` Abdellatif El Khlifi
1 sibling, 0 replies; 77+ messages in thread
From: Abdellatif El Khlifi @ 2026-05-08 10:40 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: hugues.kambampiana, ilias.apalodimas, sjg, trini, u-boot,
xypron.glpk
Hi Harsimran,
> Document how EFI runtime variables use FF-A MM communication
>
> Describe the FF-A runtime layer on arm64 and how EFI variable
> runtime services use the FF-A transport and shared MM buffer.
> Also clarify armffa command scope and link to the FF-A doc.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> ---
> doc/arch/arm64.ffa.rst | 92 +++++++++++++++++++++++++++++++++++++---
> doc/usage/cmd/armffa.rst | 11 +++++
> 2 files changed, 96 insertions(+), 7 deletions(-)
>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Regards,
Abdellatif
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH v2 00/11] arm64: FF-A runtime transport for EFI variables
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
` (13 preceding siblings ...)
2026-04-28 18:16 ` [00/12] " Simon Glass
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 01/11] efi_loader: add runtime memset helper Harsimran Singh Tungal
` (10 more replies)
14 siblings, 11 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Hi all,
This series adds FF-A runtime transport support so EFI variable runtime
services can communicate with the secure world after ExitBootServices().
It also extends tests, docs, and board configs to validate the runtime
path and keep boot‑time behavior aligned with the runtime flow.
Changes in this series:
- Add EFI runtime-safe memset helper and FF-A runtime transport support.
- Implement FF-A runtime communication in the EFI variable TEE backend.
- Enable runtime variable operations and move helpers to avoid conflicts.
- Add sandbox runtime transport tests and metadata reuse.
- Extend EFI selftests for runtime variables and bootefi selftest config.
- Document the FF-A runtime transport and selftest behavior.
Changes in v2:
Address Simon Glass's review comments:
- Fix `efi_memset_runtime()` style, declaration, and byte cast
- Tighten the FF-A runtime context failure path, clean up `arm-ffa-runtime.c`
style issues, and move ExitBootServices event registration earlier in probe
- Add shared-buffer bounds/alignment checks, and tightening comments/kernel-doc
- Document the FF-A shared buffer cacheline-alignment requirement and add
BUILD_BUG_ON() checks for the address
- Cache attributes before the shared buffer is reused, moving the read-only
check earlier, and split the `u16_strsize()` related change in separate patch
- Reword commit messages for the runtime helper relocation
- Rework the non-volatile runtime variable selftest into setup/verify phases
- Extend the sandbox FF-A runtime tests with no-context coverage,
runtime-context reset, and separate errno-mapping coverage
- Refresh the FF-A runtime transport and bootefi documentation
- Drop patch 12 in v1, as ffa_mm_communicate handles both runtime and
boottime capabilities in v2
- Squash patch 8 and patch 9 from v1
Address Ilias Apalodimas's review comments:
- Reuse common MM SP error mapping for boot and runtime paths
- Rename runtime-phase tracking to reflect the ExitBootServices transition
- Collapse duplicated boot-time and runtime MM communication helpers into common
implementations
- Keep the arm64 cache-maintenance path runtime-safe.
- Move FF-A shared-buffer runtime memory-map registration to the end of
variable-service initialization
Link to v1: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/
Harsimran Singh Tungal (11):
efi_loader: add runtime memset helper
arm-ffa: add FF-A bus runtime support
efi_loader: add FF-A runtime support in EFI variable TEE driver
efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A
transport
charset: mark u16_strsize() as __efi_runtime
efi_loader: move runtime variable read helpers to efi_variable.c
corstone1000: enable bootefi selftest
efi: selftest: add runtime variable tests with non-volatile storage
test: dm: add sandbox FF-A runtime transport tests
doc: arm64: document FF-A runtime path for EFI variables
doc: bootefi: note two-phase runtime variables selftest
arch/arm/cpu/armv8/cache.S | 8 +
arch/arm/cpu/armv8/cache_v8.c | 13 +-
arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +-
configs/corstone1000_defconfig | 3 +
doc/arch/arm64.ffa.rst | 86 ++-
doc/usage/cmd/armffa.rst | 11 +
doc/usage/cmd/bootefi.rst | 27 +
drivers/firmware/arm-ffa/Kconfig | 11 +
drivers/firmware/arm-ffa/Makefile | 4 +-
drivers/firmware/arm-ffa/arm-ffa-runtime.c | 295 ++++++++
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 113 +--
drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 48 +-
include/arm_ffa.h | 16 +-
include/arm_ffa_priv.h | 22 +-
include/arm_ffa_runtime.h | 191 +++++
include/efi_loader.h | 3 +
lib/charset.c | 2 +-
lib/efi_loader/Kconfig | 4 +
lib/efi_loader/efi_runtime.c | 20 +
lib/efi_loader/efi_var_common.c | 24 -
lib/efi_loader/efi_variable.c | 24 +
lib/efi_loader/efi_variable_tee.c | 650 +++++++++++++---
.../efi_selftest_variables_runtime.c | 713 ++++++++++++------
test/dm/Makefile | 3 +-
test/dm/ffa.c | 6 +-
test/dm/ffa_runtime.c | 129 ++++
27 files changed, 1962 insertions(+), 496 deletions(-)
create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
create mode 100644 include/arm_ffa_runtime.h
create mode 100644 test/dm/ffa_runtime.c
--
2.34.1
^ permalink raw reply [flat|nested] 77+ messages in thread
* [PATCH v2 01/11] efi_loader: add runtime memset helper
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:14 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 02/11] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
` (9 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Add efi_memset_runtime() for EFI runtime paths
This keeps buffer initialization in runtime-resident code after
ExitBootServices() and avoids relying on non-runtime helpers.
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Fix the `efi_memset_runtime()` comment and kernel-doc style
- Drop `__efi_runtime` from the header prototype
- Align the definition signature with nearby helpers
- Cast the stored byte to `u8`
include/efi_loader.h | 3 +++
lib/efi_loader/efi_runtime.c | 20 ++++++++++++++++++++
2 files changed, 23 insertions(+)
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3a4d502631c..9dfea1fd7de 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -1151,6 +1151,9 @@ void efi_memcpy_runtime(void *dest, const void *src, size_t n);
/* runtime implementation of memcmp() */
int efi_memcmp_runtime(const void *s1, const void *s2, size_t n);
+/* runtime implementation of memset() */
+void *efi_memset_runtime(void *dest, int c, size_t n);
+
/* commonly used helper functions */
u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
unsigned int index);
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 73d4097464c..c0182931c42 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -233,6 +233,26 @@ int __efi_runtime efi_memcmp_runtime(const void *s1, const void *s2, size_t n)
return 0;
}
+/**
+ * efi_memset_runtime() - fill memory area
+ *
+ * At runtime memset() is not available.
+ *
+ * @dest: destination buffer
+ * @c: byte value used to fill destination buffer
+ * @n: number of bytes to set
+ * Return: pointer to destination buffer
+ */
+__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
+{
+ u8 *d = dest;
+
+ for (; n; --n)
+ *d++ = (u8)c;
+
+ return dest;
+}
+
/**
* efi_update_table_header_crc32() - Update crc32 in table header
*
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 02/11] arm-ffa: add FF-A bus runtime support
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 01/11] efi_loader: add runtime memset helper Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:25 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
` (8 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Enable FF-A runtime transport for EFI services
Add the FF-A runtime infrastructure needed after ExitBootServices() so
EFI runtime services can continue to use the FF-A transport layer.
Introduce `drivers/firmware/arm-ffa/arm-ffa-runtime.c` and
`include/arm_ffa_runtime.h` with runtime-resident FF-A helpers for
direct messaging, SMC invocation, and error translation. Add the
sandbox runtime SMC wrapper, the `ARM_FFA_RT_MODE` Kconfig option, and
the ExitBootServices hook that copies the required FF-A runtime data
into resident storage before enabling the runtime context.
Tag the runtime code and data with `__efi_runtime` and
`__efi_runtime_data` so they remain available after
ExitBootServices().
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
----
Changelog:
===============
v2:
Simon:
- Leave runtime mode disabled if private data is missing
and update the log message
- Remove unused global-data plumbing
- Switch to `IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)`
- Fix style issues
- Register the ExitBootServices event earlier in probe
- Keep the runtime-enabled flag separate from copied boot time data
drivers/firmware/arm-ffa/Kconfig | 11 +
drivers/firmware/arm-ffa/Makefile | 4 +-
drivers/firmware/arm-ffa/arm-ffa-runtime.c | 295 +++++++++++++++++++++
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 113 ++------
drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 +
include/arm_ffa.h | 16 +-
include/arm_ffa_priv.h | 22 +-
include/arm_ffa_runtime.h | 191 +++++++++++++
test/dm/ffa.c | 6 +-
10 files changed, 566 insertions(+), 120 deletions(-)
create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
create mode 100644 include/arm_ffa_runtime.h
diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
index 3706a889305..7aaf25fdb58 100644
--- a/drivers/firmware/arm-ffa/Kconfig
+++ b/drivers/firmware/arm-ffa/Kconfig
@@ -18,6 +18,9 @@ config ARM_FFA_TRANSPORT
The FF-A support in U-Boot is based on FF-A specification v1.0 and uses SMC32
calling convention.
+ The FF-A bus also provides a runtime layer to keep a minimal set of FF-A
+ operations available after ExitBootServices().
+
FF-A specification:
https://developer.arm.com/documentation/den0077/a/?lang=en
@@ -41,3 +44,11 @@ config ARM_FFA_TRANSPORT
Secure World (sandbox_ffa.c).
For more details about the FF-A support, please refer to doc/arch/arm64.ffa.rst
+
+config ARM_FFA_RT_MODE
+ bool "Enable FF-A runtime support"
+ depends on ARM_FFA_TRANSPORT && EFI_LOADER
+ default y
+ help
+ Enable the FF-A runtime layer, keeping a minimal set of FF-A
+ operations available after ExitBootServices().
diff --git a/drivers/firmware/arm-ffa/Makefile b/drivers/firmware/arm-ffa/Makefile
index 318123a7f42..9deb59ba640 100644
--- a/drivers/firmware/arm-ffa/Makefile
+++ b/drivers/firmware/arm-ffa/Makefile
@@ -1,12 +1,12 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+# Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
#
# Authors:
# Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
# build the generic FF-A methods
-obj-y += arm-ffa-uclass.o
+obj-y += arm-ffa-uclass.o arm-ffa-runtime.o
ifeq ($(CONFIG_SANDBOX),y)
# build the FF-A sandbox emulator and driver
obj-y += ffa-emul-uclass.o sandbox_ffa.o
diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
new file mode 100644
index 00000000000..4261e8ddf24
--- /dev/null
+++ b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
@@ -0,0 +1,295 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#include <arm_ffa_runtime.h>
+#include <arm_ffa_priv.h>
+#include <log.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+/* Error mapping declarations */
+
+int __ffa_runtime_data ffa_to_std_errmap[MAX_NUMBER_FFA_ERR] = {
+ [NOT_SUPPORTED] = -EOPNOTSUPP,
+ [INVALID_PARAMETERS] = -EINVAL,
+ [NO_MEMORY] = -ENOMEM,
+ [BUSY] = -EBUSY,
+ [INTERRUPTED] = -EINTR,
+ [DENIED] = -EACCES,
+ [RETRY] = -EAGAIN,
+ [ABORTED] = -ECANCELED,
+};
+
+static __ffa_runtime_data struct ffa_priv_runtime ffa_priv_rt = {0};
+static __ffa_runtime_data bool ffa_runtime_enabled;
+
+/* Arm FF-A driver runtime operations */
+static const __ffa_runtime_data struct ffa_bus_ops_runtime ffa_ops_rt = {
+ .sync_send_receive = ffa_msg_send_direct_req_hdlr_runtime,
+};
+
+#define ffa_get_ops_runtime() (&ffa_ops_rt)
+#define ffa_get_priv_runtime() (&ffa_priv_rt)
+
+#if IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
+ void *context)
+{
+ struct ffa_priv *priv = context;
+
+ if (priv) {
+ ffa_copy_runtime_priv(&priv->rt);
+ } else {
+ log_err("FF-A: runtime data missing, keeping RT mode disabled\n");
+ return;
+ }
+
+ ffa_enable_runtime_context();
+}
+
+/**
+ * ffa_setup_efi_exit_boot_services_event() - register ExitBootServices event
+ * @priv: pointer to the FF-A private data
+ *
+ * Register an EFI event that enables the FF-A runtime context when
+ * ExitBootServices() is invoked.
+ *
+ * Return: 0 on success, -EPERM on failure to create the event.
+ */
+int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv)
+{
+ efi_status_t efi_ret;
+ struct efi_event *evt = NULL;
+
+ efi_ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
+ ffa_rt_exit_boot_services_notify, priv,
+ &efi_guid_event_group_exit_boot_services,
+ &evt);
+ if (efi_ret != EFI_SUCCESS) {
+ log_err("FF-A: cannot install ExitBootServices event %p, err (%lu)\n",
+ evt, efi_ret);
+ return -EPERM;
+ }
+
+ return 0;
+}
+#endif
+
+/**
+ * ffa_copy_runtime_priv() - copy runtime data into resident storage
+ * @priv: pointer to the runtime private data
+ *
+ * Copy boot-time runtime data into the resident runtime storage to be used
+ * after ExitBootServices().
+ */
+void ffa_copy_runtime_priv(const struct ffa_priv_runtime *priv)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ if (priv)
+ *priv_rt = *priv;
+}
+
+/**
+ * ffa_enable_runtime_context() - Enable FF-A runtime context
+ *
+ * This function marks the FF-A runtime environment as ready for use by
+ * EFI runtime services. It is called when ExitBootServices() is invoked,
+ * after the FF-A bus device has successfully probed and U-Boot's FF-A
+ * endpoint ID has been discovered and stored in the runtime private data
+ * structure.
+ *
+ * The FF-A runtime flag allows the EFI runtime layer to verify that the
+ * FF-A transport was initialized during the boot phase and that all
+ * runtime-safe FF-A operations may now be used after ExitBootServices().
+ *
+ */
+void ffa_enable_runtime_context(void)
+{
+ ffa_runtime_enabled = true;
+}
+
+/**
+ * ffa_reset_runtime_context() - Reset FF-A runtime resident state
+ *
+ * Clear the resident runtime flag and private data. This is used by the
+ * FF-A unit tests to avoid leaking runtime state across test cases.
+ */
+void ffa_reset_runtime_context(void)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ *priv_rt = (struct ffa_priv_runtime){0};
+ ffa_runtime_enabled = false;
+}
+
+/**
+ * ffa_get_status_runtime_context() - Query FF-A runtime readiness
+ *
+ * This helper returns whether the FF-A runtime environment has been
+ * enabled during the boot phase. Runtime FF-A operations must check this
+ * flag before attempting any FF-A access, as the U-Boot driver model
+ * (DM/uclass) is no longer available after ExitBootServices().
+ *
+ * The runtime context becomes enabled when ffa_enable_runtime_context()
+ * is called, typically after the FF-A bus device has probed and the
+ * endpoint ID has been discovered and stored in the runtime private
+ * data structure.
+ *
+ * Return: true if FF-A runtime support is ready, false otherwise.
+ */
+bool __ffa_runtime ffa_get_status_runtime_context(void)
+{
+ return ffa_runtime_enabled;
+}
+
+/**
+ * ffa_to_std_errno() - convert FF-A error code to standard error code
+ * @ffa_errno: Error code returned by the FF-A ABI
+ *
+ * Map the given FF-A error code as specified
+ * by the spec to a u-boot standard error code.
+ *
+ * Return: Standard U-Boot errno for known FF-A errors, or -EINVAL otherwise.
+ */
+int __ffa_runtime ffa_to_std_errno(int ffa_errno)
+{
+ int err_idx = -ffa_errno;
+
+ /* Map the FF-A error code to the standard u-boot error code */
+ if (err_idx > 0 && err_idx < MAX_NUMBER_FFA_ERR)
+ return ffa_to_std_errmap[err_idx];
+ return -EINVAL;
+}
+
+/**
+ * ffa_invoke_msg_send_direct_req() - Invokes FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * @endpoint_id: u-boot endpoint id
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
+ * The response from the secure partition is handled by reading the
+ * FFA_MSG_SEND_DIRECT_RESP arguments.
+ *
+ * The maximum size of the data that can be exchanged is 40 bytes which is
+ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
+ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int __ffa_runtime ffa_invoke_msg_send_direct_req(u16 endpoint_id, u16 dst_part_id,
+ struct ffa_send_direct_data *msg, bool is_smc64)
+{
+ int ffa_errno;
+ u64 req_mode;
+ ffa_value_t ffa_args_rt;
+ ffa_value_t ffa_res_rt;
+
+ if (is_smc64)
+ req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
+ else
+ req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
+ efi_memset_runtime(&ffa_args_rt, 0, sizeof(ffa_args_rt));
+ efi_memset_runtime(&ffa_res_rt, 0, sizeof(ffa_res_rt));
+ ffa_args_rt.a0 = req_mode;
+ ffa_args_rt.a1 = PREP_SELF_ENDPOINT_ID(endpoint_id) |
+ PREP_PART_ENDPOINT_ID(dst_part_id);
+ ffa_args_rt.a2 = 0;
+ ffa_args_rt.a3 = msg->data0;
+ ffa_args_rt.a4 = msg->data1;
+ ffa_args_rt.a5 = msg->data2;
+ ffa_args_rt.a6 = msg->data3;
+ ffa_args_rt.a7 = msg->data4;
+
+ invoke_ffa_fn_runtime(&ffa_args_rt, &ffa_res_rt);
+
+ while (ffa_res_rt.a0 == FFA_SMC_32(FFA_INTERRUPT) ||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_INTERRUPT)) {
+ efi_memset_runtime(&ffa_args_rt, 0, sizeof(ffa_args_rt));
+ ffa_args_rt.a0 = (ffa_res_rt.a0 == FFA_SMC_64(FFA_INTERRUPT)) ?
+ FFA_SMC_64(FFA_RUN) : FFA_SMC_32(FFA_RUN);
+ ffa_args_rt.a1 = ffa_res_rt.a1;
+
+ invoke_ffa_fn_runtime(&ffa_args_rt, &ffa_res_rt);
+ }
+ if (ffa_res_rt.a0 == FFA_SMC_32(FFA_SUCCESS) ||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_SUCCESS)) {
+ /* Message sent with no response */
+ return 0;
+ }
+
+ if (ffa_res_rt.a0 == FFA_SMC_32(FFA_MSG_SEND_DIRECT_RESP) ||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP)) {
+ /* Message sent with response extract the return data */
+ msg->data0 = ffa_res_rt.a3;
+ msg->data1 = ffa_res_rt.a4;
+ msg->data2 = ffa_res_rt.a5;
+ msg->data3 = ffa_res_rt.a6;
+ msg->data4 = ffa_res_rt.a7;
+ return 0;
+ }
+
+ ffa_errno = ffa_res_rt.a2;
+ return ffa_to_std_errno(ffa_errno);
+}
+
+/**
+ * ffa_msg_send_direct_req_hdlr_runtime() - Runtime implementation of
+ * FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int __ffa_runtime ffa_msg_send_direct_req_hdlr_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64)
+{
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+ return ffa_invoke_msg_send_direct_req(priv_rt->id, dst_part_id, msg, is_smc64);
+}
+
+/**
+ * ffa_sync_send_receive_runtime() - Runtime implementation of
+ * ffa_sync_send_receive()
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * Please see ffa_msg_send_direct_req_hdlr_runtime() description for more details.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int __ffa_runtime ffa_sync_send_receive_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64)
+{
+ const struct ffa_bus_ops_runtime *ops_rt = ffa_get_ops_runtime();
+
+ if (!ffa_get_status_runtime_context())
+ return -EPERM;
+
+ if (!ops_rt->sync_send_receive)
+ return -ENOSYS;
+
+ return ops_rt->sync_send_receive(dst_part_id, msg, is_smc64);
+}
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 76a8775e911..548268a42d0 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -1,12 +1,13 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <arm_ffa.h>
#include <arm_ffa_priv.h>
+#include <arm_ffa_runtime.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
@@ -18,19 +19,6 @@
#include <linux/errno.h>
#include <linux/sizes.h>
-/* Error mapping declarations */
-
-int ffa_to_std_errmap[MAX_NUMBER_FFA_ERR] = {
- [NOT_SUPPORTED] = -EOPNOTSUPP,
- [INVALID_PARAMETERS] = -EINVAL,
- [NO_MEMORY] = -ENOMEM,
- [BUSY] = -EBUSY,
- [INTERRUPTED] = -EINTR,
- [DENIED] = -EACCES,
- [RETRY] = -EAGAIN,
- [ABORTED] = -ECANCELED,
-};
-
static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
[FFA_ID_TO_ERRMAP_ID(FFA_VERSION)] = {
{
@@ -94,27 +82,6 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = {
},
};
-/**
- * ffa_to_std_errno() - convert FF-A error code to standard error code
- * @ffa_errno: Error code returned by the FF-A ABI
- *
- * Map the given FF-A error code as specified
- * by the spec to a u-boot standard error code.
- *
- * Return:
- *
- * The standard error code on success. . Otherwise, failure
- */
-static int ffa_to_std_errno(int ffa_errno)
-{
- int err_idx = -ffa_errno;
-
- /* Map the FF-A error code to the standard u-boot error code */
- if (err_idx > 0 && err_idx < MAX_NUMBER_FFA_ERR)
- return ffa_to_std_errmap[err_idx];
- return -EINVAL;
-}
-
/**
* ffa_print_error_log() - print the error log corresponding to the selected FF-A ABI
* @ffa_id: FF-A ABI ID
@@ -204,7 +171,7 @@ int ffa_get_version_hdlr(struct udevice *dev)
if (dev) {
uc_priv = dev_get_uclass_priv(dev);
if (uc_priv)
- uc_priv->fwk_version = res.a0;
+ uc_priv->rt.fwk_version = res.a0;
}
return 0;
@@ -238,8 +205,8 @@ static int ffa_get_endpoint_id(struct udevice *dev)
}, &res);
if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
- uc_priv->id = GET_SELF_ENDPOINT_ID((u32)res.a2);
- log_debug("FF-A endpoint ID is %u\n", uc_priv->id);
+ uc_priv->rt.id = GET_SELF_ENDPOINT_ID((u32)res.a2);
+ log_debug("FF-A endpoint ID is %u\n", uc_priv->rt.id);
return 0;
}
@@ -461,7 +428,7 @@ int ffa_unmap_rxtx_buffers_hdlr(struct udevice *dev)
invoke_ffa_fn((ffa_value_t){
.a0 = FFA_SMC_32(FFA_RXTX_UNMAP),
- .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->id),
+ .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->rt.id),
}, &res);
if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
@@ -851,16 +818,8 @@ static int ffa_cache_partitions_info(struct udevice *dev)
* @msg: pointer to the message data preallocated by the client (in/out)
* @is_smc64: select 64-bit or 32-bit FF-A ABI
*
- * Implement FFA_MSG_SEND_DIRECT_{REQ,RESP}
- * FF-A functions.
- *
- * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
- * The response from the secure partition is handled by reading the
- * FFA_MSG_SEND_DIRECT_RESP arguments.
- *
- * The maximum size of the data that can be exchanged is 40 bytes which is
- * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
- * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
*
* Return:
*
@@ -869,9 +828,6 @@ static int ffa_cache_partitions_info(struct udevice *dev)
int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
struct ffa_send_direct_data *msg, bool is_smc64)
{
- ffa_value_t res = {0};
- int ffa_errno;
- u64 req_mode, resp_mode;
struct ffa_priv *uc_priv;
uc_priv = dev_get_uclass_priv(dev);
@@ -880,50 +836,7 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
if (!uc_priv->partitions.count || !uc_priv->partitions.descs)
return -ENODEV;
- if (is_smc64) {
- req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
- resp_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP);
- } else {
- req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
- resp_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_RESP);
- }
-
- invoke_ffa_fn((ffa_value_t){
- .a0 = req_mode,
- .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->id) |
- PREP_PART_ENDPOINT_ID(dst_part_id),
- .a2 = 0,
- .a3 = msg->data0,
- .a4 = msg->data1,
- .a5 = msg->data2,
- .a6 = msg->data3,
- .a7 = msg->data4,
- }, &res);
-
- while (res.a0 == FFA_SMC_32(FFA_INTERRUPT))
- invoke_ffa_fn((ffa_value_t){
- .a0 = FFA_SMC_32(FFA_RUN),
- .a1 = res.a1,
- }, &res);
-
- if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
- /* Message sent with no response */
- return 0;
- }
-
- if (res.a0 == resp_mode) {
- /* Message sent with response extract the return data */
- msg->data0 = res.a3;
- msg->data1 = res.a4;
- msg->data2 = res.a5;
- msg->data3 = res.a6;
- msg->data4 = res.a7;
-
- return 0;
- }
-
- ffa_errno = res.a2;
- return ffa_to_std_errno(ffa_errno);
+ return ffa_invoke_msg_send_direct_req(uc_priv->rt.id, dst_part_id, msg, is_smc64);
}
/* FF-A driver operations (used by clients for communicating with FF-A)*/
@@ -1024,6 +937,7 @@ int ffa_rxtx_unmap(struct udevice *dev)
static int ffa_do_probe(struct udevice *dev)
{
int ret;
+ struct ffa_priv *uc_priv = dev_get_uclass_priv(dev);
ret = ffa_get_version_hdlr(dev);
if (ret)
@@ -1033,6 +947,12 @@ static int ffa_do_probe(struct udevice *dev)
if (ret)
return ret;
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+ ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
+ if (ret)
+ return ret;
+ }
+
ret = ffa_get_rxtx_map_features_hdlr(dev);
if (ret)
return ret;
@@ -1046,7 +966,6 @@ static int ffa_do_probe(struct udevice *dev)
ffa_unmap_rxtx_buffers_hdlr(dev);
return ret;
}
-
return 0;
}
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c
index 9e6b5dcc542..241ef018817 100644
--- a/drivers/firmware/arm-ffa/arm-ffa.c
+++ b/drivers/firmware/arm-ffa/arm-ffa.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -8,6 +8,7 @@
#include <arm_ffa.h>
#include <arm_ffa_priv.h>
+#include <arm_ffa_runtime.h>
#include <dm.h>
#include <log.h>
#include <dm/device-internal.h>
@@ -25,6 +26,19 @@ void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
arm_smccc_1_2_smc(&args, res);
}
+/**
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
+ * @args: FF-A ABI arguments to be copied to Xn registers
+ * @res: FF-A ABI return values copied from Xn registers
+ *
+ * Calls the SMCCC SMC 1.2 helper from EFI runtime context. This wrapper
+ * is marked __ffa_runtime so it remains available after ExitBootServices().
+ */
+void __ffa_runtime invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res)
+{
+ arm_smccc_1_2_smc(args, res);
+}
+
/**
* arm_ffa_discover() - perform FF-A discovery
* @dev: The Arm FF-A bus device (arm_ffa)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
index 6198d687354..d270f7b614e 100644
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
@@ -671,6 +671,18 @@ void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
sandbox_arm_ffa_smccc_smc(&args, res);
}
+/**
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
+ * @args: FF-A ABI arguments to be copied to Xn registers
+ * @res: FF-A ABI return data to be copied from Xn registers
+ *
+ * Calls the emulated SMC call.
+ */
+void invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res)
+{
+ sandbox_arm_ffa_smccc_smc(args, res);
+}
+
/**
* ffa_emul_find() - Find the FF-A emulator
* @dev: the sandbox FF-A device (sandbox-arm-ffa)
diff --git a/include/arm_ffa.h b/include/arm_ffa.h
index 2994d8ee3ae..6a03aad81a8 100644
--- a/include/arm_ffa.h
+++ b/include/arm_ffa.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -129,21 +129,13 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id,
/**
* ffa_msg_send_direct_req_hdlr() - FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
- * @dev: The arm_ffa bus device
+ * @dev: The FF-A bus device
* @dst_part_id: destination partition ID
* @msg: pointer to the message data preallocated by the client (in/out)
* @is_smc64: select 64-bit or 32-bit FF-A ABI
*
- * This function implements FFA_MSG_SEND_DIRECT_{REQ,RESP}
- * FF-A functions.
- *
- * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
- * The response from the secure partition is handled by reading the
- * FFA_MSG_SEND_DIRECT_RESP arguments.
- *
- * The maximum size of the data that can be exchanged is 40 bytes which is
- * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
- * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
*
* Return:
*
diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
index d564c33c647..3c74c63dfa6 100644
--- a/include/arm_ffa_priv.h
+++ b/include/arm_ffa_priv.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -200,11 +200,24 @@ struct ffa_partitions {
};
/**
- * struct ffa_priv - the driver private data structure
+ * struct ffa_priv_runtime - the driver's private runtime data structure
*
* @fwk_version: FF-A framework version
- * @emul: FF-A sandbox emulator
* @id: u-boot endpoint ID
+ *
+ * The device private runtime data structure containing all the
+ * data read from secure world.
+ */
+struct ffa_priv_runtime {
+ u32 fwk_version;
+ u16 id;
+};
+
+/**
+ * struct ffa_priv - the driver private data structure
+ *
+ * @rt: Runtime data captured at boot time
+ * @emul: FF-A sandbox emulator
* @partitions: The partitions descriptors structure
* @pair: The RX/TX buffers pair
*
@@ -212,9 +225,8 @@ struct ffa_partitions {
* data read from secure world.
*/
struct ffa_priv {
- u32 fwk_version;
+ struct ffa_priv_runtime rt;
struct udevice *emul;
- u16 id;
struct ffa_partitions partitions;
struct ffa_rxtxpair pair;
};
diff --git a/include/arm_ffa_runtime.h b/include/arm_ffa_runtime.h
new file mode 100644
index 00000000000..2411218cb12
--- /dev/null
+++ b/include/arm_ffa_runtime.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#ifndef __ARM_FFA_RUNTIME_H
+#define __ARM_FFA_RUNTIME_H
+
+#include <linux/types.h>
+#include <arm_ffa.h>
+#include <arm_ffa_priv.h>
+#include <efi_loader.h>
+
+/**
+ * __ffa_runtime - controls whether functions are
+ * available after calling the EFI ExitBootServices service.
+ * Functions tagged with these keywords are resident (available at boot time and
+ * at runtime)
+ */
+#if IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+#define __ffa_runtime_data __efi_runtime_data
+#define __ffa_runtime __efi_runtime
+#else
+#define __ffa_runtime_data
+#define __ffa_runtime
+#endif
+
+/**
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
+ * @args: FF-A ABI arguments to be copied to Xn registers
+ * @res: FF-A ABI return values copied from Xn registers
+ *
+ * Calls low level SMC implementation. This wrapper
+ * is marked __ffa_runtime so it remains available after ExitBootServices().
+ */
+void __ffa_runtime invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res);
+
+/**
+ * struct ffa_bus_ops_runtime - Operations for FF-A runtime
+ * @sync_send_receive: callback for the FFA_MSG_SEND_DIRECT_REQ
+ *
+ * The data structure providing all the runtime operations supported by the driver.
+ * This structure is an EFI runtime resident.
+ */
+struct ffa_bus_ops_runtime {
+ int (*sync_send_receive)(u16 dst_part_id, struct ffa_send_direct_data *msg,
+ bool is_smc64);
+};
+
+/**
+ * ffa_enable_runtime_context() - Enable FF-A runtime context
+ *
+ * This function marks the FF-A runtime environment as ready for use by
+ * EFI runtime services. It is called when ExitBootServices() is invoked,
+ * after the FF-A bus device has successfully probed and U-Boot's FF-A
+ * endpoint ID has been discovered and stored in the runtime private data
+ * structure.
+ *
+ * The FF-A runtime flag allows the EFI runtime layer to verify that the
+ * FF-A transport was initialized during the boot phase and that all
+ * runtime-safe FF-A operations may now be used after ExitBootServices().
+ *
+ */
+void ffa_enable_runtime_context(void);
+
+/**
+ * ffa_reset_runtime_context() - Reset FF-A runtime resident state
+ *
+ * Clear the resident runtime flag and private data. This is used by the
+ * FF-A unit tests to avoid leaking runtime state across test cases.
+ */
+void ffa_reset_runtime_context(void);
+
+/**
+ * ffa_copy_runtime_priv() - copy runtime data into resident storage
+ * @priv: pointer to the runtime private data
+ *
+ * Copy boot-time runtime data into the resident runtime storage to be used
+ * after ExitBootServices().
+ */
+void ffa_copy_runtime_priv(const struct ffa_priv_runtime *priv);
+
+/**
+ * ffa_setup_efi_exit_boot_services_event() - register ExitBootServices event
+ * @priv: pointer to the FF-A private data
+ *
+ * Register an EFI event that enables the FF-A runtime context when
+ * ExitBootServices() is invoked.
+ *
+ * Return: 0 on success, -EPERM on failure to create the event.
+ */
+#if IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv);
+#else
+static inline int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv)
+{
+ return 0;
+}
+#endif
+
+/**
+ * ffa_get_status_runtime_context() - Query FF-A runtime readiness
+ *
+ * This helper returns whether the FF-A runtime environment has been
+ * enabled during the boot phase. Runtime FF-A operations must check this
+ * flag before attempting any FF-A access, as the U-Boot driver model
+ * (DM/uclass) is no longer available after ExitBootServices().
+ *
+ * The runtime context becomes enabled when ffa_enable_runtime_context()
+ * is called, typically after the FF-A bus device has probed and the
+ * endpoint ID has been discovered and stored in the runtime private
+ * data structure.
+ *
+ * Return: true if FF-A runtime support is ready, false otherwise.
+ */
+bool __ffa_runtime ffa_get_status_runtime_context(void);
+
+/**
+ * ffa_to_std_errno() - convert FF-A error code to standard error code
+ * @ffa_errno: Error code returned by the FF-A ABI
+ *
+ * Map the given FF-A error code as specified
+ * by the spec to a u-boot standard error code.
+ *
+ * Return: Standard U-Boot errno for known FF-A errors, or -EINVAL otherwise.
+ */
+int __ffa_runtime ffa_to_std_errno(int ffa_errno);
+
+/**
+ * ffa_sync_send_receive_runtime() - Runtime implementation of
+ * ffa_sync_send_receive()
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * Please see ffa_msg_send_direct_req_hdlr_runtime() description for more details.
+ *
+ * Return: 0 on success, negative errno on failure.
+ */
+int __ffa_runtime ffa_sync_send_receive_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64);
+
+/**
+ * ffa_invoke_msg_send_direct_req() - Invokes FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * @endpoint_id: u-boot endpoint id
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
+ * The response from the secure partition is handled by reading the
+ * FFA_MSG_SEND_DIRECT_RESP arguments.
+ *
+ * The maximum size of the data that can be exchanged is 40 bytes which is
+ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
+ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, error on failure
+ */
+int __ffa_runtime ffa_invoke_msg_send_direct_req(u16 endpoint_id, u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64);
+
+/**
+ * ffa_msg_send_direct_req_hdlr_runtime() - Runtime implementation of
+ * FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
+ * @dst_part_id: destination partition ID
+ * @msg: pointer to the message data preallocated by the client (in/out)
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
+ *
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int __ffa_runtime ffa_msg_send_direct_req_hdlr_runtime(u16 dst_part_id,
+ struct ffa_send_direct_data *msg,
+ bool is_smc64);
+
+#endif
diff --git a/test/dm/ffa.c b/test/dm/ffa.c
index 593b7177fce..a0c95e62607 100644
--- a/test/dm/ffa.c
+++ b/test/dm/ffa.c
@@ -2,7 +2,7 @@
/*
* Functional tests for UCLASS_FFA class
*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -26,14 +26,14 @@ static int check_fwk_version(struct ffa_priv *uc_priv, struct unit_test_state *u
func_data.data0 = &fwk_version;
func_data.data0_size = sizeof(fwk_version);
ut_assertok(sandbox_query_ffa_emul_state(FFA_VERSION, &func_data));
- ut_asserteq(uc_priv->fwk_version, fwk_version);
+ ut_asserteq(uc_priv->rt.fwk_version, fwk_version);
return 0;
}
static int check_endpoint_id(struct ffa_priv *uc_priv, struct unit_test_state *uts)
{
- ut_asserteq(0, uc_priv->id);
+ ut_asserteq(0, uc_priv->rt.id);
return 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 01/11] efi_loader: add runtime memset helper Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 02/11] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:35 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 04/11] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
` (7 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Enable MM variable services over FF-A after ExitBootServices
Extend lib/efi_loader/efi_variable_tee.c to support FF-A
communication with the secure world during EFI runtime. Reuse the
statically reserved FF-A shared buffer after ExitBootServices(),
make the MM communication path runtime-safe so runtime variable
operations continue to reach the secure partition.
Share the MM communication and MM SP notification helpers between the
boot and runtime paths instead of maintaining separate runtime-only
variants. Select dynamic allocation during boot and the fixed FF-A
shared buffer at runtime, and reject requests that would exceed the
shared buffer size.
Mark the required code and data with __efi_runtime and
__efi_runtime_data, use range-based cache maintenance on the shared
buffer for the runtime FF-A path, and add the shared buffer to the EFI
runtime memory map. Document the FF-A shared MM buffer
cacheline-alignment requirement in Kconfig and add BUILD_BUG_ON()
checks for the shared buffer address and size in the arm64
cache-maintenance path.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Ilias, Simon:
- Reuse common MM SP error mapping
- Rename runtime-phase tracking to `efi_at_runtime()`
- Collapse boot and runtime MM communication helpers
- Fold runtime MM SP notification into the common path
- Make the arm64 cache-maintenance path runtime-safe
- Document the FF-A shared buffer cacheline-alignment requirement and
add BUILD_BUG_ON() checks for the address and size
- Move shared-buffer reservation to the end of init
- Add a runtime shared-buffer bounds check
- Document the shared-buffer page-alignment assumption
- Reword `setup_mm_hdr()` documentation
- Narrow `mm_var_guid` variable scope
- Update the copyright header
arch/arm/cpu/armv8/cache.S | 8 +
arch/arm/cpu/armv8/cache_v8.c | 13 +-
lib/efi_loader/Kconfig | 4 +
lib/efi_loader/efi_variable_tee.c | 330 ++++++++++++++++++++++--------
4 files changed, 260 insertions(+), 95 deletions(-)
diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S
index c9e46859b4f..916558fe477 100644
--- a/arch/arm/cpu/armv8/cache.S
+++ b/arch/arm/cpu/armv8/cache.S
@@ -169,7 +169,11 @@ ENDPROC(__asm_flush_l3_dcache)
* x0: start address
* x1: end address
*/
+#ifdef CONFIG_EFI_LOADER
+.pushsection .text.efi_runtime.__asm_flush_dcache_range, "ax"
+#else
.pushsection .text.__asm_flush_dcache_range, "ax"
+#endif
ENTRY(__asm_flush_dcache_range)
mrs x3, ctr_el0
ubfx x3, x3, #16, #4
@@ -195,7 +199,11 @@ ENDPROC(__asm_flush_dcache_range)
* x0: start address
* x1: end address
*/
+#ifdef CONFIG_EFI_LOADER
+.pushsection .text.efi_runtime.__asm_invalidate_dcache_range, "ax"
+#else
.pushsection .text.__asm_invalidate_dcache_range, "ax"
+#endif
ENTRY(__asm_invalidate_dcache_range)
mrs x3, ctr_el0
ubfx x3, x3, #16, #4
diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c
index 39479df7b21..7c2840fc545 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -8,6 +8,7 @@
*/
#include <cpu_func.h>
+#include <efi_loader.h>
#include <hang.h>
#include <log.h>
#include <asm/cache.h>
@@ -853,7 +854,8 @@ inline void flush_dcache_all(void)
/*
* Invalidates range in all levels of D-cache/unified cache
*/
-void invalidate_dcache_range(unsigned long start, unsigned long stop)
+void __efi_runtime invalidate_dcache_range(unsigned long start,
+ unsigned long stop)
{
__asm_invalidate_dcache_range(start, stop);
}
@@ -861,16 +863,19 @@ void invalidate_dcache_range(unsigned long start, unsigned long stop)
/*
* Flush range(clean & invalidate) from all levels of D-cache/unified cache
*/
-void flush_dcache_range(unsigned long start, unsigned long stop)
+void __efi_runtime flush_dcache_range(unsigned long start,
+ unsigned long stop)
{
__asm_flush_dcache_range(start, stop);
}
#else
-void invalidate_dcache_range(unsigned long start, unsigned long stop)
+void __efi_runtime invalidate_dcache_range(unsigned long start,
+ unsigned long stop)
{
}
-void flush_dcache_range(unsigned long start, unsigned long stop)
+void __efi_runtime flush_dcache_range(unsigned long start,
+ unsigned long stop)
{
}
#endif /* CONFIG_SYS_DISABLE_DCACHE_OPS */
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index 4cb13ae7c8a..a9791b8f2e3 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -195,6 +195,8 @@ config FFA_SHARED_MM_BUF_SIZE
the MM SP in secure world.
The size of the memory region must be a multiple of the size of the maximum
translation granule size that is specified in the ID_AA64MMFR0_EL1 System register.
+ For arm64 FF-A cache maintenance, this size must also be aligned to
+ CONFIG_SYS_CACHELINE_SIZE.
It is assumed that the MM SP knows the size of the shared MM communication buffer.
config FFA_SHARED_MM_BUF_OFFSET
@@ -211,6 +213,8 @@ config FFA_SHARED_MM_BUF_ADDR
This defines the address of the shared MM communication buffer
used for communication between the MM feature in U-Boot and
the MM SP in secure world.
+ For arm64 FF-A cache maintenance, this address must also be aligned to
+ CONFIG_SYS_CACHELINE_SIZE.
It is assumed that the MM SP knows the address of the shared MM communication buffer.
config EFI_VARIABLE_SF_OFFSET
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 6a1fa39bb6f..ccd8d94a51e 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -4,7 +4,7 @@
*
* Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
* Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -14,6 +14,7 @@
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
#include <arm_ffa.h>
+#include <arm_ffa_runtime.h>
#endif
#include <cpu_func.h>
#include <dm.h>
@@ -21,6 +22,7 @@
#include <efi_api.h>
#include <efi_loader.h>
#include <efi_variable.h>
+#include <linux/build_bug.h>
#include <malloc.h>
#include <mapmem.h>
#include <mm_communication.h>
@@ -34,20 +36,44 @@
#define MM_DENIED (-3)
#define MM_NO_MEMORY (-5)
+static const int __efi_runtime_rodata mm_sp_errmap[] = {
+ [-MM_NOT_SUPPORTED] = -EINVAL,
+ [-MM_INVALID_PARAMETER] = -EPERM,
+ [-MM_DENIED] = -EACCES,
+ [-MM_NO_MEMORY] = -EBUSY,
+};
+
static const char *mm_sp_svc_uuid = MM_SP_UUID;
-static u16 mm_sp_id;
+static u16 __efi_runtime_data mm_sp_id;
#endif
+static void *__efi_runtime_data ffa_shared_buf;
extern struct efi_var_file __efi_runtime_data *efi_var_buf;
-static efi_uintn_t max_buffer_size; /* comm + var + func + data */
-static efi_uintn_t max_payload_size; /* func + data */
+static efi_uintn_t __efi_runtime_data max_buffer_size; /* comm + var + func + data */
+static efi_uintn_t __efi_runtime_data max_payload_size; /* func + data */
static const u16 __efi_runtime_rodata pk[] = u"PK";
+static bool __efi_runtime_data ebs_called;
struct mm_connection {
struct udevice *tee;
u32 session;
};
+/**
+ * efi_at_runtime() - Indicate whether the system is in the UEFI runtime phase
+ *
+ * This helper returns whether the firmware has transitioned into the
+ * UEFI runtime phase, meaning that ExitBootServices() has been invoked.
+ *
+ * Return:
+ * true - The system is operating in UEFI runtime mode.
+ * false - The system is still in the boot services phase.
+ */
+static bool __efi_runtime efi_at_runtime(void)
+{
+ return ebs_called;
+}
+
/**
* get_connection() - Retrieve OP-TEE session for a specific UUID.
*
@@ -169,6 +195,28 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
}
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+/**
+ * ffa_map_sp_event() - Map MM SP response to errno
+ * @sp_event_ret: MM SP return code from MM SP notification
+ *
+ * Convert the MM SP return code into a standard U-Boot errno. This helper
+ * is marked __efi_runtime so it can be shared by both the boot and runtime
+ * FF-A notification paths.
+ *
+ * Return: 0 on success, negative errno on failure
+ */
+static int __efi_runtime ffa_map_sp_event(int sp_event_ret)
+{
+ int idx = -sp_event_ret;
+
+ if (sp_event_ret == MM_SUCCESS)
+ return 0;
+ if (idx > 0 && idx < (int)ARRAY_SIZE(mm_sp_errmap) &&
+ mm_sp_errmap[idx])
+ return mm_sp_errmap[idx];
+ return -EACCES;
+}
+
/**
* ffa_notify_mm_sp() - Announce there is data in the shared buffer
*
@@ -177,52 +225,36 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
* This is a blocking call during which trusted world has exclusive access
* to the MM shared buffer.
*
- * Return:
- *
- * 0 on success
+ * Return: 0 on success
*/
-static int ffa_notify_mm_sp(void)
+static int __efi_runtime ffa_notify_mm_sp(void)
{
struct ffa_send_direct_data msg = {0};
int ret;
int sp_event_ret;
- struct udevice *dev;
+ bool at_runtime = efi_at_runtime();
- ret = uclass_first_device_err(UCLASS_FFA, &dev);
- if (ret) {
- log_err("EFI: Cannot find FF-A bus device, notify MM SP failure\n");
- return ret;
- }
+ msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
+
+ if (at_runtime) {
+ ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
+ } else {
+ struct udevice *dev;
- msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET; /* x3 */
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
+ if (ret) {
+ log_err("EFI: Cannot find FF-A bus device, notify MM SP failure\n");
+ return ret;
+ }
- ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
+ ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
+ }
if (ret)
return ret;
- sp_event_ret = msg.data0; /* x3 */
-
- switch (sp_event_ret) {
- case MM_SUCCESS:
- ret = 0;
- break;
- case MM_NOT_SUPPORTED:
- ret = -EINVAL;
- break;
- case MM_INVALID_PARAMETER:
- ret = -EPERM;
- break;
- case MM_DENIED:
- ret = -EACCES;
- break;
- case MM_NO_MEMORY:
- ret = -EBUSY;
- break;
- default:
- ret = -EACCES;
- }
+ sp_event_ret = msg.data0;
- return ret;
+ return ffa_map_sp_event(sp_event_ret);
}
/**
@@ -266,36 +298,41 @@ static int ffa_discover_mm_sp_id(void)
}
/**
- * ffa_mm_communicate() - Exchange EFI services data with the MM partition using FF-A
+ * ffa_mm_communicate() - Exchange EFI services data with the MM partition using FF-A
* @comm_buf: locally allocated communication buffer used for rx/tx
- * @dsize: communication buffer size
+ * @comm_buf_size: communication buffer size
*
* Issue a door bell event to notify the MM partition (SP) running in OP-TEE
* that there is data to read from the shared buffer.
* Communication with the MM SP is performed using FF-A transport.
* On the event, MM SP can read the data from the buffer and
* update the MM shared buffer with response data.
- * The response data is copied back to the communication buffer.
- *
- * Return:
+ * The response data is copied back to the communication buffer during the
+ * boot phase. At runtime, the communication buffer is already the FF-A
+ * shared buffer and is updated in place.
*
- * EFI status code
+ * Return: EFI status code
*/
-static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
+static efi_status_t __efi_runtime ffa_mm_communicate(void *comm_buf,
+ ulong comm_buf_size)
{
ulong tx_data_size;
int ffa_ret;
efi_status_t efi_ret;
struct efi_mm_communicate_header *mm_hdr;
- void *virt_shared_buf;
+ u8 *shared_buf;
+ bool at_runtime = efi_at_runtime();
if (!comm_buf)
return EFI_INVALID_PARAMETER;
- /* Discover MM partition ID at boot time */
- if (!mm_sp_id && ffa_discover_mm_sp_id()) {
- log_err("EFI: Failure to discover MM SP ID at boot time, FF-A MM comms failure\n");
- return EFI_UNSUPPORTED;
+ if (!mm_sp_id) {
+ if (at_runtime)
+ return EFI_UNSUPPORTED;
+ if (ffa_discover_mm_sp_id()) {
+ log_err("EFI: Failure to discover MM SP ID at boot time, FF-A MM comms failure\n");
+ return EFI_UNSUPPORTED;
+ }
}
mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
@@ -304,30 +341,61 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
if (comm_buf_size != tx_data_size || tx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
return EFI_INVALID_PARAMETER;
- /* Copy the data to the shared buffer */
-
- virt_shared_buf = map_sysmem((phys_addr_t)CONFIG_FFA_SHARED_MM_BUF_ADDR, 0);
- memcpy(virt_shared_buf, comm_buf, tx_data_size);
+ if (at_runtime) {
+ shared_buf = comm_buf;
+ } else {
+ /* Copy the data to the shared buffer */
+ shared_buf = map_sysmem((phys_addr_t)CONFIG_FFA_SHARED_MM_BUF_ADDR, 0);
+ memcpy(shared_buf, comm_buf, tx_data_size);
+ }
/*
- * The secure world might have cache disabled for
- * the device region used for shared buffer (which is the case for Optee).
- * In this case, the secure world reads the data from DRAM.
- * Let's flush the cache so the DRAM is updated with the latest data.
+ * Shared buffer cache maintenance for FF-A / OP-TEE communication:
+ *
+ * NS -> S (request path):
+ *
+ * The non-secure side populates the shared buffer. If the buffer is cached
+ * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
+ * visible in DDR. Since the secure world typically reads the shared buffer
+ * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
+ * must clean the corresponding cache lines to the Point of Coherency (PoC)
+ * before entering secure world.
+ *
+ * S -> NS (response path):
+ *
+ * The secure world may update the same shared buffer in DDR. After returning
+ * to non-secure, any cached copies of that region in NS may be stale. We
+ * therefore invalidate the shared buffer range after the FF-A call to drop
+ * those lines and force subsequent reads to fetch the latest data from DDR.
+ *
+ * Note: Whole-cache invalidation must not be used in EFI runtime context.
+ * After ExitBootServices(), the OS owns the cache hierarchy; global
+ * invalidation could drop OS dirty lines and violate the OS coherency
+ * model. Always operate on the shared buffer range only.
*/
-#ifdef CONFIG_ARM64
- invalidate_dcache_all();
-#endif
+ if (IS_ENABLED(CONFIG_ARM64)) {
+ BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR %
+ CONFIG_SYS_CACHELINE_SIZE);
+ BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_SIZE %
+ CONFIG_SYS_CACHELINE_SIZE);
+ flush_dcache_range((unsigned long)shared_buf,
+ (unsigned long)(shared_buf +
+ CONFIG_FFA_SHARED_MM_BUF_SIZE));
+ }
/* Announce there is data in the shared buffer */
-
ffa_ret = ffa_notify_mm_sp();
+ if (IS_ENABLED(CONFIG_ARM64))
+ invalidate_dcache_range((unsigned long)shared_buf,
+ (unsigned long)(shared_buf +
+ CONFIG_FFA_SHARED_MM_BUF_SIZE));
+
switch (ffa_ret) {
case 0: {
ulong rx_data_size;
- /* Copy the MM SP response from the shared buffer to the communication buffer */
- rx_data_size = ((struct efi_mm_communicate_header *)virt_shared_buf)->message_len +
+
+ rx_data_size = ((struct efi_mm_communicate_header *)shared_buf)->message_len +
sizeof(efi_guid_t) +
sizeof(size_t);
@@ -336,7 +404,8 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
break;
}
- memcpy(comm_buf, virt_shared_buf, rx_data_size);
+ if (!at_runtime)
+ memcpy(comm_buf, shared_buf, rx_data_size);
efi_ret = EFI_SUCCESS;
break;
}
@@ -356,28 +425,34 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
efi_ret = EFI_ACCESS_DENIED;
}
- unmap_sysmem(virt_shared_buf);
+ if (!at_runtime)
+ unmap_sysmem(shared_buf);
return efi_ret;
}
/**
* get_mm_comms() - detect the available MM transport
*
- * Make sure the FF-A bus is probed successfully
- * which means FF-A communication with secure world works and ready
- * for use.
- *
- * If FF-A bus is not ready, use OPTEE comms.
+ * Make sure the FF-A bus is probed successfully during the boot phase,
+ * which means FF-A communication with secure world works and is ready for
+ * use. During the runtime phase, only the FF-A runtime transport can be
+ * selected.
*
- * Return:
+ * If FF-A bus is not ready at boot, use OP-TEE comms.
*
- * MM_COMMS_FFA or MM_COMMS_OPTEE
+ * Return: MM_COMMS_FFA, MM_COMMS_OPTEE, or MM_COMMS_UNDEFINED
*/
-static enum mm_comms_select get_mm_comms(void)
+static enum mm_comms_select __efi_runtime get_mm_comms(void)
{
struct udevice *dev;
int ret;
+ if (efi_at_runtime()) {
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE))
+ return MM_COMMS_FFA;
+ return MM_COMMS_UNDEFINED;
+ }
+
ret = uclass_first_device_err(UCLASS_FFA, &dev);
if (ret) {
log_debug("EFI: Cannot find FF-A bus device, trying Optee comms\n");
@@ -389,8 +464,8 @@ static enum mm_comms_select get_mm_comms(void)
#endif
/**
- * mm_communicate() - Adjust the communication buffer to the MM SP and send
- * it to OP-TEE
+ * mm_communicate() - Adjust the communication buffer to the MM SP and send it
+ * to the selected MM transport
*
* @comm_buf: locally allocated communication buffer
* @dsize: buffer size
@@ -400,11 +475,12 @@ static enum mm_comms_select get_mm_comms(void)
* When using the u-boot OP-TEE driver, StandAlonneMM is supported.
* When using the u-boot FF-A driver, any MM SP is supported.
*
- * Return: status code
+ * Return: status code
*/
-static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
+static efi_status_t __efi_runtime mm_communicate(u8 *comm_buf,
+ efi_uintn_t dsize)
{
- efi_status_t ret;
+ efi_status_t ret = EFI_UNSUPPORTED;
struct efi_mm_communicate_header *mm_hdr;
struct smm_variable_communicate_header *var_hdr;
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
@@ -419,14 +495,15 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
mm_comms = get_mm_comms();
if (mm_comms == MM_COMMS_FFA)
ret = ffa_mm_communicate(comm_buf, dsize);
- else
+ else if (mm_comms == MM_COMMS_OPTEE)
ret = optee_mm_communicate(comm_buf, dsize);
#else
- ret = optee_mm_communicate(comm_buf, dsize);
+ ret = optee_mm_communicate(comm_buf, dsize);
#endif
if (ret != EFI_SUCCESS) {
- log_err("%s failed!\n", __func__);
+ if (!efi_at_runtime())
+ log_err("%s failed!\n", __func__);
return ret;
}
@@ -434,8 +511,55 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
}
/**
- * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
- * header data.
+ * get_comm_buf() - Obtain a communication buffer for MM/FF-A exchange
+ * @payload_size: size of the payload that will be appended to the
+ * MM communication header
+ * This helper returns a buffer suitable for constructing an
+ * EFI_MM_COMMUNICATE message. During the boot phase a new buffer is
+ * dynamically allocated. After ExitBootServices(), dynamic
+ * allocation is no longer permitted, and all runtime communication must
+ * use the statically reserved FF-A shared buffer.
+ *
+ * Return:
+ * Pointer to a valid communication buffer on success,
+ * NULL if allocation fails during the boot phase.
+ */
+static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
+{
+ efi_uintn_t comm_buf_size;
+ u8 *comm_buf;
+
+ comm_buf_size = MM_COMMUNICATE_HEADER_SIZE +
+ MM_VARIABLE_COMMUNICATE_SIZE +
+ payload_size;
+
+ /*
+ * After ExitBootServices(), dynamic allocation is no longer permitted.
+ * Use the predefined FF-A shared buffer at runtime; otherwise allocate
+ * a fresh buffer during the boot phase.
+ */
+ if (efi_at_runtime()) {
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+ if (comm_buf_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
+ return NULL;
+ comm_buf = ffa_shared_buf;
+ if (!comm_buf)
+ return NULL;
+ efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
+ } else {
+ return NULL;
+ }
+ } else {
+ comm_buf = calloc(1, comm_buf_size);
+ if (!comm_buf)
+ return NULL;
+ }
+ return comm_buf;
+}
+
+/**
+ * setup_mm_hdr() - Obtain a communication buffer for StandAloneMM and
+ * initialize the MM header
*
* @dptr: pointer address of the corresponding StandAloneMM
* function
@@ -444,10 +568,11 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
* @ret: EFI return code
* Return: buffer or NULL
*/
-static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
- efi_uintn_t func, efi_status_t *ret)
+static __efi_runtime u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
+ efi_uintn_t func, efi_status_t *ret)
{
- const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
+ static const __efi_runtime_rodata efi_guid_t mm_var_guid =
+ EFI_MM_VARIABLE_GUID;
struct efi_mm_communicate_header *mm_hdr;
struct smm_variable_communicate_header *var_hdr;
u8 *comm_buf;
@@ -465,16 +590,15 @@ static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
return NULL;
}
- comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
- MM_VARIABLE_COMMUNICATE_SIZE +
- payload_size);
+ comm_buf = get_comm_buf(payload_size);
if (!comm_buf) {
*ret = EFI_OUT_OF_RESOURCES;
return NULL;
}
mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
- guidcpy(&mm_hdr->header_guid, &mm_var_guid);
+ efi_memcpy_runtime(&mm_hdr->header_guid, &mm_var_guid,
+ sizeof(mm_hdr->header_guid));
mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
@@ -982,6 +1106,9 @@ void efi_variables_boot_exit_notify(void)
efi_get_next_variable_name_runtime;
efi_runtime_services.set_variable = efi_set_variable_runtime;
efi_update_table_header_crc32(&efi_runtime_services.hdr);
+
+ /* Record that ExitBootServices() has been called */
+ ebs_called = true;
}
/**
@@ -1010,5 +1137,26 @@ efi_status_t efi_init_variables(void)
if (ret != EFI_SUCCESS)
return ret;
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+ /*
+ * The FF-A shared buffer is accessed by EFI runtime services, so it
+ * must be marked as runtime memory in the EFI memory map.
+ *
+ * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
+ */
+ ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
+ ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
+ CONFIG_FFA_SHARED_MM_BUF_SIZE,
+ EFI_RUNTIME_SERVICES_DATA);
+ if (ret != EFI_SUCCESS) {
+ log_err("EFI: failed to add FF-A shared buffer to runtime map (%lu)\n",
+ ret);
+ return ret;
+ }
+ log_info("EFI: FF-A shared buffer runtime map: addr=0x%lx size=0x%lx\n",
+ (ulong)CONFIG_FFA_SHARED_MM_BUF_ADDR,
+ (ulong)CONFIG_FFA_SHARED_MM_BUF_SIZE);
+ }
+
return EFI_SUCCESS;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 04/11] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (2 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:26 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 05/11] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
` (6 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Route EFI runtime variable APIs through FF-A MM communication
Route EFI runtime variable services through the FF-A/MM backend in
lib/efi_loader/efi_variable_tee.c. After ExitBootServices(),
GetVariable(), SetVariable(), GetNextVariableName(), and
QueryVariableInfo() use the runtime entry points and continue to reach
the MM secure partition.
Keep the existing boot-time helpers unchanged and add runtime service
wrappers for variable access and property handling. Reuse the
runtime-safe setup_mm_hdr() and common mm_communicate() path, which
selects the FF-A transport appropriate for the current phase, and use
the EFI runtime-safe memory helpers in the runtime-only code.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Cache attributes before reusing the FF-A shared buffer
- Move the read-only property check before `setup_mm_hdr()` in
efi_set_variable_runtime
- Drop the stale copied boot-path comment
- Split the `u16_strsize()` runtime annotation to a separate patch
lib/efi_loader/efi_variable_tee.c | 320 +++++++++++++++++++++++++++++-
1 file changed, 315 insertions(+), 5 deletions(-)
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index ccd8d94a51e..8acd0ed127b 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -698,6 +698,38 @@ out:
return ret;
}
+static efi_status_t __efi_runtime set_property_int_runtime(const u16 *variable_name,
+ efi_uintn_t name_size,
+ const efi_guid_t *vendor,
+ struct var_check_property *var_property)
+{
+ struct smm_variable_var_check_property *smm_property;
+ efi_uintn_t payload_size;
+ u8 *comm_buf = NULL;
+ efi_status_t ret;
+
+ payload_size = sizeof(*smm_property) + name_size;
+ if (payload_size > max_payload_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+ comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
+ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(*vendor));
+ smm_property->name_size = name_size;
+ efi_memcpy_runtime(&smm_property->property, var_property,
+ sizeof(smm_property->property));
+ efi_memcpy_runtime(smm_property->name, variable_name, name_size);
+
+ ret = mm_communicate(comm_buf, payload_size);
+
+ return ret;
+}
+
static efi_status_t get_property_int(const u16 *variable_name,
efi_uintn_t name_size,
const efi_guid_t *vendor,
@@ -743,6 +775,49 @@ out:
return ret;
}
+static efi_status_t __efi_runtime get_property_int_runtime(const u16 *variable_name,
+ efi_uintn_t name_size,
+ const efi_guid_t *vendor,
+ struct var_check_property *var_property)
+{
+ struct smm_variable_var_check_property *smm_property;
+ efi_uintn_t payload_size;
+ u8 *comm_buf = NULL;
+ efi_status_t ret;
+
+ efi_memset_runtime(var_property, 0, sizeof(*var_property));
+ payload_size = sizeof(*smm_property) + name_size;
+ if (payload_size > max_payload_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+ comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
+ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(smm_property->guid));
+ smm_property->name_size = name_size;
+ efi_memcpy_runtime(smm_property->name, variable_name, name_size);
+
+ ret = mm_communicate(comm_buf, payload_size);
+ /*
+ * Currently only R/O property is supported in StMM.
+ * Variables that are not set to R/O will not set the property in StMM
+ * and the call will return EFI_NOT_FOUND. We are setting the
+ * properties to 0x0 so checking against that is enough for the
+ * EFI_NOT_FOUND case.
+ */
+ if (ret == EFI_NOT_FOUND)
+ ret = EFI_SUCCESS;
+ if (ret != EFI_SUCCESS)
+ return ret;
+ efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
+
+ return ret;
+}
+
efi_status_t efi_get_variable_int(const u16 *variable_name,
const efi_guid_t *vendor,
u32 *attributes, efi_uintn_t *data_size,
@@ -830,6 +905,95 @@ out:
return ret;
}
+efi_status_t __efi_runtime efi_get_variable_runtime(u16 *variable_name,
+ const efi_guid_t *vendor,
+ u32 *attributes,
+ efi_uintn_t *data_size,
+ void *data)
+{
+ struct var_check_property var_property;
+ struct smm_variable_access *var_acc;
+ efi_uintn_t payload_size;
+ efi_uintn_t name_size;
+ efi_uintn_t tmp_dsize;
+ u8 *comm_buf = NULL;
+ efi_status_t ret, tmp;
+ u32 var_attr = 0;
+
+ if (!variable_name || !vendor || !data_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ /* Check payload size */
+ name_size = u16_strsize(variable_name);
+ if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ /* Trim output buffer size */
+ tmp_dsize = *data_size;
+ if (name_size + tmp_dsize >
+ max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
+ tmp_dsize = max_payload_size -
+ MM_VARIABLE_ACCESS_HEADER_SIZE -
+ name_size;
+ }
+
+ /* Get communication buffer and initialize header */
+ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
+ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
+ SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret);
+ if (!comm_buf)
+ return ret;
+
+ /* Fill in contents */
+ efi_memcpy_runtime(&var_acc->guid, vendor, sizeof(var_acc->guid));
+ var_acc->data_size = tmp_dsize;
+ var_acc->name_size = name_size;
+ var_acc->attr = attributes ? *attributes : 0;
+ efi_memcpy_runtime(var_acc->name, variable_name, name_size);
+
+ /* Communicate */
+ ret = mm_communicate(comm_buf, payload_size);
+ if (ret != EFI_SUCCESS && ret != EFI_BUFFER_TOO_SMALL)
+ return ret;
+
+ /* Update with reported data size for trimmed case */
+ *data_size = var_acc->data_size;
+ if (attributes)
+ var_attr = var_acc->attr;
+
+ /* Copy the data if ret is EFI_SUCCESS */
+ if (ret == EFI_SUCCESS) {
+ if (data)
+ efi_memcpy_runtime(data, (u8 *)var_acc->name + var_acc->name_size,
+ var_acc->data_size);
+ else
+ ret = EFI_INVALID_PARAMETER;
+ }
+
+ /*
+ * UEFI > 2.7 needs the attributes set even if the buffer is
+ * smaller
+ */
+ if (attributes) {
+ tmp = get_property_int_runtime(variable_name, name_size, vendor,
+ &var_property);
+ if (tmp != EFI_SUCCESS) {
+ ret = tmp;
+ return ret;
+ }
+ *attributes = var_attr;
+ if (var_property.property &
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
+ *attributes |= EFI_VARIABLE_READ_ONLY;
+ }
+
+ return ret;
+}
+
efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
u16 *variable_name,
efi_guid_t *guid)
@@ -894,6 +1058,68 @@ out:
return ret;
}
+efi_status_t __efi_runtime efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
+ u16 *variable_name,
+ efi_guid_t *guid)
+{
+ struct smm_variable_getnext *var_getnext;
+ efi_uintn_t payload_size;
+ efi_uintn_t out_name_size;
+ efi_uintn_t in_name_size;
+ u8 *comm_buf = NULL;
+ efi_status_t ret;
+
+ if (!variable_name_size || !variable_name || !guid) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ out_name_size = *variable_name_size;
+ in_name_size = u16_strsize(variable_name);
+
+ if (out_name_size < in_name_size) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
+ ret = EFI_INVALID_PARAMETER;
+ return ret;
+ }
+
+ /* Trim output buffer size */
+ if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
+ out_name_size = max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE;
+
+ payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
+ comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size,
+ SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ /* Fill in contents */
+ efi_memcpy_runtime(&var_getnext->guid, guid, sizeof(*guid));
+ var_getnext->name_size = out_name_size;
+ efi_memcpy_runtime(var_getnext->name, variable_name, in_name_size);
+ efi_memset_runtime((u8 *)var_getnext->name + in_name_size, 0x0,
+ out_name_size - in_name_size);
+
+ /* Communicate */
+ ret = mm_communicate(comm_buf, payload_size);
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
+ /* Update with reported data size for trimmed case */
+ *variable_name_size = var_getnext->name_size;
+ }
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ efi_memcpy_runtime(guid, &var_getnext->guid, sizeof(*guid));
+ efi_memcpy_runtime(variable_name, var_getnext->name, var_getnext->name_size);
+
+ return ret;
+}
+
efi_status_t efi_set_variable_int(const u16 *variable_name,
const efi_guid_t *vendor, u32 attributes,
efi_uintn_t data_size, const void *data,
@@ -1036,11 +1262,11 @@ out:
*
* @attributes: bitmask to select variables to be
* queried
- * @maximum_variable_storage_size: maximum size of storage area for the
+ * @max_variable_storage_size: maximum size of storage area for the
* selected variable types
- * @remaining_variable_storage_size: remaining size of storage are for the
+ * @remain_variable_storage_size: remaining size of storage are for the
* selected variable types
- * @maximum_variable_size: maximum size of a variable of the
+ * @max_variable_size: maximum size of a variable of the
* selected type
* Return: status code
*/
@@ -1049,7 +1275,33 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
u64 *remain_variable_storage_size,
u64 *max_variable_size)
{
- return EFI_UNSUPPORTED;
+ struct smm_variable_query_info *mm_query_info;
+ efi_uintn_t payload_size;
+ efi_status_t ret;
+ u8 *comm_buf;
+
+ if (!max_variable_storage_size ||
+ !remain_variable_storage_size ||
+ !max_variable_size || !attributes)
+ return EFI_INVALID_PARAMETER;
+
+ payload_size = sizeof(*mm_query_info);
+ comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
+ SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
+ &ret);
+ if (!comm_buf)
+ return ret;
+
+ mm_query_info->attr = attributes;
+ ret = mm_communicate(comm_buf, payload_size);
+ if (ret != EFI_SUCCESS)
+ return ret;
+ *max_variable_storage_size = mm_query_info->max_variable_storage;
+ *remain_variable_storage_size =
+ mm_query_info->remaining_variable_storage;
+ *max_variable_size = mm_query_info->max_variable_size;
+
+ return ret;
}
/**
@@ -1067,7 +1319,65 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
u32 attributes, efi_uintn_t data_size,
const void *data)
{
- return EFI_UNSUPPORTED;
+ efi_status_t ret, mm_communicate_ret = EFI_SUCCESS;
+ struct var_check_property var_property;
+ struct smm_variable_access *var_acc;
+ efi_uintn_t payload_size;
+ efi_uintn_t name_size;
+ u8 *comm_buf = NULL;
+ bool ro;
+
+ if (!variable_name || variable_name[0] == 0 || !guid)
+ return EFI_INVALID_PARAMETER;
+
+ if (data_size > 0 && !data)
+ return EFI_INVALID_PARAMETER;
+
+ /* Check payload size */
+ name_size = u16_strsize(variable_name);
+ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
+ if (payload_size > max_payload_size)
+ return EFI_INVALID_PARAMETER;
+
+ ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
+ attributes &= EFI_VARIABLE_MASK;
+
+ ret = get_property_int_runtime(variable_name, name_size, guid,
+ &var_property);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
+ return EFI_WRITE_PROTECTED;
+
+ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
+ SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
+ if (!comm_buf)
+ return ret;
+
+ /* Fill in contents */
+ efi_memcpy_runtime(&var_acc->guid, guid, sizeof(*guid));
+ var_acc->data_size = data_size;
+ var_acc->name_size = name_size;
+ var_acc->attr = attributes;
+ efi_memcpy_runtime(var_acc->name, variable_name, name_size);
+ efi_memcpy_runtime((u8 *)var_acc->name + name_size, data, data_size);
+
+ /* Communicate */
+ ret = mm_communicate(comm_buf, payload_size);
+ if (ret != EFI_SUCCESS)
+ mm_communicate_ret = ret;
+
+ if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
+ var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
+ var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
+ var_property.attributes = attributes;
+ var_property.minsize = 1;
+ var_property.maxsize = var_acc->data_size;
+ ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
+ }
+
+ return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
}
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 05/11] charset: mark u16_strsize() as __efi_runtime
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (3 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 04/11] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:21 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 06/11] efi_loader: move runtime variable read helpers to efi_variable.c Harsimran Singh Tungal
` (5 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Mark u16_strsize() as __efi_runtime so it can be called from the EFI
runtime variable paths added for FF-A/MM communication after
ExitBootServices().
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
lib/charset.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/charset.c b/lib/charset.c
index 182c92a50c4..738ad1352de 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -407,7 +407,7 @@ size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
return i;
}
-size_t u16_strsize(const void *in)
+size_t __efi_runtime u16_strsize(const void *in)
{
return (u16_strlen(in) + 1) * sizeof(u16);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 06/11] efi_loader: move runtime variable read helpers to efi_variable.c
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (4 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 05/11] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:21 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 07/11] corstone1000: enable bootefi selftest Harsimran Singh Tungal
` (4 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Relocate the generic runtime variable read helpers from
efi_var_common.c to efi_variable.c.
efi_var_common.c is always built, while efi_variable.c is only built
when CONFIG_EFI_MM_COMM_TEE is unset. Earlier patches in this series
add TEE/FF-A-specific runtime read helpers in efi_variable_tee.c.
Leaving the generic definitions in efi_var_common.c would therefore
cause a symbol clash in EFI_MM_COMM_TEE builds.
Move efi_get_variable_runtime() and
efi_get_next_variable_name_runtime() into efi_variable.c so the
non-TEE backend keeps the generic memory-backed implementations,
while the TEE/FF-A backend continues to provide its own runtime read
helpers in efi_variable_tee.c.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Ilias, Simon:
- Reword commit message to include relocation of generic non-TEE
helpers and broaden the wording to cover both runtime read helpers
lib/efi_loader/efi_var_common.c | 24 ------------------------
lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
2 files changed, 24 insertions(+), 24 deletions(-)
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
index d63c2d1b1cd..7cbf098c64a 100644
--- a/lib/efi_loader/efi_var_common.c
+++ b/lib/efi_loader/efi_var_common.c
@@ -173,30 +173,6 @@ efi_status_t EFIAPI efi_query_variable_info(
return EFI_EXIT(ret);
}
-efi_status_t __efi_runtime EFIAPI
-efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
- u32 *attributes, efi_uintn_t *data_size, void *data)
-{
- efi_status_t ret;
-
- ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
- data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
-
- /* Remove EFI_VARIABLE_READ_ONLY flag */
- if (attributes)
- *attributes &= EFI_VARIABLE_MASK;
-
- return ret;
-}
-
-efi_status_t __efi_runtime EFIAPI
-efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
- u16 *variable_name, efi_guid_t *guid)
-{
- return efi_get_next_variable_name_mem(variable_name_size, variable_name,
- guid, EFI_VARIABLE_RUNTIME_ACCESS);
-}
-
/**
* efi_set_secure_state - modify secure boot state variables
* @secure_boot: value of SecureBoot
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 9923936c1b5..f2e0e1ad4e2 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -579,6 +579,30 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
return EFI_SUCCESS;
}
+efi_status_t __efi_runtime EFIAPI
+efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
+ u32 *attributes, efi_uintn_t *data_size, void *data)
+{
+ efi_status_t ret;
+
+ ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
+ data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
+
+ /* Remove EFI_VARIABLE_READ_ONLY flag */
+ if (attributes)
+ *attributes &= EFI_VARIABLE_MASK;
+
+ return ret;
+}
+
+efi_status_t __efi_runtime EFIAPI
+efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
+ u16 *variable_name, efi_guid_t *guid)
+{
+ return efi_get_next_variable_name_mem(variable_name_size, variable_name,
+ guid, EFI_VARIABLE_RUNTIME_ACCESS);
+}
+
/**
* efi_variables_boot_exit_notify() - notify ExitBootServices() is called
*/
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 07/11] corstone1000: enable bootefi selftest
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (5 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 06/11] efi_loader: move runtime variable read helpers to efi_variable.c Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:22 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 08/11] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
` (3 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Enable `CMD_BOOTEFI_SELFTEST` in `corstone1000_defconfig` so the later
runtime-variable selftest patch in this series can be exercised on
Corstone-1000.
Keep `CMD_BOOTEFI_HELLO` and `CMD_POWEROFF` explicitly disabled.
Enabling `CMD_BOOTEFI_SELFTEST` would otherwise make
`CMD_BOOTEFI_HELLO` default to `y` and pull in `CMD_POWEROFF` on this
PSCI-based defconfig. The intent here is to enable the selftest command
without broadening the rest of the board command set.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Reword the commit message around `CMD_BOOTEFI_SELFTEST` and explain why
the selftest enable is needed on Corstone-1000
- Clarify in commit message that `is not set` lines are intentional
configs/corstone1000_defconfig | 3 +++
1 file changed, 3 insertions(+)
diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
index 527a679b785..b5fb4868e0f 100644
--- a/configs/corstone1000_defconfig
+++ b/configs/corstone1000_defconfig
@@ -32,6 +32,8 @@ CONFIG_SYS_PROMPT="corstone1000# "
# CONFIG_CMD_CONSOLE is not set
CONFIG_CMD_FWU_METADATA=y
CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_BOOTEFI_HELLO is not set
+CONFIG_CMD_BOOTEFI_SELFTEST=y
# CONFIG_CMD_XIMG is not set
CONFIG_CMD_GPT=y
CONFIG_CMD_LOADM=y
@@ -63,6 +65,7 @@ CONFIG_SYSRESET=y
CONFIG_SYSRESET_PSCI=y
CONFIG_TEE=y
CONFIG_OPTEE=y
+# CONFIG_CMD_POWEROFF is not set
CONFIG_USB=y
CONFIG_USB_ISP1760=y
# CONFIG_RANDOM_UUID is not set
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 08/11] efi: selftest: add runtime variable tests with non-volatile storage
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (6 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 07/11] corstone1000: enable bootefi selftest Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:35 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 09/11] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
` (2 subsequent siblings)
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Extend runtime variable tests for persistent storage
Runtime variable selftests already cover the volatile-store path in a
single run, but non-volatile storage needs state to survive a reboot.
Make that flow explicit by keeping the existing "variables at runtime"
test for CONFIG_EFI_RT_VOLATILE_STORE=y and adding on-request
"variables at runtime setup" and "variables at runtime verify" tests
for the non-volatile case.
The setup phase runs QueryVariableInfo(), exercises create/delete of a
runtime variable, prepares the persistent test state, and prompts the
user to reboot and run the verify test. If an old test variable is
already present, reuse it only when it matches the expected
half-payload; otherwise delete it and recreate clean state. The setup
path also performs a best-effort cleanup if a later check fails.
The verify phase checks the prepared value, appends the remaining
payload, validates the full contents, deletes the test variable, and
confirms that it is gone.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Split the non-volatile flow into setup and verify tests
- Keep the single-run test only for volatile-store builds
- Reuse shared QueryVariableInfo and enumeration helpers
- Make setup and verify logs stage-specific
.../efi_selftest_variables_runtime.c | 713 ++++++++++++------
1 file changed, 481 insertions(+), 232 deletions(-)
diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
index fd570d673f0..510e3f4c302 100644
--- a/lib/efi_selftest/efi_selftest_variables_runtime.c
+++ b/lib/efi_selftest/efi_selftest_variables_runtime.c
@@ -3,6 +3,7 @@
* efi_selftest_variables_runtime
*
* Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ * Copyright (c) 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* This unit test checks the runtime services for variables after
* ExitBootServices():
@@ -17,36 +18,28 @@
#define EFI_ST_MAX_VARNAME_SIZE 40
static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID;
-static const efi_guid_t efi_rt_var_guid = U_BOOT_EFI_RT_VAR_FILE_GUID;
/**
- * execute() - execute unit test
+ * check_runtime_query_variable_info() - Run QueryVariableInfo() checks
+ * @phase: test phase string used in failure logs
+ *
+ * Run the runtime QueryVariableInfo() checks for the current test phase.
*
- * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned.
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
*/
-static int execute(void)
+static int check_runtime_query_variable_info(const char *phase)
{
efi_status_t ret;
- efi_uintn_t len, avail, append_len = 17;
- u32 attr;
- u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
- 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
- u8 v2[CONFIG_EFI_VAR_BUF_SIZE];
- u8 data[EFI_ST_MAX_DATA_SIZE];
- u8 data2[CONFIG_EFI_VAR_BUF_SIZE];
- u16 varname[EFI_ST_MAX_VARNAME_SIZE];
- efi_guid_t guid;
u64 max_storage, rem_storage, max_size;
int test_ret;
- memset(v2, 0x1, sizeof(v2));
-
if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE)) {
test_ret = efi_st_query_variable_common(
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS);
if (test_ret != EFI_ST_SUCCESS) {
- efi_st_error("QueryVariableInfo failed\n");
+ efi_st_error("%s: QueryVariableInfo checks failed\n",
+ phase);
return EFI_ST_FAILURE;
}
} else {
@@ -54,257 +47,513 @@ static int execute(void)
EFI_VARIABLE_BOOTSERVICE_ACCESS, &max_storage,
&rem_storage, &max_size);
if (ret != EFI_UNSUPPORTED) {
- efi_st_error("QueryVariableInfo failed\n");
+ efi_st_error("%s: QueryVariableInfo returned status=%lx\n",
+ phase, (ulong)ret);
return EFI_ST_FAILURE;
}
}
+ return EFI_ST_SUCCESS;
+}
+
+/**
+ * check_runtime_variable_enumeration() - Check runtime variable enumeration
+ * @phase: test phase string used in failure logs
+ *
+ * Confirm that runtime variable reads and GetNextVariableName() still work
+ * while the current test state is present.
+ *
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
+ */
+static int check_runtime_variable_enumeration(const char *phase)
+{
+ efi_status_t ret;
+ efi_uintn_t len;
+ u32 attr = 0;
+ u8 data[EFI_ST_MAX_DATA_SIZE];
+ u16 varname[EFI_ST_MAX_VARNAME_SIZE];
+ efi_guid_t guid;
+
+ len = sizeof(data);
+ ret = st_runtime->get_variable(u"PlatformLangCodes", &guid_vendor0,
+ &attr, &len, data);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("%s: failed to read PlatformLangCodes, status=%lx\n",
+ phase, (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ memset(&guid, 0, sizeof(guid));
+ *varname = 0;
+ len = sizeof(varname);
+ ret = st_runtime->get_next_variable_name(&len, varname, &guid);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("%s: GetNextVariableName failed, status=%lx\n",
+ phase, (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ return EFI_ST_SUCCESS;
+}
+
+#ifdef CONFIG_EFI_RT_VOLATILE_STORE
+static const efi_guid_t efi_rt_var_guid = U_BOOT_EFI_RT_VAR_FILE_GUID;
+
+/**
+ * execute() - Execute the single-run volatile-store runtime test
+ *
+ * Run the runtime variable checks that complete in a single invocation when
+ * the runtime store is volatile.
+ *
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
+ */
+static int execute(void)
+{
+ efi_status_t ret;
+ efi_uintn_t len, avail, append_len = 17;
+ u32 attr = 0;
+ u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
+ 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
+ u8 v2[CONFIG_EFI_VAR_BUF_SIZE];
+ u8 data[EFI_ST_MAX_DATA_SIZE];
+ u8 data2[CONFIG_EFI_VAR_BUF_SIZE];
+ efi_uintn_t prev_len, delta;
+ struct efi_var_entry *var;
+ struct efi_var_file *hdr;
+
+ memset(v2, 0x1, sizeof(v2));
+
+ if (check_runtime_query_variable_info("runtime") != EFI_ST_SUCCESS)
+ return EFI_ST_FAILURE;
+
ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
3, v + 4);
- if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
- efi_uintn_t prev_len, delta;
- struct efi_var_entry *var;
- struct efi_var_file *hdr;
-
- /* At runtime only non-volatile variables may be set. */
- if (ret != EFI_INVALID_PARAMETER) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- /* runtime attribute must be set */
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- 3, v + 4);
- if (ret != EFI_INVALID_PARAMETER) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* At runtime only non-volatile variables may be set. */
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- len = sizeof(data);
- ret = st_runtime->get_variable(u"RTStorageVolatile",
- &efi_rt_var_guid, &attr, &len,
- data);
- if (ret != EFI_SUCCESS) {
- efi_st_error("GetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* runtime attribute must be set */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 3, v + 4);
+ if (ret != EFI_INVALID_PARAMETER) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- if (len != sizeof(EFI_VAR_FILE_NAME) ||
- memcmp(data, EFI_VAR_FILE_NAME, sizeof(EFI_VAR_FILE_NAME))) {
- data[len - 1] = 0;
- efi_st_error("RTStorageVolatile = %s\n", data);
- return EFI_ST_FAILURE;
- }
+ len = sizeof(data);
+ ret = st_runtime->get_variable(u"RTStorageVolatile", &efi_rt_var_guid,
+ &attr, &len, data);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- len = sizeof(data2);
- ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
- &attr, &len, data2);
- if (ret != EFI_SUCCESS) {
- efi_st_error("GetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- /*
- * VarToFile size must change once a variable is inserted
- * Store it now, we'll use it later
- */
- prev_len = len;
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- sizeof(v2), v2);
- /*
- * This will try to update VarToFile as well and must fail,
- * without changing or deleting VarToFile
- */
- if (ret != EFI_OUT_OF_RESOURCES) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- len = sizeof(data2);
- ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
- &attr, &len, data2);
- if (ret != EFI_SUCCESS || prev_len != len) {
- efi_st_error("Get/SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ if (len != sizeof(EFI_VAR_FILE_NAME) ||
+ memcmp(data, EFI_VAR_FILE_NAME, sizeof(EFI_VAR_FILE_NAME))) {
+ data[len - 1] = 0;
+ efi_st_error("RTStorageVolatile = %s\n", data);
+ return EFI_ST_FAILURE;
+ }
- /* Add an 8byte aligned variable */
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- sizeof(v), v);
- if (ret != EFI_SUCCESS) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ len = sizeof(data2);
+ ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
+ &attr, &len, data2);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ /*
+ * VarToFile size must change once a variable is inserted
+ * Store it now, we'll use it later
+ */
+ prev_len = len;
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof(v2), v2);
+ /*
+ * This will try to update VarToFile as well and must fail,
+ * without changing or deleting VarToFile
+ */
+ if (ret != EFI_OUT_OF_RESOURCES) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ len = sizeof(data2);
+ ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
+ &attr, &len, data2);
+ if (ret != EFI_SUCCESS || prev_len != len) {
+ efi_st_error("Get/SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- /* Delete it by setting the attrs to 0 */
- ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0, 0,
- sizeof(v), v);
- if (ret != EFI_SUCCESS) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* Add an 8byte aligned variable */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof(v), v);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- /* Add it back */
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- sizeof(v), v);
- if (ret != EFI_SUCCESS) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* Delete it by setting the attrs to 0 */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0, 0,
+ sizeof(v), v);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- /* Delete it again by setting the size to 0 */
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- 0, NULL);
- if (ret != EFI_SUCCESS) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* Add it back */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof(v), v);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- /* Delete it again and make sure it's not there */
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- 0, NULL);
- if (ret != EFI_NOT_FOUND) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* Delete it again by setting the size to 0 */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 0, NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- /*
- * Add a non-aligned variable
- * VarToFile updates must include efi_st_var0
- */
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- 9, v + 4);
- if (ret != EFI_SUCCESS) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- var = efi_var_mem_find(&guid_vendor0, u"efi_st_var0", NULL);
- if (!var) {
- efi_st_error("GetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- delta = efi_var_entry_len(var);
- len = sizeof(data2);
- ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
- &attr, &len, data2);
- if (ret != EFI_SUCCESS || prev_len + delta != len) {
- efi_st_error("Get/SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* Delete it again and make sure it's not there */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 0, NULL);
+ if (ret != EFI_NOT_FOUND) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
- /*
- * Append on an existing variable must update VarToFile
- * Our variable entries are 8-byte aligned.
- * Adding a single byte will fit on the existing space
- */
- prev_len = len;
- avail = efi_var_entry_len(var) -
- (sizeof(u16) * (u16_strlen(var->name) + 1) +
- sizeof(*var)) -
- var->length;
- if (avail >= append_len)
- delta = 0;
- else
- delta = ALIGN(append_len - avail, 8);
- ret = st_runtime->set_variable(
- u"efi_st_var0", &guid_vendor0,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_APPEND_WRITE |
- EFI_VARIABLE_NON_VOLATILE,
- append_len, v2);
- if (ret != EFI_SUCCESS) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- len = sizeof(data2);
- ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
- &attr, &len, data2);
+ /*
+ * Add a non-aligned variable
+ * VarToFile updates must include efi_st_var0
+ */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 9, v + 4);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ var = efi_var_mem_find(&guid_vendor0, u"efi_st_var0", NULL);
+ if (!var) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ delta = efi_var_entry_len(var);
+ len = sizeof(data2);
+ ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
+ &attr, &len, data2);
+ if (ret != EFI_SUCCESS || prev_len + delta != len) {
+ efi_st_error("Get/SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /*
+ * Append on an existing variable must update VarToFile
+ * Our variable entries are 8-byte aligned.
+ * Adding a single byte will fit on the existing space
+ */
+ prev_len = len;
+ avail = efi_var_entry_len(var) -
+ (sizeof(u16) * (u16_strlen(var->name) + 1) +
+ sizeof(*var)) -
+ var->length;
+ if (avail >= append_len)
+ delta = 0;
+ else
+ delta = ALIGN(append_len - avail, 8);
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_APPEND_WRITE |
+ EFI_VARIABLE_NON_VOLATILE,
+ append_len, v2);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ len = sizeof(data2);
+ ret = st_runtime->get_variable(u"VarToFile", &efi_rt_var_guid,
+ &attr, &len, data2);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("GetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+ if (prev_len + delta != len) {
+ efi_st_error("Unexpected VarToFile size");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Make sure that variable contains a valid file */
+ hdr = (struct efi_var_file *)data2;
+ if (hdr->magic != EFI_VAR_FILE_MAGIC || len != hdr->length ||
+ hdr->crc32 != crc32(0,
+ (u8 *)((uintptr_t)data2 +
+ sizeof(struct efi_var_file)),
+ len - sizeof(struct efi_var_file))) {
+ efi_st_error("VarToFile invalid header\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Variables that are BS, RT and volatile are RO after EBS */
+ ret = st_runtime->set_variable(u"VarToFile", &efi_rt_var_guid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof(v), v);
+ if (ret != EFI_WRITE_PROTECTED) {
+ efi_st_error("Get/SetVariable failed\n");
+ return EFI_ST_FAILURE;
+ }
+
+ return check_runtime_variable_enumeration("runtime");
+}
+
+EFI_UNIT_TEST(variables_run) = {
+ .name = "variables at runtime",
+ .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
+ .execute = execute,
+};
+#else
+/**
+ * execute_setup() - Prepare the non-volatile runtime-variable test state
+ *
+ * Create the persistent variable state consumed by execute_verify() after a
+ * reboot and make the reboot boundary explicit to the caller.
+ *
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
+ */
+static int execute_setup(void)
+{
+ efi_status_t ret;
+ efi_uintn_t len;
+ u32 attr = 0;
+ u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
+ 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
+ u8 data[EFI_ST_MAX_DATA_SIZE];
+
+ /* Check if the setup variable already exists in non-volatile storage. */
+ len = sizeof(data);
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
+ &attr, &len, data);
+ if (ret == EFI_SUCCESS && len == sizeof(v) / 2 && !memcmp(data, v, len)) {
+ efi_st_printf("setup: efi_st_var0 ready, run verify\n");
+ return EFI_ST_SUCCESS;
+ }
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
+ /* Delete a stale variable before recreating the setup state. */
+ if (!attr)
+ attr = EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE;
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ attr, 0, NULL);
if (ret != EFI_SUCCESS) {
- efi_st_error("GetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- if (prev_len + delta != len) {
- efi_st_error("Unexpected VarToFile size");
+ efi_st_error("setup: failed to delete stale efi_st_var0, status=%lx\n",
+ (ulong)ret);
return EFI_ST_FAILURE;
}
+ } else if (ret != EFI_NOT_FOUND) {
+ efi_st_error("setup: failed to inspect existing efi_st_var0, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
- /* Make sure that variable contains a valid file */
- hdr = (struct efi_var_file *)data2;
- if (hdr->magic != EFI_VAR_FILE_MAGIC || len != hdr->length ||
- hdr->crc32 != crc32(0,
- (u8 *)((uintptr_t)data2 +
- sizeof(struct efi_var_file)),
- len - sizeof(struct efi_var_file))) {
- efi_st_error("VarToFile invalid header\n");
- return EFI_ST_FAILURE;
- }
+ /* QueryVariableInfo */
+ if (check_runtime_query_variable_info("setup") != EFI_ST_SUCCESS)
+ return EFI_ST_FAILURE;
- /* Variables that are BS, RT and volatile are RO after EBS */
- ret = st_runtime->set_variable(
- u"VarToFile", &efi_rt_var_guid,
- EFI_VARIABLE_BOOTSERVICE_ACCESS |
- EFI_VARIABLE_RUNTIME_ACCESS |
- EFI_VARIABLE_NON_VOLATILE,
- sizeof(v), v);
- if (ret != EFI_WRITE_PROTECTED) {
- efi_st_error("Get/SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
- } else {
- if (ret != EFI_UNSUPPORTED) {
- efi_st_error("SetVariable failed\n");
- return EFI_ST_FAILURE;
- }
+ /* Create and delete a volatile runtime variable. */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 3, v + 4);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("setup: failed to create volatile efi_st_var0, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
}
- len = EFI_ST_MAX_DATA_SIZE;
- ret = st_runtime->get_variable(u"PlatformLangCodes", &guid_vendor0,
+
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS,
+ 0, NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("setup: failed to delete volatile efi_st_var0, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Create the non-volatile variable that verify expects after reboot. */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ sizeof(v) / 2, v);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("setup: failed to create non-volatile efi_st_var0, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Check variable enumeration while the setup variable is present. */
+ if (check_runtime_variable_enumeration("setup") != EFI_ST_SUCCESS) {
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 0, NULL);
+ if (ret != EFI_SUCCESS)
+ efi_st_error("setup: enumeration failed and cleanup returned status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ efi_st_printf("Reboot and run 'variables at runtime verify'\n");
+
+ return EFI_ST_SUCCESS;
+}
+
+/**
+ * execute_verify() - Verify the non-volatile runtime-variable test state
+ *
+ * Validate the state created by execute_setup(), append the remaining
+ * payload, confirm the full value, and remove the test variable.
+ *
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
+ */
+static int execute_verify(void)
+{
+ efi_status_t ret;
+ efi_uintn_t len, append_len;
+ u32 attr = 0;
+ u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c,
+ 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,};
+ u8 data[EFI_ST_MAX_DATA_SIZE];
+
+ /* Validate the non-volatile variable created by setup. */
+ len = sizeof(v) / 2;
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
&attr, &len, data);
+ if (ret == EFI_NOT_FOUND) {
+ efi_st_error("verify: efi_st_var0 missing, run setup first\n");
+ return EFI_ST_FAILURE;
+ }
if (ret != EFI_SUCCESS) {
- efi_st_error("GetVariable failed\n");
+ efi_st_error("verify: failed to read prepared efi_st_var0, status=%lx\n",
+ (ulong)ret);
return EFI_ST_FAILURE;
}
- memset(&guid, 0, 16);
- *varname = 0;
- len = 2 * EFI_ST_MAX_VARNAME_SIZE;
- ret = st_runtime->get_next_variable_name(&len, varname, &guid);
+ if (len != sizeof(v) / 2) {
+ efi_st_error("verify: unexpected prepared variable size=%lu\n",
+ (ulong)len);
+ return EFI_ST_FAILURE;
+ }
+ if (memcmp(data, v, len)) {
+ efi_st_error("verify: prepared variable contents do not match setup payload\n");
+ return EFI_ST_FAILURE;
+ }
+
+ /* Append the remaining payload. */
+ append_len = sizeof(v) - len;
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_APPEND_WRITE |
+ EFI_VARIABLE_NON_VOLATILE,
+ append_len, v + len);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("verify: failed to append remaining payload, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Validate the full variable contents after append. */
+ len = sizeof(v);
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
+ &attr, &len, data);
if (ret != EFI_SUCCESS) {
- efi_st_error("GetNextVariableName failed\n");
+ efi_st_error("verify: failed to read appended efi_st_var0, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+ if (len != sizeof(v)) {
+ efi_st_error("verify: unexpected appended variable size=%lu\n",
+ (ulong)len);
+ return EFI_ST_FAILURE;
+ }
+ if (memcmp(data, v, len)) {
+ efi_st_error("verify: appended variable contents do not match expected payload\n");
return EFI_ST_FAILURE;
}
+ /* Delete the test variable. */
+ ret = st_runtime->set_variable(u"efi_st_var0", &guid_vendor0,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE,
+ 0, NULL);
+ if (ret != EFI_SUCCESS) {
+ efi_st_error("verify: failed to delete efi_st_var0, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ /* Make sure the variable is no longer present. */
+ len = sizeof(data);
+ ret = st_runtime->get_variable(u"efi_st_var0", &guid_vendor0,
+ &attr, &len, data);
+ if (ret != EFI_NOT_FOUND) {
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL)
+ efi_st_error("verify: efi_st_var0 still exists after delete\n");
+ else
+ efi_st_error("verify: failed to confirm deletion, status=%lx\n",
+ (ulong)ret);
+ return EFI_ST_FAILURE;
+ }
+
+ efi_st_printf("verify: runtime variable test passed\n");
+
return EFI_ST_SUCCESS;
}
-EFI_UNIT_TEST(variables_run) = {
- .name = "variables at runtime",
+EFI_UNIT_TEST(variables_run_setup) = {
+ .name = "variables at runtime setup",
.phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
- .execute = execute,
+ .execute = execute_setup,
+ .on_request = true,
+};
+
+EFI_UNIT_TEST(variables_run_verify) = {
+ .name = "variables at runtime verify",
+ .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT,
+ .execute = execute_verify,
+ .on_request = true,
};
+#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 09/11] test: dm: add sandbox FF-A runtime transport tests
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (7 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 08/11] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:27 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 10/11] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 11/11] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
Exercise FF-A runtime helpers via sandbox DM tests
Test the successful runtime direct-message round trip and the invalid
destination-partition case, using the shared FF-A prepare step so the
sandbox emulator has initialized partition state before exercising the
runtime-only messaging helpers.
Add a dedicated no-context test that calls
ffa_sync_send_receive_runtime() before enabling the runtime context and
checks that it returns -EPERM. Reset the resident FF-A runtime context
around the transport tests so the runtime flag and private data do not
leak across test cases.
Split the ffa_to_std_errno() checks into a separate DM test so
error-mapping regressions are reported independently from transport
failures. Cover both the valid mappings and the boundary inputs that
must return -EINVAL.
Replace the hard-coded synthetic partition execution-context and
property values in ffa-emul-uclass.c with the shared
SANDBOX_SP*_EXEC_CTXT and SANDBOX_SP*_PROPERTIES macros. This lets the
sandbox emulator and tests reuse a single definition of the synthetic
partition metadata.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Drop unused `sp_id` handling from the negative-path test
- Add no-context `-EPERM` coverage
- Reset the FF-A runtime context between tests
- Split errno-mapping checks into a dedicated DM test
- Add invalid-input boundary coverage
arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 ++-
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 ++++--
test/dm/Makefile | 3 +-
test/dm/ffa_runtime.c | 129 +++++++++++++++++++++
4 files changed, 172 insertions(+), 12 deletions(-)
create mode 100644 test/dm/ffa_runtime.c
diff --git a/arch/sandbox/include/asm/sandbox_arm_ffa.h b/arch/sandbox/include/asm/sandbox_arm_ffa.h
index be2790f4960..a20eb159b73 100644
--- a/arch/sandbox/include/asm/sandbox_arm_ffa.h
+++ b/arch/sandbox/include/asm/sandbox_arm_ffa.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -26,6 +26,20 @@
#define SANDBOX_SP3_ID 0x6452
#define SANDBOX_SP4_ID 0x7814
+/*
+ * The sandbox FF-A emulator uses fixed, synthetic execution-context counts and
+ * property bitfields for each partition.
+ */
+#define SANDBOX_SP1_EXEC_CTXT 0x5687
+#define SANDBOX_SP2_EXEC_CTXT 0x9587
+#define SANDBOX_SP3_EXEC_CTXT 0x7687
+#define SANDBOX_SP4_EXEC_CTXT 0x1487
+
+#define SANDBOX_SP1_PROPERTIES 0x89325621
+#define SANDBOX_SP2_PROPERTIES 0x45325621
+#define SANDBOX_SP3_PROPERTIES 0x23325621
+#define SANDBOX_SP4_PROPERTIES 0x70325621
+
/* Invalid service UUID (no matching SP) */
#define SANDBOX_SERVICE3_UUID "55d532ed-0942-e699-722d-c09ca798d9cd"
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
index d270f7b614e..a8c6d3010eb 100644
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0+
/*
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
@@ -19,41 +19,57 @@
/* The partitions (SPs) table */
static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
{
- .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
+ .info = {
+ .id = SANDBOX_SP1_ID,
+ .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
+ .properties = SANDBOX_SP1_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE1_UUID_A1,
.a2 = SANDBOX_SERVICE1_UUID_A2,
.a3 = SANDBOX_SERVICE1_UUID_A3,
.a4 = SANDBOX_SERVICE1_UUID_A4,
- }
+ },
},
{
- .info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
+ .info = {
+ .id = SANDBOX_SP3_ID,
+ .exec_ctxt = SANDBOX_SP3_EXEC_CTXT,
+ .properties = SANDBOX_SP3_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE2_UUID_A1,
.a2 = SANDBOX_SERVICE2_UUID_A2,
.a3 = SANDBOX_SERVICE2_UUID_A3,
.a4 = SANDBOX_SERVICE2_UUID_A4,
- }
+ },
},
{
- .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
+ .info = {
+ .id = SANDBOX_SP2_ID,
+ .exec_ctxt = SANDBOX_SP2_EXEC_CTXT,
+ .properties = SANDBOX_SP2_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE1_UUID_A1,
.a2 = SANDBOX_SERVICE1_UUID_A2,
.a3 = SANDBOX_SERVICE1_UUID_A3,
.a4 = SANDBOX_SERVICE1_UUID_A4,
- }
+ },
},
{
- .info = { .id = SANDBOX_SP4_ID, .exec_ctxt = 0x1487, .properties = 0x70325621 },
+ .info = {
+ .id = SANDBOX_SP4_ID,
+ .exec_ctxt = SANDBOX_SP4_EXEC_CTXT,
+ .properties = SANDBOX_SP4_PROPERTIES,
+ },
.sp_uuid = {
.a1 = SANDBOX_SERVICE2_UUID_A1,
.a2 = SANDBOX_SERVICE2_UUID_A2,
.a3 = SANDBOX_SERVICE2_UUID_A3,
.a4 = SANDBOX_SERVICE2_UUID_A4,
- }
- }
+ },
+ },
};
diff --git a/test/dm/Makefile b/test/dm/Makefile
index d69b0e08d66..383cec13666 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2013 Google, Inc
-# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
+# Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
# Tests for particular subsystems - when enabling driver model for a new
# subsystem you must add sandbox tests here.
@@ -97,6 +97,7 @@ obj-$(CONFIG_ACPI_PMC) += pmc.o
obj-$(CONFIG_DM_PMIC) += pmic.o
obj-$(CONFIG_DM_PWM) += pwm.o
obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa.o
+obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa_runtime.o
obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_RAM) += ram.o
obj-y += regmap.o
diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
new file mode 100644
index 00000000000..b48a6b363af
--- /dev/null
+++ b/test/dm/ffa_runtime.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Functional tests for FF-A runtime helpers
+ *
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
+ *
+ * Authors:
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
+ */
+
+#include <dm.h>
+#include <dm/test.h>
+#include <asm/sandbox_arm_ffa.h>
+#include <asm/sandbox_arm_ffa_priv.h>
+#include <arm_ffa_runtime.h>
+#include <test/ut.h>
+
+static int ffa_runtime_prepare(struct unit_test_state *uts, u16 *sp_id)
+{
+ struct ffa_partition_desc *descs;
+ u32 count;
+ struct udevice *dev;
+ const char *svc_uuid = SANDBOX_SERVICE1_UUID;
+
+ ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
+ ut_assertok(ffa_partition_info_get(dev, svc_uuid, &count, &descs));
+ ut_assert(count > 0);
+
+ if (sp_id)
+ *sp_id = descs[0].info.id;
+
+ return 0;
+}
+
+static int dm_test_ffa_runtime_no_context(struct unit_test_state *uts)
+{
+ struct ffa_send_direct_data msg = {0};
+ u16 sp_id;
+
+ ffa_reset_runtime_context();
+ ut_assert(!ffa_get_status_runtime_context());
+
+ ut_assertok(ffa_runtime_prepare(uts, &sp_id));
+
+ /* Runtime messaging must fail until the runtime context is enabled */
+ ut_asserteq(-EPERM, ffa_sync_send_receive_runtime(sp_id, &msg, true));
+
+ ffa_reset_runtime_context();
+ return 0;
+}
+
+DM_TEST(dm_test_ffa_runtime_no_context, UTF_SCAN_FDT | UTF_CONSOLE);
+
+static int dm_test_ffa_to_std_errno(struct unit_test_state *uts)
+{
+ (void)uts;
+
+ ut_asserteq(-EINVAL, ffa_to_std_errno(0));
+ ut_asserteq(-EINVAL, ffa_to_std_errno(MAX_NUMBER_FFA_ERR));
+ ut_asserteq(-EINVAL, ffa_to_std_errno(-MAX_NUMBER_FFA_ERR));
+ ut_asserteq(-EINVAL, ffa_to_std_errno(-(MAX_NUMBER_FFA_ERR + 1)));
+
+ ut_asserteq(-EINVAL, ffa_to_std_errno(-INVALID_PARAMETERS));
+ ut_asserteq(-EOPNOTSUPP, ffa_to_std_errno(-NOT_SUPPORTED));
+
+ return 0;
+}
+
+DM_TEST(dm_test_ffa_to_std_errno, UTF_SCAN_FDT | UTF_CONSOLE);
+
+static int dm_test_ffa_runtime_ack(struct unit_test_state *uts)
+{
+ struct ffa_send_direct_data msg = {0};
+ u16 sp_id;
+ u8 cnt;
+
+ ffa_reset_runtime_context();
+ ut_assert(!ffa_get_status_runtime_context());
+
+ ut_assertok(ffa_runtime_prepare(uts, &sp_id));
+
+ ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
+ .id = NS_PHYS_ENDPOINT_ID,
+ });
+ ffa_enable_runtime_context();
+
+ /* Ensure runtime context is available before attempting runtime-only paths */
+ ut_assert(ffa_get_status_runtime_context());
+
+ /* Runtime messaging should reuse the sandbox emulator and return 0xff pattern */
+ ut_assertok(ffa_sync_send_receive_runtime(sp_id, &msg, true));
+ for (cnt = 0; cnt < sizeof(struct ffa_send_direct_data) / sizeof(u64); cnt++)
+ ut_asserteq_64(-1UL, ((u64 *)&msg)[cnt]);
+
+ ffa_reset_runtime_context();
+ return 0;
+}
+
+DM_TEST(dm_test_ffa_runtime_ack, UTF_SCAN_FDT | UTF_CONSOLE);
+
+static int dm_test_ffa_runtime_nack(struct unit_test_state *uts)
+{
+ struct ffa_send_direct_data msg = {0};
+
+ ffa_reset_runtime_context();
+ ut_assert(!ffa_get_status_runtime_context());
+
+ /*
+ * Prime the sandbox partition table so the invalid-ID path reaches
+ * the emulator's validation logic with initialized partition state.
+ */
+ ut_assertok(ffa_runtime_prepare(uts, NULL));
+
+ ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
+ .id = NS_PHYS_ENDPOINT_ID,
+ });
+ ffa_enable_runtime_context();
+
+ /* Ensure runtime context is available before attempting runtime-only paths */
+ ut_assert(ffa_get_status_runtime_context());
+
+ /* Invalid partition IDs must be rejected and mapped to -EINVAL */
+ ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0, &msg, true));
+
+ ffa_reset_runtime_context();
+ return 0;
+}
+
+DM_TEST(dm_test_ffa_runtime_nack, UTF_SCAN_FDT | UTF_CONSOLE);
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 10/11] doc: arm64: document FF-A runtime path for EFI variables
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (8 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 09/11] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:30 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 11/11] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
The arm64 FF-A documentation still said EFI runtime support was a
future development, so readers had no description of the current FF-A
runtime transport or how EFI runtime variable services use it.
Document the FF-A runtime transport, the shared MM communication path,
and the EFI runtime variable flow on arm64. Also clarify that the
armffa command is boot-time only and point readers to the architecture
documentation for EFI runtime variable services over FF-A.
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Normalize `Secure world` capitalization
- Drop low-level cache-maintenance detail
- Remove internal helper names from the public flow
- Refresh `doc/usage/cmd/armffa.rst` to match final wording
doc/arch/arm64.ffa.rst | 86 ++++++++++++++++++++++++++++++++++++----
doc/usage/cmd/armffa.rst | 11 +++++
2 files changed, 90 insertions(+), 7 deletions(-)
diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
index f966f8ba6af..e9a5375ce24 100644
--- a/doc/arch/arm64.ffa.rst
+++ b/doc/arch/arm64.ffa.rst
@@ -15,10 +15,10 @@ application in S-EL0, or a Trusted OS in S-EL1.
The U-Boot FF-A support (the bus) implements the interfaces to communicate
with partitions in the Secure world aka Secure partitions (SPs).
-The FF-A support specifically focuses on communicating with SPs that
-isolate portions of EFI runtime services that must run in a protected
-environment which is inaccessible by the Host OS or Hypervisor.
-Examples of such services are set/get variables.
+U-Boot's FF-A bus support exposes an optional transport that EFI runtime
+services can use to communicate with Secure partitions. Through this
+interface, EFI services (such as variable access) can request or exchange
+data with the Secure world using FF-A.
The FF-A support uses the SMC ABIs defined by the FF-A specification to:
@@ -26,13 +26,13 @@ The FF-A support uses the SMC ABIs defined by the FF-A specification to:
- Access an SP's service through communication protocols
e.g. EFI MM communication protocol
-At this stage of development only EFI boot-time services are supported.
-Runtime support will be added in future developments.
-
The U-Boot FF-A support provides the following parts:
- A Uclass driver providing generic FF-A methods.
- An Arm FF-A device driver providing Arm-specific methods and reusing the Uclass methods.
+- An optional runtime FF-A transport (toggled via CONFIG_ARM_FFA_RT_MODE) that is
+ resident after ExitBootServices() and enables EFI runtime variable services
+ via FF-A helpers and a shared MM communication buffer.
- A sandbox emulator for Arm FF-A, emulates the FF-A side of the Secure World and provides
FF-A ABIs inspection methods.
- An FF-A sandbox device driver for FF-A communication with the emulated Secure World.
@@ -69,6 +69,12 @@ CONFIG_ARM_FFA_TRANSPORT
When using an Arm 64-bit platform, the Arm FF-A driver will be used.
When using sandbox, the sandbox FF-A emulator and FF-A sandbox driver will be used.
+CONFIG_ARM_FFA_RT_MODE
+ Enables the FF-A runtime transport. This option depends on
+ CONFIG_ARM_FFA_TRANSPORT and CONFIG_EFI_LOADER, and is enabled by default.
+ When enabled, a minimal set of FF-A operations remains available after
+ ExitBootServices().
+
FF-A ABIs under the hood
------------------------
@@ -158,6 +164,71 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
the 32-bit or 64-bit version of FFA_MSG_SEND_DIRECT_{REQ, RESP}.
The calling convention between U-Boot and the secure world stays the same: SMC32.
+FF-A runtime support for EFI variables
+--------------------------------------
+
+U-Boot provides an FF-A runtime transport to keep a minimal set of FF-A operations
+available after ExitBootServices(). This runtime transport is enabled with
+CONFIG_ARM_FFA_RT_MODE. The runtime helpers and data are marked with
+``__efi_runtime`` / ``__efi_runtime_data`` through the
+``__ffa_runtime`` / ``__ffa_runtime_data`` aliases in
+``include/arm_ffa_runtime.h``.
+
+Runtime context is enabled at ExitBootServices(), and the following prerequisites
+are prepared during FF-A bus probe:
+
+- The U-Boot FF-A endpoint ID is discovered at boot time with FFA_ID_GET and
+ stored in the runtime private data.
+- An ExitBootServices() event is registered by the FF-A runtime transport so
+ the resident runtime context is enabled when EFI transitions to runtime.
+
+At runtime, the driver model is no longer available. Runtime users should
+use the resident FF-A runtime transport, which verifies the runtime context
+before issuing FF-A calls.
+
+EFI variable services over FF-A
+-------------------------------
+
+When CONFIG_EFI_MM_COMM_TEE and CONFIG_ARM_FFA_TRANSPORT are enabled, U-Boot
+routes EFI variable services to an MM Secure Partition (SP) over FF-A.
+The MM SP is discovered at boot time using FFA_PARTITION_INFO_GET and its
+partition ID is cached in runtime data.
+
+The data path uses a shared MM communication buffer and a door-bell style
+direct message:
+
+- The communication buffer is located at CONFIG_FFA_SHARED_MM_BUF_ADDR and
+ sized by CONFIG_FFA_SHARED_MM_BUF_SIZE.
+- CONFIG_FFA_SHARED_MM_BUF_OFFSET is sent in the FF-A direct message payload
+ to indicate where the data begins.
+
+After ExitBootServices(), EFI SetVariable()/GetVariable() call paths use the
+runtime MM communication path:
+
+- A pre-reserved shared buffer is used for the MM communication payload.
+- The cached MM SP partition ID and FF-A runtime transport are used to
+ dispatch direct FF-A messages to the Secure world after
+ ExitBootServices().
+
+Configuration notes
+-------------------
+
+Enable FF-A transport and MM communication:
+
+- CONFIG_ARM_FFA_TRANSPORT
+- CONFIG_ARM_FFA_RT_MODE
+- CONFIG_EFI_MM_COMM_TEE
+
+CONFIG_ARM_FFA_RT_MODE is enabled by default. It turns on MM communication for
+EFI runtime and may be disabled when EFI services over FF-A are not required
+after ExitBootServices().
+
+Configure the shared MM communication buffer:
+
+- CONFIG_FFA_SHARED_MM_BUF_ADDR
+- CONFIG_FFA_SHARED_MM_BUF_SIZE
+- CONFIG_FFA_SHARED_MM_BUF_OFFSET
+
Requirements for user drivers
-----------------------------
@@ -256,6 +327,7 @@ For example, when using FF-A with Corstone-1000, debug logs enabled, the output
Contributors
------------
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
.. _`FF-A v1.0 specification`: https://documentation-service.arm.com/static/5fb7e8a6ca04df4095c1d65e
.. _`SMC Calling Convention v1.2 specification`: https://documentation-service.arm.com/static/5f8edaeff86e16515cdbe4c6
diff --git a/doc/usage/cmd/armffa.rst b/doc/usage/cmd/armffa.rst
index dbe4d5bc842..64571d615cb 100644
--- a/doc/usage/cmd/armffa.rst
+++ b/doc/usage/cmd/armffa.rst
@@ -39,6 +39,17 @@ The command also allows to gather secure partitions information and ping these
The command is also helpful in testing the communication with secure partitions.
+Notes
+-----
+
+armffa is a boot-time test command. It relies on the FF-A driver model device
+(UCLASS_FFA) and is not part of the resident FF-A runtime transport used after
+ExitBootServices().
+
+armffa does not provide EFI variable operations. For more information about
+the FF-A runtime transport and EFI runtime variable services over FF-A please see
+:doc:`../../arch/arm64.ffa`.
+
Example
-------
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* [PATCH v2 11/11] doc: bootefi: note two-phase runtime variables selftest
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
` (9 preceding siblings ...)
2026-05-14 12:49 ` [PATCH v2 10/11] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
@ 2026-05-14 12:49 ` Harsimran Singh Tungal
2026-05-15 18:30 ` Simon Glass
10 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 12:49 UTC (permalink / raw)
To: u-boot
Cc: abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg, Harsimran Singh Tungal
The bootefi documentation did not describe how to run the
runtime-variable selftest, so users had no guidance on its reboot
requirements or on which flow applies to their configuration.
Document the runtime-variable selftest flow in bootefi.rst. Describe
the non-volatile path, note the single-run
CONFIG_EFI_RT_VOLATILE_STORE=y case, and show how to select the
runtime-variable selftest with efi_selftest.
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
Changelog:
===============
v2:
Simon:
- Update the doc to match the v2 new efi selftest flow
- Document single-run behavior for volatile-store builds
doc/usage/cmd/bootefi.rst | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
index 7c5448586b7..e44d345cab2 100644
--- a/doc/usage/cmd/bootefi.rst
+++ b/doc/usage/cmd/bootefi.rst
@@ -160,6 +160,33 @@ environment variable to match one of the listed identifiers
Some of the tests execute the ExitBootServices() UEFI boot service and will not
return to the command line but require a board reset.
+When CONFIG_EFI_RT_VOLATILE_STORE is enabled, the test
+*variables at runtime* completes in a single run and does not require
+a reboot.
+
+::
+
+ => setenv efi_selftest 'variables at runtime'
+ => bootefi selftest
+
+When CONFIG_EFI_RT_VOLATILE_STORE is not enabled, the runtime-variable
+flow is split into *variables at runtime setup* and
+*variables at runtime verify*. Run the setup test once to create the
+runtime-accessible variable in non-volatile storage, reboot, then run
+the verify test to validate, append, and delete that variable.
+
+::
+
+ => setenv efi_selftest 'variables at runtime setup'
+ => bootefi selftest
+
+After reboot:
+
+::
+
+ => setenv efi_selftest 'variables at runtime verify'
+ => bootefi selftest
+
Configuration
-------------
--
2.34.1
^ permalink raw reply related [flat|nested] 77+ messages in thread
* Re: [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests
2026-04-28 18:05 ` Simon Glass
@ 2026-05-14 14:58 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 14:58 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:05 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > test: dm: add sandbox FF-A runtime transport tests
> >
> > Exercise FF-A runtime helpers via sandbox DM tests
> >
> > Add driver-model unit tests that exercise the FF-A runtime helpers on
> > sandbox. The new tests reuse the sandbox emulator to validate both the
> > positive direct-request flow and failure handling, priming the emulator
> > state so the runtime path can be executed.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +++++-
> > test/dm/Makefile | 3 +-
> > test/dm/ffa_runtime.c | 82 ++++++++++++++++++++++++++++++
> > 3 files changed, 99 insertions(+), 2 deletions(-)
>
> > diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> > @@ -0,0 +1,82 @@
> > +static int dm_test_ffa_runtime_nack(struct unit_test_state *uts)
> > +{
> > + struct ffa_send_direct_data msg = {0};
> > + u16 sp_id;
> > +
> > + ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
> > +
> > + ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
> > + .id = NS_PHYS_ENDPOINT_ID,
> > + });
> > + ffa_enable_runtime_context();
> > +
> > + /* Ensure runtime context is available before attempting runtime-only paths */
> > + ut_assert(ffa_get_status_runtime_context());
> > +
> > + /* Invalid partition IDs must be rejected and mapped to -EINVAL */
> > + ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0, &msg, true));
>
> sp_id is fetched here but never used - the test sends to id 0
> directly. Please drop the call to ffa_runtime_get_sp_id() in this
> test, or use the discovered id for a positive comparison.
>
Thanks, you are right that sp_id was unused in dm_test_ffa_runtime_nack().
This has been fixed in v2.
Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
> > diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> > @@ -0,0 +1,82 @@
> > +static int dm_test_ffa_runtime_ack(struct unit_test_state *uts)
> > +{
> > + struct ffa_send_direct_data msg = {0};
> > + u16 sp_id;
> > + u8 cnt;
> > +
> > + ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
> > +
> > + ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
> > + .id = NS_PHYS_ENDPOINT_ID,
> > + });
> > + ffa_enable_runtime_context();
>
> ffa_enable_runtime_context() flips a global static flag in
> arm-ffa-runtime.c that is never reset. Once either test has run,
> ffa_get_status_runtime_context() returns true for the rest of the
> process, which leaks state into other tests and means a
> missing-context path can never be reached. Please add a case that
> calls ffa_sync_send_receive_runtime() before enabling the context and
> verifies it returns -EPERM (that branch is currently untested) and
> provide a way to reset the runtime priv between tests.
>
Thanks, good point.
In v2 I added ffa_reset_runtime_context() and use it around the sandbox runtime
tests so the resident FF-A runtime state does not leak across cases.
In v2, I have also added a separate dm_test_ffa_runtime_no_context() test that calls
ffa_sync_send_receive_runtime() before enabling the runtime context and checks for -EPERM.
> > diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> > @@ -0,0 +1,82 @@
> > + /* Validate FF-A error to errno translation helpers */
> > + ut_asserteq(-EINVAL, ffa_to_std_errno(-INVALID_PARAMETERS));
> > + ut_asserteq(-EOPNOTSUPP, ffa_to_std_errno(-NOT_SUPPORTED));
>
> Just to clarify, ffa_to_std_errno() is a pure helper unrelated to the
> messaging round-trip - please split this into its own dm_test, so a
> regression in the table doesn't look like a transport failure, and add
> coverage for at least the boundary cases (e.g. 0, MAX_NUMBER_FFA_ERR,
> an out-of-range value) which all should map to -EINVAL.
>
> Regards,
> Simon
>
Agreed.
In v2 I split the ffa_to_std_errno() checks into a separate dm_test_ffa_to_std_errno() case,
so errno-table regressions are reported independently from the FF-A messaging tests.
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros
2026-04-28 18:07 ` Simon Glass
@ 2026-05-14 15:00 ` Harsimran Singh Tungal
2026-05-15 18:28 ` Simon Glass
0 siblings, 1 reply; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 15:00 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:07 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > sandbox: ffa: share synthetic partition metadata via macros
> >
> > Reuse sandbox FF-A partition constants in emulator tests
> >
> > Allow the sandbox FF-A emulator test to use execution-context and property
> > constants defined in sandbox_arm_ffa.h
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 +++++++++++++++++++++---------
> > 1 file changed, 26 insertions(+), 10 deletions(-)
>
> > diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> > @@ -19,41 +19,57 @@
> > /* The partitions (SPs) table */
> > static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
> > {
> > - .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
> > + .info = {
> > + .id = SANDBOX_SP1_ID,
> > + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> > + .properties = SANDBOX_SP1_PROPERTIES,
> > + },
> > .sp_uuid = {
> > .a1 = SANDBOX_SERVICE1_UUID_A1,
> > ...
> > {
> > - .info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
> > + .info = {
> > + .id = SANDBOX_SP2_ID,
> > + .exec_ctxt = SANDBOX_SP2_EXEC_CTXT,
> > + .properties = SANDBOX_SP2_PROPERTIES,
> > + },
> > .sp_uuid = {
> > .a1 = SANDBOX_SERVICE2_UUID_A1,
> > ...
> > {
> > - .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
> > + .info = {
> > + .id = SANDBOX_SP3_ID,
> > + .exec_ctxt = SANDBOX_SP3_EXEC_CTXT,
> > + .properties = SANDBOX_SP3_PROPERTIES,
> > + },
> > .sp_uuid = {
> > .a1 = SANDBOX_SERVICE1_UUID_A1,
>
> This is not a pure refactor. Index 1 and 2 swap, so SP2 moves from
> SERVICE1 to SERVICE2, and SP3 moves from SERVICE2 to SERVICE1. The
> existing test in test/dm/ffa.c queries by UUID and walks the matching
> SPs, so the set of IDs returned for each service changes.
>
> If the reorder is deliberate (e.g. so the table reads SP1..SP4 in
> numeric order), please call it out in the commit message and confirm
> no downstream test relies on the previous SP-to-UUID mapping.
> Otherwise keep the .id fields where they were and only substitute in
> the macros.
>
> > diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> > @@ -19,41 +19,57 @@
> > + .info = {
> > + .id = SANDBOX_SP1_ID,
> > + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> > + .properties = SANDBOX_SP1_PROPERTIES,
> > + },
>
> The macros being substituted in here are added in patch 8, and nothing
> else in this patch uses them - they exist solely to be consumed by
> this patch. Can you squash 9 into 8 so the macro definitions and their
> first user land together.
>
As suggested,
This patch has been now squashed to previous patch and all the comments
for this commit have been addressed in v2.
Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
Regards
Harsimran Singh Tungal
> > Author: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> >
> > sandbox: ffa: share synthetic partition metadata via macros
> >
> > Reuse sandbox FF-A partition constants in emulator tests
> >
> > Allow the sandbox FF-A emulator test to use execution-context and property
> > constants defined in sandbox_arm_ffa.h
>
> The body reads like two competing subject lines followed by a one-line
> restatement, and none of it explains the motivation. Also, the file
> changed is the emulator itself (ffa-emul-uclass.c), not a test, so 'in
> emulator tests' / 'emulator test' is misleading. Please rewrite to say
> what problem is being solved (e.g. the runtime tests added in 8 need
> to reference the same exec_ctxt/properties values, so the magic
> numbers are pulled out into shared macros) and drop the duplicate
> sentence.
>
> Regards,
> Simon
>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables
2026-04-28 18:08 ` Simon Glass
@ 2026-05-14 15:05 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 15:05 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:08 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > doc: arm64: document FF-A runtime path for EFI variables
> >
> > Document how EFI runtime variables use FF-A MM communication
> >
> > Describe the FF-A runtime layer on arm64 and how EFI variable
> > runtime services use the FF-A transport and shared MM buffer.
> > Also clarify armffa command scope and link to the FF-A doc.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > doc/arch/arm64.ffa.rst | 92 ++++++++++++++++++++++++++++++++++++++++++++----
> > doc/usage/cmd/armffa.rst | 11 ++++++
> > 2 files changed, 96 insertions(+), 7 deletions(-)
>
> > diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> > @@ -15,10 +15,10 @@ application in S-EL0, or a Trusted OS in S-EL1.
> > +U-Boot's FF-A bus support exposes an optional transport that EFI runtime
> > +services can use to communicate with Secure Partitions. Through this
> > +interface, EFI services (such as variable access) can request or exchange
> > +data with the Secure World using FF-A.
>
> The rest of this file uses lower-case 'Secure world' (see lines 12 and
> 16). Please keep the capitalisation consistent throughout the new
> prose — also at the 'Secure World' in the runtime section below.
>
Thanks, I fixed the capitalization in v2.
Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
> > diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> > @@ -158,6 +164,77 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
> > +- The communication buffer is located at CONFIG_FFA_SHARED_MM_BUF_ADDR and
> > + sized by CONFIG_FFA_SHARED_MM_BUF_SIZE.
> > +- CONFIG_FFA_SHARED_MM_BUF_OFFSET is sent in the FF-A direct message payload
> > + to indicate where the data begins.
> > +- The buffer is filled by memcpy(), the cache is flushed before notifying the
> > + MM SP, and later the buffer is reused directly with only the shared-buffer
> > + range invalidated (invalidate_dcache_range()) to avoid whole-cache
> > + invalidation.
>
> This level of cache-maintenance detail is an implementation note and
> will go stale the moment the code is touched (and patch 12 is already
> touching it in this very series). I'd drop the third bullet and let
> the source comments have that, or move it under a clearly marked
> 'Implementation notes' sub-heading so readers know it is informative
> rather than contractual.
>
Thanks, agreed.
In v2, I dropped that cache-maintenance bullet and kept the section focused on the FF-A
runtime/MM buffer interface rather than implementation detail.
> > diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> > @@ -158,6 +164,77 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
> > +- get_comm_buf() switches to the static shared buffer
> > +- mm_communicate_runtime() selects FF-A transport when the runtime context
> > + is enabled
> > +- ffa_mm_communicate_runtime() issues FFA_MSG_SEND_DIRECT_{REQ,RESP} through
> > + ffa_sync_send_receive_runtime()
>
> Naming specific static helpers in a public document ties the doc to
> current internal names. If one is renamed or refactored later, the doc
> silently lies. Please describe the flow at one level higher (e.g. 'the
> runtime path uses a static shared buffer and dispatches direct FF-A
> messages') and leave the function names to the source.
>
Thanks, this makes sense to me.
In v2, I removed the internal helper names from that section and rewrote it at a higher level
in terms of the FF-A runtime transport, the shared MM buffer, and direct FF-A messaging
after ExitBootServices().
> >
> > doc: arm64: document FF-A runtime path for EFI variables
> >
> > Document how EFI runtime variables use FF-A MM communication
> >
> > Describe the FF-A runtime layer on arm64 and how EFI variable
> > runtime services use the FF-A transport and shared MM buffer.
> > Also clarify armffa command scope and link to the FF-A doc.
>
> The single-line paragraph just restates the subject and the next
> paragraph. U-Boot convention is to open with the motivation/problem -
> please replace this with a sentence explaining why the doc was
> previously incomplete (the previous text said runtime support was a
> future development) and what readers gain from the new sections.
>
> Regards,
> Simon
>
This has been updated in v2.
Thanks
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest
2026-04-28 18:14 ` Simon Glass
@ 2026-05-14 15:07 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 15:07 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:14 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > doc: bootefi: note two-phase runtime variables selftest
> >
> > Explain how the runtime variable selftest runs in two phases
> >
> > Document that the "variables at runtime" selftest runs in two
> > phases when CONFIG_EFI_RT_VOLATILE_STORE is not enabled, and
> > show how to select it with efi_selftest.
> >
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > doc/usage/cmd/bootefi.rst | 12 ++++++++++++
> > 1 file changed, 12 insertions(+)
>
> > diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
> > @@ -167,6 +177,8 @@ To use the *bootefi* command you must specify CONFIG_CMD_BOOTEFI=y.
> > The *bootefi bootmgr* sub-command requries CMD_BOOTEFI_BOOTMGR=y.
> > The *bootefi hello* sub-command requries CMD_BOOTEFI_HELLO=y.
> > The *bootefi selftest* sub-command depends on CMD_BOOTEFI_SELFTEST=y.
> > +The *variables at runtime* selftest runs in two phases when
> > +CONFIG\_EFI\_RT\_VOLATILE\_STORE is not enabled.
>
> Please drop this addition. It duplicates what you wrote a few lines
> above and the Configuration section is for build-time CONFIG_ options,
> not runtime test behaviour. Also the backslash-escaped underscores are
> not needed in rST and produce inconsistent rendering compared to the
> plain CONFIG_EFI_RT_VOLATILE_STORE used in the paragraph above.
>
Thanks.
In v2, I dropped that extra Configuration-section note
Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
> > diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
> > @@ -160,6 +160,16 @@ environment variable to match one of the listed identifiers
> > Some of the tests execute the ExitBootServices() UEFI boot service and will not
> > return to the command line but require a board reset.
> >
> > +The test *variables at runtime* runs in two phases when
> > +CONFIG_EFI_RT_VOLATILE_STORE is not enabled. Run it once to create a
> > +runtime-accessible variable in non-volatile storage, reboot, then run it
> > +again to validate, append, and delete that variable.
>
> It would help to also say what happens when
> CONFIG_EFI_RT_VOLATILE_STORE is enabled (single phase, no reboot
> needed) so readers know which path applies to their build. A one-line
> note is enough.
>
Thanks.
In v2, I added a short note for CONFIG_EFI_RT_VOLATILE_STORE=y saying that the variables
at runtime selftest completes in a single run and does not require a reboot, so the doc
now covers both paths.
> > Explain how the runtime variable selftest runs in two phases
> >
> > Document that the "variables at runtime" selftest runs in two
> > phases when CONFIG_EFI_RT_VOLATILE_STORE is not enabled, and
> > show how to select it with efi_selftest.
>
> The first paragraph just restates the subject - please drop it and
> lead with the motivation, then describe what the patch adds. Lines are
> also wrapping well short of 72 columns.
>
> Regards,
> Simon
>
Rewording is done in v2.
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path
2026-04-28 18:14 ` Simon Glass
2026-05-08 10:34 ` Abdellatif El Khlifi
@ 2026-05-14 15:11 ` Harsimran Singh Tungal
1 sibling, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 15:11 UTC (permalink / raw)
To: Simon Glass
Cc: harsimransingh.tungal, u-boot, Abdellatif El Khlifi, Tom Rini,
Ilias Apalodimas, Heinrich Schuchardt, Hugues Kamba Mpiana
On 2026-04-28 12:14 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
> > efi_loader: align FF-A cache maintenance with runtime path
> >
> > Match boot-time FF-A cache handling to runtime behavior
> >
> > The boot-time FF-A MM communication path used invalidate_dcache_all()
> > after copying the message into the shared buffer. This differs from the
> > runtime path, which performs range-based maintenance to avoid global cache
> > operations.
> >
> > Update ffa_mm_communicate() to use the same pattern as the runtime helper:
> > clean the shared buffer range before the SMC and invalidate the same range
> > after the response. This keeps boot-time and runtime behavior consistent
> > and avoids whole-cache invalidation.
> >
> > Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> >
> > lib/efi_loader/efi_variable_tee.c | 33 ++++++++++++++++++++++++++-------
> > 1 file changed, 26 insertions(+), 7 deletions(-)
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > memcpy(virt_shared_buf, comm_buf, tx_data_size);
> >
> > /*
> > - * The secure world might have cache disabled for
> > - * the device region used for shared buffer (which is the case for Optee).
> > - * In this case, the secure world reads the data from DRAM.
> > - * Let's flush the cache so the DRAM is updated with the latest data.
> > + * Shared buffer cache maintenance for FF-A / OP-TEE communication:
> > + *
> > + * NS -> S (request path):
> > + *
> > + * The non-secure side populates the shared buffer. If the buffer is cached
> > + * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
> > + * visible in DDR. Since the secure world typically reads the shared buffer
> > + * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
> > + * must clean the corresponding cache lines to the Point of Coherency (PoC)
> > + * before entering secure world.
> > + *
> > + * S -> NS (response path):
> > + *
> > + * The secure world may update the same shared buffer in DDR. After returning
> > + * to non-secure, any cached copies of that region in NS may be stale. We
> > + * therefore invalidate the shared buffer range after the FF-A call to drop
> > + * those lines and force subsequent reads to fetch the latest data from DDR.
> > */
>
> This 20-line comment is now duplicated verbatim with the one in
> ffa_mm_communicate_runtime() introduced earlier in the series. Please
> factor the clean-before / invalidate-after sequence into a small
> helper (e.g. ffa_mm_buf_pre_call() / ffa_mm_buf_post_call()) so the
> commentary lives in one place and the two paths cannot drift. The
> runtime helper would add the extra 'no whole-cache invalidation after
> ExitBootServices()' note at the call site.
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> > -#ifdef CONFIG_ARM64
> > - invalidate_dcache_all();
> > -#endif
> > + if (IS_ENABLED(CONFIG_ARM64))
> > + flush_dcache_range((unsigned long)virt_shared_buf,
> > + (unsigned long)virt_shared_buf +
> > + CONFIG_FFA_SHARED_MM_BUF_SIZE);
>
> Just to check - flush_dcache_range() and invalidate_dcache_range() on
> arm64 require start and end to be cache-line aligned, otherwise the
> arch code warns and falls back to clean+invalidate of the partial
> lines. CONFIG_FFA_SHARED_MM_BUF_ADDR and _SIZE need to be at least
> CONFIG_SYS_CACHELINE_SIZE aligned - is that documented or enforced
> anywhere? You could use BUILD_BUG_ON() near the call, perhaps?
>
> > diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> > @@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
>
> The commit message body opens with 'Match boot-time FF-A cache
> handling to runtime behavior', which restates the subject. Please drop
> that line and start directly with the problem paragraph per the U-Boot
> convention of leading with motivation.
>
> Regards,
> Simon
>
In v2, ffa_mm_communicate() itself handles both boot time and runtime
capabilities, so this patch is no longer required. This patch has been
removed in v2 but the review comments have been addressed.
Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [00/12] arm64: FF-A runtime transport for EFI variables
2026-04-28 18:16 ` [00/12] " Simon Glass
@ 2026-05-14 15:37 ` Harsimran Singh Tungal
0 siblings, 0 replies; 77+ messages in thread
From: Harsimran Singh Tungal @ 2026-05-14 15:37 UTC (permalink / raw)
To: Simon Glass; +Cc: harsimransingh.tungal, u-boot
On 2026-04-28 12:16 -0600, Simon Glass wrote:
> Hi Harsimran,
>
> On 2026-04-24T17:31:50, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
>
> > efi_loader: align FF-A cache maintenance with runtime path
>
> Patch 12 changes the boot-time path to match the runtime path, but
> sits at the end of the series. Between patch 3 (which introduces the
> runtime cache pattern) and patch 12 the two paths are deliberately
> inconsistent. I'd prefer this alignment before patch 3, so patch 3
> simply adopts the established pattern. It would also make the
> rationale in patch 12's commit message read more naturally. What do
> you think?
>
> Regards,
> Simon
>
In v2, patch 12 is no longer required as ffa_mm_communicate() handles
both boot time and runtime capabilities. Patch 12 is eventually dropped
from v2. Patch 3 of v2 is now taking care of cache related changes.
Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
Regards
Harsimran Singh Tungal
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 01/11] efi_loader: add runtime memset helper
2026-05-14 12:49 ` [PATCH v2 01/11] efi_loader: add runtime memset helper Harsimran Singh Tungal
@ 2026-05-15 18:14 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:14 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: add runtime memset helper
>
> Add efi_memset_runtime() for EFI runtime paths
>
> This keeps buffer initialization in runtime-resident code after
> ExitBootServices() and avoids relying on non-runtime helpers.
>
> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> include/efi_loader.h | 3 +++
> lib/efi_loader/efi_runtime.c | 20 ++++++++++++++++++++
> 2 files changed, 23 insertions(+)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 05/11] charset: mark u16_strsize() as __efi_runtime
2026-05-14 12:49 ` [PATCH v2 05/11] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
@ 2026-05-15 18:21 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:21 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> charset: mark u16_strsize() as __efi_runtime
>
> Mark u16_strsize() as __efi_runtime so it can be called from the EFI
> runtime variable paths added for FF-A/MM communication after
> ExitBootServices().
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> lib/charset.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 06/11] efi_loader: move runtime variable read helpers to efi_variable.c
2026-05-14 12:49 ` [PATCH v2 06/11] efi_loader: move runtime variable read helpers to efi_variable.c Harsimran Singh Tungal
@ 2026-05-15 18:21 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:21 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: move runtime variable read helpers to efi_variable.c
>
> Relocate the generic runtime variable read helpers from
> efi_var_common.c to efi_variable.c.
>
> efi_var_common.c is always built, while efi_variable.c is only built
> when CONFIG_EFI_MM_COMM_TEE is unset. Earlier patches in this series
> add TEE/FF-A-specific runtime read helpers in efi_variable_tee.c.
> Leaving the generic definitions in efi_var_common.c would therefore
> cause a symbol clash in EFI_MM_COMM_TEE builds.
>
> Move efi_get_variable_runtime() and
> efi_get_next_variable_name_runtime() into efi_variable.c so the
> non-TEE backend keeps the generic memory-backed implementations,
> while the TEE/FF-A backend continues to provide its own runtime read
> helpers in efi_variable_tee.c.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> lib/efi_loader/efi_var_common.c | 24 ------------------------
> lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
> 2 files changed, 24 insertions(+), 24 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 07/11] corstone1000: enable bootefi selftest
2026-05-14 12:49 ` [PATCH v2 07/11] corstone1000: enable bootefi selftest Harsimran Singh Tungal
@ 2026-05-15 18:22 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:22 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> corstone1000: enable bootefi selftest
>
> Enable CMD_BOOTEFI_SELFTEST in corstone1000_defconfig so the later
> runtime-variable selftest patch in this series can be exercised on
> Corstone-1000.
>
> Keep CMD_BOOTEFI_HELLO and CMD_POWEROFF explicitly disabled.
> Enabling CMD_BOOTEFI_SELFTEST would otherwise make
> CMD_BOOTEFI_HELLO default to y and pull in CMD_POWEROFF on this
> PSCI-based defconfig. The intent here is to enable the selftest command
> without broadening the rest of the board command set.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> configs/corstone1000_defconfig | 3 +++
> 1 file changed, 3 insertions(+)
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 02/11] arm-ffa: add FF-A bus runtime support
2026-05-14 12:49 ` [PATCH v2 02/11] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
@ 2026-05-15 18:25 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:25 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
Hi Harsimran,
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> arm-ffa: add FF-A bus runtime support
>
> Enable FF-A runtime transport for EFI services
>
> Add the FF-A runtime infrastructure needed after ExitBootServices() so
> EFI runtime services can continue to use the FF-A transport layer.
> Introduce drivers/firmware/arm-ffa/arm-ffa-runtime.c and
> include/arm_ffa_runtime.h with runtime-resident FF-A helpers for
> direct messaging, SMC invocation, and error translation. Add the
> sandbox runtime SMC wrapper, the ARM_FFA_RT_MODE Kconfig option, and
> the ExitBootServices hook that copies the required FF-A runtime data
> into resident storage before enabling the runtime context.
>
> Tag the runtime code and data with __efi_runtime and
> __efi_runtime_data so they remain available after
> ExitBootServices().
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> ----
> [...]
>
> drivers/firmware/arm-ffa/Kconfig | 11 ++
> drivers/firmware/arm-ffa/Makefile | 4 +-
> drivers/firmware/arm-ffa/arm-ffa-runtime.c | 295 +++++++++++++++++++++++++++++
> drivers/firmware/arm-ffa/arm-ffa-uclass.c | 113 ++---------
> drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
> drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 ++
> include/arm_ffa.h | 16 +-
> include/arm_ffa_priv.h | 22 ++-
> include/arm_ffa_runtime.h | 191 +++++++++++++++++++
> test/dm/ffa.c | 6 +-
> 10 files changed, 566 insertions(+), 120 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
> @@ -1024,6 +937,7 @@ int ffa_rxtx_unmap(struct udevice *dev)
> static int ffa_do_probe(struct udevice *dev)
> {
> int ret;
> + struct ffa_priv *uc_priv = dev_get_uclass_priv(dev);
>
> ret = ffa_get_version_hdlr(dev);
> if (ret)
> @@ -1033,6 +947,12 @@ static int ffa_do_probe(struct udevice *dev)
> if (ret)
> return ret;
>
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
> + if (ret)
> + return ret;
> + }
> +
> ret = ffa_get_rxtx_map_features_hdlr(dev);
The event is installed before the rxtx-map and partition-cache steps.
If any of those later steps fail, probe returns nonzero but the EBS
event stays registered against this uc_priv. When ExitBootServices()
fires the notifier still copies priv->rt and calls
ffa_enable_runtime_context(), so runtime FF-A appears ready even
though the bus never finished probing. Either install the event at the
end of probe, or tear it down on the error paths.
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,295 @@
> +#if IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> +static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
> + void *context)
> +{
> + struct ffa_priv *priv = context;
> +
> + if (priv) {
> + ffa_copy_runtime_priv(&priv->rt);
> + } else {
> + log_err("FF-A: runtime data missing, keeping RT mode disabled\n");
> + return;
> + }
> +
> + ffa_enable_runtime_context();
> +}
Please flip this around - the usual U-Boot thing is an early-return guard:
if (!priv) {
log_err("FF-A: runtime data missing, keeping RT mode disabled\n");
return;
}
ffa_copy_runtime_priv(&priv->rt);
ffa_enable_runtime_context();
Also, since the context is set when we create the event, this is
essentially can't happen - drop to log_warn() or an assert.
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,295 @@
> +/* Error mapping declarations */
> +
> +int __ffa_runtime_data ffa_to_std_errmap[MAX_NUMBER_FFA_ERR] = {
> + [NOT_SUPPORTED] = -EOPNOTSUPP,
Only referenced inside ffa_to_std_errno() in this file — please make
it static. Also this is a definition, not a declaration.
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
> @@ -1046,7 +966,6 @@ static int ffa_do_probe(struct udevice *dev)
> ffa_unmap_rxtx_buffers_hdlr(dev);
> return ret;
> }
> -
> return 0;
> }
Unrelated whitespace change - please drop (we normally have a blank
line before the final return in a function).
> diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
> @@ -0,0 +1,295 @@
> +bool __ffa_runtime ffa_get_status_runtime_context(void)
> +{
> + return ffa_runtime_enabled;
> +}
The name reads awkwardly - how about ffa_runtime_is_ready() or
ffa_runtime_context_ready() ?. Same for ffa_enable_runtime_context() /
ffa_reset_runtime_context() if you want to keep them parallel.
> arm-ffa: add FF-A bus runtime support
>
> Enable FF-A runtime transport for EFI services
>
> Add the FF-A runtime infrastructure needed after ExitBootServices() so
> EFI runtime services can continue to use the FF-A transport layer.
> Introduce drivers/firmware/arm-ffa/arm-ffa-runtime.c and
> include/arm_ffa_runtime.h with runtime-resident FF-A helpers for
Please use single quotes rather than backticks throughout the commit
message if you need them at all, also for CONFIG_ARM_FFA_RT_MODE /
efi_memset_runtime() later on. Filenames such as
drivers/firmware/arm-ffa/arm-ffa-runtime.c don't need quoting at all.
Also, the single-line lede ('Enable FF-A runtime transport for EFI
services') is redundant with the paragraph that follows - drop it and
let the first paragraph carry the motivation.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 04/11] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
2026-05-14 12:49 ` [PATCH v2 04/11] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
@ 2026-05-15 18:26 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:26 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
Hi Harsimran,
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport
>
> Route EFI runtime variable APIs through FF-A MM communication
>
> Route EFI runtime variable services through the FF-A/MM backend in
> lib/efi_loader/efi_variable_tee.c. After ExitBootServices(),
> GetVariable(), SetVariable(), GetNextVariableName(), and
> QueryVariableInfo() use the runtime entry points and continue to reach
> the MM secure partition.
>
> Keep the existing boot-time helpers unchanged and add runtime service
> wrappers for variable access and property handling. Reuse the
> runtime-safe setup_mm_hdr() and common mm_communicate() path, which
> selects the FF-A transport appropriate for the current phase, and use
> the EFI runtime-safe memory helpers in the runtime-only code.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> lib/efi_loader/efi_variable_tee.c | 320 +++++++++++++++++++++++++++++++++++++-
> 1 file changed, 315 insertions(+), 5 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -830,6 +905,95 @@ out:
> +efi_status_t __efi_runtime efi_get_variable_runtime(u16 *variable_name,
> + const efi_guid_t *vendor,
> + u32 *attributes,
> + efi_uintn_t *data_size,
> + void *data)
EFIAPI is missing so this will break on x86_64 where there is a
different ABI. Same for efi_get_next_variable_name_runtime() below -
please match efi_set_variable_runtime() /
efi_query_variable_info_runtime() which already carry EFIAPI.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -743,6 +775,49 @@ out:
> + ret = mm_communicate(comm_buf, payload_size);
> + /*
> + * Currently only R/O property is supported in StMM.
> + * Variables that are not set to R/O will not set the property in StMM
> + * and the call will return EFI_NOT_FOUND. We are setting the
> + * properties to 0x0 so checking against that is enough for the
> + * EFI_NOT_FOUND case.
> + */
> + if (ret == EFI_NOT_FOUND)
> + ret = EFI_SUCCESS;
> + if (ret != EFI_SUCCESS)
> + return ret;
> + efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
When EFI_NOT_FOUND is mapped to EFI_SUCCESS we still fall through and
memcpy smm_property->property over the zeroed var_property - at
runtime smm_property aliases the FF-A shared buffer, so whatever the
SP left in those bytes ends up in var_property and undoes the memset
above. Either move the memcpy under an explicit found branch, or skip
it on the NOT_FOUND-mapped-to-SUCCESS path. The boot-time copy doesn't
matter because the SP fills the response into the local buffer; here
the shared buffer is the response.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -1067,7 +1319,65 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> + if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
> + var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
> + var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
> + var_property.attributes = attributes;
> + var_property.minsize = 1;
> + var_property.maxsize = var_acc->data_size;
> + ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
> + }
Just to check - at runtime var_acc points into the FF-A shared buffer,
and the preceding mm_communicate() has already let the SP write its
response there, so var_acc->data_size is whatever the SP reported (and
may be 0 on failure). Is that what we want as maxsize, or should this
be the original data_size argument? Please confirm the SP guarantees
data_size on the way out for SET_VARIABLE before relying on it.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 09/11] test: dm: add sandbox FF-A runtime transport tests
2026-05-14 12:49 ` [PATCH v2 09/11] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
@ 2026-05-15 18:27 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:27 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
Hi Harsimran,
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> test: dm: add sandbox FF-A runtime transport tests
>
> Exercise FF-A runtime helpers via sandbox DM tests
>
> Test the successful runtime direct-message round trip and the invalid
> destination-partition case, using the shared FF-A prepare step so the
> sandbox emulator has initialized partition state before exercising the
> runtime-only messaging helpers.
> Add a dedicated no-context test that calls
> ffa_sync_send_receive_runtime() before enabling the runtime context and
> checks that it returns -EPERM. Reset the resident FF-A runtime context
> around the transport tests so the runtime flag and private data do not
> leak across test cases.
> Split the ffa_to_std_errno() checks into a separate DM test so
> error-mapping regressions are reported independently from transport
> failures. Cover both the valid mappings and the boundary inputs that
> must return -EINVAL.
>
> Replace the hard-coded synthetic partition execution-context and
> property values in ffa-emul-uclass.c with the shared
> [...]
>
> arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 +++-
> drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 +++++---
> test/dm/Makefile | 3 +-
> test/dm/ffa_runtime.c | 129 +++++++++++++++++++++++++++++
> 4 files changed, 172 insertions(+), 12 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
> diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> @@ -0,0 +1,129 @@
> +static int dm_test_ffa_to_std_errno(struct unit_test_state *uts)
> +{
> + (void)uts;
> +
> + ut_asserteq(-EINVAL, ffa_to_std_errno(0));
(void)uts is incorrect - uts is used by the ut_asserteq() macro
expansions. Please drop it.
> diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> @@ -0,0 +1,129 @@
> + ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
> + .id = NS_PHYS_ENDPOINT_ID,
> + });
> + ffa_enable_runtime_context();
Twice you do reset + prepare + copy + enable + assert + reset. Please
pull this into a small helper (e.g. ffa_runtime_setup()) with matching
teardown, so the two tests can't drift and a failed assertion mid-test
doesn't leak the runtime flag into later tests.
> diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
> @@ -0,0 +1,129 @@
> + /* Invalid partition IDs must be rejected and mapped to -EINVAL */
> + ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0, &msg, true));
Just to clarify, this works because NS_PHYS_ENDPOINT_ID happens to be
0, so the emulator's self-ID check trips first rather than the SP
validity check. Please pick a clearly-invalid partition ID (e.g.
0xffff) so the test exercises the intended rejection path.
> diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> @@ -19,41 +19,57 @@
> /* The partitions (SPs) table */
> static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
> {
> - .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
> + .info = {
> + .id = SANDBOX_SP1_ID,
> + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> + .properties = SANDBOX_SP1_PROPERTIES,
> + },
This refactor (lifting exec_ctxt/properties into SANDBOX_SP*_EXEC_CTXT
/ SANDBOX_SP*_PROPERTIES) is unrelated to the runtime tests - none of
the new tests reference these macros. Please split it into a
preparatory patch.
> diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> @@ -19,41 +19,57 @@
> - }
> - }
> + },
> + },
>
> };
Stray blank line between the last entry and the closing }; — while you
are reflowing this table, please drop it.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros
2026-05-14 15:00 ` Harsimran Singh Tungal
@ 2026-05-15 18:28 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:28 UTC (permalink / raw)
To: Harsimran Singh Tungal
Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
Heinrich Schuchardt, Hugues Kamba Mpiana
Hi Harsimran,
On Thu, 14 May 2026 at 09:00, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
> On 2026-04-28 12:07 -0600, Simon Glass wrote:
> > Hi Harsimran,
> >
> > On 2026-04-24T17:31:50, Harsimran Singh Tungal
> > <harsimransingh.tungal@arm.com> wrote:
> > > sandbox: ffa: share synthetic partition metadata via macros
> > >
> > > Reuse sandbox FF-A partition constants in emulator tests
> > >
> > > Allow the sandbox FF-A emulator test to use execution-context and property
> > > constants defined in sandbox_arm_ffa.h
> > >
> > > Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
> > >
> > > drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 +++++++++++++++++++++---------
> > > 1 file changed, 26 insertions(+), 10 deletions(-)
> >
> > > diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> > > @@ -19,41 +19,57 @@
> > > /* The partitions (SPs) table */
> > > static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
> > > {
> > > - .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
> > > + .info = {
> > > + .id = SANDBOX_SP1_ID,
> > > + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> > > + .properties = SANDBOX_SP1_PROPERTIES,
> > > + },
> > > .sp_uuid = {
> > > .a1 = SANDBOX_SERVICE1_UUID_A1,
> > > ...
> > > {
> > > - .info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
> > > + .info = {
> > > + .id = SANDBOX_SP2_ID,
> > > + .exec_ctxt = SANDBOX_SP2_EXEC_CTXT,
> > > + .properties = SANDBOX_SP2_PROPERTIES,
> > > + },
> > > .sp_uuid = {
> > > .a1 = SANDBOX_SERVICE2_UUID_A1,
> > > ...
> > > {
> > > - .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
> > > + .info = {
> > > + .id = SANDBOX_SP3_ID,
> > > + .exec_ctxt = SANDBOX_SP3_EXEC_CTXT,
> > > + .properties = SANDBOX_SP3_PROPERTIES,
> > > + },
> > > .sp_uuid = {
> > > .a1 = SANDBOX_SERVICE1_UUID_A1,
> >
> > This is not a pure refactor. Index 1 and 2 swap, so SP2 moves from
> > SERVICE1 to SERVICE2, and SP3 moves from SERVICE2 to SERVICE1. The
> > existing test in test/dm/ffa.c queries by UUID and walks the matching
> > SPs, so the set of IDs returned for each service changes.
> >
> > If the reorder is deliberate (e.g. so the table reads SP1..SP4 in
> > numeric order), please call it out in the commit message and confirm
> > no downstream test relies on the previous SP-to-UUID mapping.
> > Otherwise keep the .id fields where they were and only substitute in
> > the macros.
> >
> > > diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
> > > @@ -19,41 +19,57 @@
> > > + .info = {
> > > + .id = SANDBOX_SP1_ID,
> > > + .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
> > > + .properties = SANDBOX_SP1_PROPERTIES,
> > > + },
> >
> > The macros being substituted in here are added in patch 8, and nothing
> > else in this patch uses them - they exist solely to be consumed by
> > this patch. Can you squash 9 into 8 so the macro definitions and their
> > first user land together.
> >
>
> As suggested,
> This patch has been now squashed to previous patch and all the comments
> for this commit have been addressed in v2.
> Link to v2: https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tungal@arm.com/
Thank you for the note. From my POV it is fine to just send the next
version, with the per-patch change log indicating what happened. If
you remove a patch you can use a 'Cover-changes' tag to indicate that
(if you are using Patman). To be honest I might not even notice a
removed patch :-)
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 10/11] doc: arm64: document FF-A runtime path for EFI variables
2026-05-14 12:49 ` [PATCH v2 10/11] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
@ 2026-05-15 18:30 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:30 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
Hi Harsimran,
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> doc: arm64: document FF-A runtime path for EFI variables
>
> The arm64 FF-A documentation still said EFI runtime support was a
> future development, so readers had no description of the current FF-A
> runtime transport or how EFI runtime variable services use it.
>
> Document the FF-A runtime transport, the shared MM communication path,
> and the EFI runtime variable flow on arm64. Also clarify that the
> armffa command is boot-time only and point readers to the architecture
> documentation for EFI runtime variable services over FF-A.
>
> Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> doc/arch/arm64.ffa.rst | 86 ++++++++++++++++++++++++++++++++++++++++++++----
> doc/usage/cmd/armffa.rst | 11 +++++++
> 2 files changed, 90 insertions(+), 7 deletions(-)
> diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
> @@ -158,6 +164,71 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
> +At runtime, the driver model is no longer available. Runtime users should
> +use the resident FF-A runtime transport, which verifies the runtime context
> +before issuing FF-A calls.
Please name the actual API the runtime user is expected to call (the
helpers from include/arm_ffa_runtime.h), otherwise the reader is told
to use the resident runtime transport without being pointed at the
entry points.
Reviewed-by: Simon Glass <sjg@chromium.org>
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 11/11] doc: bootefi: note two-phase runtime variables selftest
2026-05-14 12:49 ` [PATCH v2 11/11] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
@ 2026-05-15 18:30 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:30 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
Hi Harsimran,
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> doc: bootefi: note two-phase runtime variables selftest
>
> The bootefi documentation did not describe how to run the
> runtime-variable selftest, so users had no guidance on its reboot
> requirements or on which flow applies to their configuration.
>
> Document the runtime-variable selftest flow in bootefi.rst. Describe
> the non-volatile path, note the single-run
> CONFIG_EFI_RT_VOLATILE_STORE=y case, and show how to select the
> runtime-variable selftest with efi_selftest.
>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>
> doc/usage/cmd/bootefi.rst | 27 +++++++++++++++++++++++++++
> 1 file changed, 27 insertions(+)
Reviewed-by: Simon Glass <sjg@chromium.org>
> diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
> @@ -160,6 +160,33 @@ environment variable to match one of the listed identifiers
> Some of the tests execute the ExitBootServices() UEFI boot service and will not
> return to the command line but require a board reset.
>
> +When CONFIG_EFI_RT_VOLATILE_STORE is enabled, the test
> +*variables at runtime* completes in a single run and does not require
> +a reboot.
This contradicts the sentence above it. All three tests live in the
EFI_SETUP_BEFORE_BOOTTIME_EXIT phase, so the framework calls
efi_st_exit_boot_services() before executing them and a board reset is
still required to get back to the prompt. What I suspect you mean is
that the volatile path does not need an intermediate reboot between
setup and verify - please reword, e.g. "completes in a single run and
does not require an intermediate reboot to carry state across runs (a
board reset is still needed afterwards, as for any test that calls
ExitBootServices())".
> diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
> @@ -160,6 +160,33 @@ environment variable to match one of the listed identifiers
> +When CONFIG_EFI_RT_VOLATILE_STORE is not enabled, the runtime-variable
> +flow is split into *variables at runtime setup* and
> +*variables at runtime verify*. Run the setup test once to create the
> +runtime-accessible variable in non-volatile storage, reboot, then run
> +the verify test to validate, append, and delete that variable.
Worth noting that both halves are on_request tests, so they will not
be picked up by 'bootefi selftest' without naming them explicitly. A
single sentence ("Both phases are on-request tests, so they only run
when selected by efi_selftest.") would make this self-contained.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver
2026-05-14 12:49 ` [PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
@ 2026-05-15 18:35 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:35 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
Hi Harsimran,
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi_loader: add FF-A runtime support in EFI variable TEE driver
>
> Enable MM variable services over FF-A after ExitBootServices
>
> Extend lib/efi_loader/efi_variable_tee.c to support FF-A
> communication with the secure world during EFI runtime. Reuse the
> statically reserved FF-A shared buffer after ExitBootServices(),
> make the MM communication path runtime-safe so runtime variable
> operations continue to reach the secure partition.
>
> Share the MM communication and MM SP notification helpers between the
> boot and runtime paths instead of maintaining separate runtime-only
> variants. Select dynamic allocation during boot and the fixed FF-A
> shared buffer at runtime, and reject requests that would exceed the
> shared buffer size.
>
> Mark the required code and data with __efi_runtime and
> __efi_runtime_data, use range-based cache maintenance on the shared
> buffer for the runtime FF-A path, and add the shared buffer to the EFI
> runtime memory map. Document the FF-A shared MM buffer
> [...]
>
> arch/arm/cpu/armv8/cache.S | 8 +
> arch/arm/cpu/armv8/cache_v8.c | 13 +-
> lib/efi_loader/Kconfig | 4 +
> lib/efi_loader/efi_variable_tee.c | 330 +++++++++++++++++++++++++++-----------
> 4 files changed, 260 insertions(+), 95 deletions(-)
Reviewed-by: Simon Glass <sjg@chromium.org>
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -34,20 +36,44 @@
> +static const int __efi_runtime_rodata mm_sp_errmap[] = {
> + [-MM_NOT_SUPPORTED] = -EINVAL,
> + [-MM_INVALID_PARAMETER] = -EPERM,
> + [-MM_DENIED] = -EACCES,
> + [-MM_NO_MEMORY] = -EBUSY,
> +};
Hard to read. The MM_* constants are negative, so the designators
silently become positive indices and the array ends up sparse (slot 4
is implicitly zero, since MM_NO_MEMORY is -5). ffa_map_sp_event() then
uses mm_sp_errmap[idx] as a truthy check to distinguish known error
from uninitialised gap, which only works because every assigned value
happens to be non-zero. Please either pack this as a switch (matching
the original) or store {mm_code, errno} pairs; otherwise add a comment
spelling out the convention.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -304,30 +341,61 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> + if (IS_ENABLED(CONFIG_ARM64)) {
> + BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR %
> + CONFIG_SYS_CACHELINE_SIZE);
> + BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_SIZE %
> + CONFIG_SYS_CACHELINE_SIZE);
> + flush_dcache_range((unsigned long)shared_buf,
> + (unsigned long)(shared_buf +
> + CONFIG_FFA_SHARED_MM_BUF_SIZE));
> + }
The commit message says the BUILD_BUG_ON() checks are added "in the
arm64 cache-maintenance path", but they live in ffa_mm_communicate() -
please reword.
Second, both the flush and the matching invalidate below cover the
entire CONFIG_FFA_SHARED_MM_BUF_SIZE regardless of tx_data_size. At
boot the input is only tx_data_size bytes and on the response path we
already trust message_len. Using tx_data_size (request) and
rx_data_size (response) rounded up to a cacheline would avoid flushing
megabytes on every call.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -1010,5 +1137,26 @@ efi_status_t efi_init_variables(void)
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + /*
> + * The FF-A shared buffer is accessed by EFI runtime services, so it
> + * must be marked as runtime memory in the EFI memory map.
> + *
> + * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
> + */
> + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
This path requires the OS to leave the region identity-mapped, right?
Worth a comment. You could add a BUILD_BUG_ON() to check that it is
EFI-page-aligned.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -434,8 +511,55 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> +static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
> +{
> + efi_uintn_t comm_buf_size;
> + u8 *comm_buf;
> +
> + comm_buf_size = MM_COMMUNICATE_HEADER_SIZE +
> + MM_VARIABLE_COMMUNICATE_SIZE +
> + payload_size;
> +
> + /*
> + * After ExitBootServices(), dynamic allocation is no longer permitted.
> + * Use the predefined FF-A shared buffer at runtime; otherwise allocate
> + * a fresh buffer during the boot phase.
> + */
> + if (efi_at_runtime()) {
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + if (comm_buf_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
> + return NULL;
> + comm_buf = ffa_shared_buf;
> + if (!comm_buf)
> + return NULL;
> + efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
Implicit contract here that bites later: at runtime this returns the
static shared buffer, so callers must NOT free() it. The boot-time
setup_mm_hdr() callers all do free(comm_buf), and the runtime variants
in patch 4 carefully don't. Please either document the ownership
contract in the kerneldoc, or expose a paired release helper so
callers don't need to know which phase they are in.
Also, memset'ing the full CONFIG_FFA_SHARED_MM_BUF_SIZE for every
runtime request is wasteful; zeroing comm_buf_size would be enough.
Regards,
Simon
^ permalink raw reply [flat|nested] 77+ messages in thread
* Re: [PATCH v2 08/11] efi: selftest: add runtime variable tests with non-volatile storage
2026-05-14 12:49 ` [PATCH v2 08/11] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
@ 2026-05-15 18:35 ` Simon Glass
0 siblings, 0 replies; 77+ messages in thread
From: Simon Glass @ 2026-05-15 18:35 UTC (permalink / raw)
To: harsimransingh.tungal
Cc: u-boot, abdellatif.elkhlifi, trini, ilias.apalodimas, xypron.glpk,
hugues.kambampiana, sjg
On 2026-05-14T12:49:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
> efi: selftest: add runtime variable tests with non-volatile storage
>
> Extend runtime variable tests for persistent storage
>
> Runtime variable selftests already cover the volatile-store path in a
> single run, but non-volatile storage needs state to survive a reboot.
> Make that flow explicit by keeping the existing "variables at runtime"
> test for CONFIG_EFI_RT_VOLATILE_STORE=y and adding on-request
> "variables at runtime setup" and "variables at runtime verify" tests
> for the non-volatile case.
>
> The setup phase runs QueryVariableInfo(), exercises create/delete of a
> runtime variable, prepares the persistent test state, and prompts the
> user to reboot and run the verify test. If an old test variable is
> already present, reuse it only when it matches the expected
> half-payload; otherwise delete it and recreate clean state. The setup
> path also performs a best-effort cleanup if a later check fails.
>
> The verify phase checks the prepared value, appends the remaining
> payload, validates the full contents, deletes the test variable, and
> [...]
>
> lib/efi_selftest/efi_selftest_variables_runtime.c | 713 +++++++++++++++-------
> 1 file changed, 481 insertions(+), 232 deletions(-)
Lots of subtle things here, but if it works it seems good to me.
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 77+ messages in thread
end of thread, other threads:[~2026-05-15 18:35 UTC | newest]
Thread overview: 77+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-24 17:31 [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 01/12] efi_loader: add runtime memset helper Harsimran Singh Tungal
2026-04-27 7:54 ` Ilias Apalodimas
2026-04-28 18:08 ` Simon Glass
2026-05-04 20:03 ` Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 02/12] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
2026-04-28 18:10 ` Simon Glass
2026-05-04 20:25 ` Harsimran Singh Tungal
2026-05-08 10:18 ` Abdellatif El Khlifi
2026-04-24 17:31 ` [PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
2026-04-27 16:21 ` Ilias Apalodimas
2026-05-04 20:40 ` Harsimran Singh Tungal
2026-05-08 10:23 ` Abdellatif El Khlifi
2026-04-28 18:12 ` Simon Glass
2026-05-05 8:55 ` Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 04/12] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
2026-04-28 18:16 ` Simon Glass
2026-05-05 14:30 ` Harsimran Singh Tungal
2026-05-07 15:31 ` Simon Glass
2026-04-24 17:31 ` [PATCH 05/12] efi_loader: move runtime GetVariable() helpers to efi_variable.c Harsimran Singh Tungal
2026-04-28 12:03 ` Ilias Apalodimas
2026-05-06 10:30 ` Harsimran Singh Tungal
2026-04-28 18:25 ` Simon Glass
2026-04-24 17:31 ` [PATCH 06/12] corstone1000: enable bootefi selftest Harsimran Singh Tungal
2026-04-27 7:56 ` Ilias Apalodimas
2026-04-28 18:01 ` Simon Glass
2026-05-06 12:20 ` Harsimran Singh Tungal
2026-05-07 15:32 ` Simon Glass
2026-04-24 17:31 ` [PATCH 07/12] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
2026-04-28 18:04 ` Simon Glass
2026-05-06 15:14 ` Harsimran Singh Tungal
2026-05-07 15:32 ` Simon Glass
2026-04-24 17:31 ` [PATCH 08/12] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
2026-04-28 18:05 ` Simon Glass
2026-05-14 14:58 ` Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 09/12] sandbox: ffa: share synthetic partition metadata via macros Harsimran Singh Tungal
2026-04-28 18:07 ` Simon Glass
2026-05-14 15:00 ` Harsimran Singh Tungal
2026-05-15 18:28 ` Simon Glass
2026-04-24 17:31 ` [PATCH 10/12] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
2026-04-28 18:08 ` Simon Glass
2026-05-14 15:05 ` Harsimran Singh Tungal
2026-05-08 10:40 ` Abdellatif El Khlifi
2026-04-24 17:31 ` [PATCH 11/12] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
2026-04-28 18:14 ` Simon Glass
2026-05-14 15:07 ` Harsimran Singh Tungal
2026-04-24 17:31 ` [PATCH 12/12] efi_loader: align FF-A cache maintenance with runtime path Harsimran Singh Tungal
2026-04-28 18:14 ` Simon Glass
2026-05-08 10:34 ` Abdellatif El Khlifi
2026-05-14 15:11 ` Harsimran Singh Tungal
2026-04-24 22:18 ` [PATCH 00/12] arm64: FF-A runtime transport for EFI variables Heinrich Schuchardt
2026-05-05 14:37 ` Harsimran Singh Tungal
2026-04-28 18:16 ` [00/12] " Simon Glass
2026-05-14 15:37 ` Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 00/11] " Harsimran Singh Tungal
2026-05-14 12:49 ` [PATCH v2 01/11] efi_loader: add runtime memset helper Harsimran Singh Tungal
2026-05-15 18:14 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 02/11] arm-ffa: add FF-A bus runtime support Harsimran Singh Tungal
2026-05-15 18:25 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver Harsimran Singh Tungal
2026-05-15 18:35 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 04/11] efi_loader: enable EFI runtime SetVariable()/GetVariable() using FF-A transport Harsimran Singh Tungal
2026-05-15 18:26 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 05/11] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
2026-05-15 18:21 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 06/11] efi_loader: move runtime variable read helpers to efi_variable.c Harsimran Singh Tungal
2026-05-15 18:21 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 07/11] corstone1000: enable bootefi selftest Harsimran Singh Tungal
2026-05-15 18:22 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 08/11] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
2026-05-15 18:35 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 09/11] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
2026-05-15 18:27 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 10/11] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
2026-05-15 18:30 ` Simon Glass
2026-05-14 12:49 ` [PATCH v2 11/11] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
2026-05-15 18:30 ` Simon Glass
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox