All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables
@ 2026-09-14 11:00 Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 01/22] efi_loader: add runtime memset helper Harsimran Singh Tungal
                   ` (21 more replies)
  0 siblings, 22 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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, documentation, and Corstone-1000 configuration 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.
- Add runtime-safe FF-A direct-message handling and ExitBootServices setup.
- Implement FF-A runtime communication in the EFI variable TEE backend.
- Enable EFI runtime SetVariable(), GetVariable(), GetNextVariableName(),
  and QueryVariableInfo() over the FF-A transport.
- Add sandbox FF-A runtime transport tests.
- Extend EFI selftests for runtime variables and enable bootefi selftest
  on Corstone-1000.
- Document the FF-A runtime transport and runtime-variable selftest flow.

Testing:

Tested on Corstone-1000 FVP with the Trusted Services SMM Gateway SP.
The instructions to build and run the Corstone-1000 FVP are available at:

  https://corstone1000.docs.arm.com/en/corstone1000-2026.05/user-guide.html

The SMM Gateway SP provides the MM variable service and exposes the MM
Communicate endpoint over FF-A direct messages.

The EFI runtime variable selftest was run in two phases. The setup phase
creates a non-volatile runtime variable before reset. On the U-Boot
prompt:

  corstone1000# setenv efi_selftest 'variables at runtime setup'
  corstone1000# bootefi selftest

Then reset the Corstone-1000 FVP and run the verify phase. The verify
phase checks that the variable is available after reset, then exercises
the runtime get/set/append/delete paths. On the U-Boot prompt after
reset:

  corstone1000# setenv efi_selftest 'variables at runtime verify'
  corstone1000# bootefi selftest

Both phases completed with Summary: 0 failures.

Changes in v5:

Address Ilias Apalodimas's review comments:
- Limit arm64 cache runtime annotations to CONFIG_ARM_FFA_RT_MODE.
- Include MM_SUCCESS in the MM SP response map.
- Guard FF-A shared-buffer references for OP-TEE-only builds.
- Add Corstone-1000 FVP build and test information to the cover letter.

Link to v4:
https://www.mail-archive.com/u-boot@lists.u-boot-project.org/msg01127.html

Link to v3: 
https://lore.kernel.org/u-boot/20260627144421.2067410-1-harsimransingh.tun...@arm.com/

Link to v2: 
https://lore.kernel.org/u-boot/20260514124924.1804332-1-harsimransingh.tun...@arm.com/

Link to v1: 
https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tun...@arm.com/

Harsimran Singh Tungal (22):
  efi_loader: add runtime memset helper
  arm-ffa: store boot-discovered runtime data separately
  arm-ffa: add runtime-safe FF-A SMC wrapper
  arm-ffa: add runtime direct-message support
  arm-ffa: reuse direct-message helper at boot time
  arm-ffa: enable runtime context at ExitBootServices
  arm: cache: keep range maintenance available at EFI runtime
  efi_loader: add MM SP status mapping for FF-A variables
  efi_loader: make MM transport selection runtime-safe
  efi_loader: make FF-A MM SP notification runtime-safe
  efi_loader: make FF-A MM communication runtime-safe
  efi_loader: reserve FF-A shared buffer for runtime variables
  efi_loader: enable TEE runtime SetVariable() over FF-A
  efi_loader: enable TEE runtime GetVariable() over FF-A
  efi_loader: enable TEE runtime GetNextVariableName() over FF-A
  efi_loader: enable TEE runtime QueryVariableInfo() over FF-A
  charset: mark u16_strsize() as __efi_runtime
  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                 |  20 +-
 arch/sandbox/include/asm/sandbox_arm_ffa.h    |  16 +-
 configs/corstone1000_defconfig                |   3 +
 doc/arch/arm64.ffa.rst                        |  88 +-
 doc/usage/cmd/armffa.rst                      |  11 +
 doc/usage/cmd/bootefi.rst                     |  31 +
 drivers/firmware/arm-ffa/Kconfig              |  11 +
 drivers/firmware/arm-ffa/Makefile             |   4 +-
 drivers/firmware/arm-ffa/arm-ffa-runtime.c    | 294 +++++++
 drivers/firmware/arm-ffa/arm-ffa-uclass.c     | 114 +--
 drivers/firmware/arm-ffa/arm-ffa.c            |  16 +-
 drivers/firmware/arm-ffa/ffa-emul-uclass.c    |  49 +-
 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_variable_tee.c             | 751 +++++++++++++++---
 .../efi_selftest_variables_runtime.c          | 715 +++++++++++------
 test/dm/Makefile                              |   3 +-
 test/dm/ffa.c                                 |   6 +-
 test/dm/ffa_runtime.c                         | 123 +++
 25 files changed, 2023 insertions(+), 498 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] 35+ messages in thread

* [PATCH v5 01/22] efi_loader: add runtime memset helper
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 02/22] arm-ffa: store boot-discovered runtime data separately Harsimran Singh Tungal
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
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] 35+ messages in thread

* [PATCH v5 02/22] arm-ffa: store boot-discovered runtime data separately
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 01/22] efi_loader: add runtime memset helper Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 03/22] arm-ffa: add runtime-safe FF-A SMC wrapper Harsimran Singh Tungal
                   ` (19 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

The FF-A runtime transport needs the framework version and U-Boot
endpoint ID after ExitBootServices(). Keep these fields in a dedicated
runtime sub-structure inside struct ffa_priv so they can be copied into
resident storage later.

Update existing users to access the values through uc_priv->rt. This
does not enable runtime behaviour yet.

Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
---
 drivers/firmware/arm-ffa/arm-ffa-uclass.c | 12 ++++++------
 include/arm_ffa_priv.h                    | 22 +++++++++++++++++-----
 test/dm/ffa.c                             |  6 +++---
 3 files changed, 26 insertions(+), 14 deletions(-)

diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 76a8775e911..eb159dbfade 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-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>
@@ -204,7 +204,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 +238,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 +461,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)) {
@@ -890,7 +890,7 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
 
 	invoke_ffa_fn((ffa_value_t){
 			.a0 = req_mode,
-			.a1 = PREP_SELF_ENDPOINT_ID(uc_priv->id) |
+			.a1 = PREP_SELF_ENDPOINT_ID(uc_priv->rt.id) |
 				PREP_PART_ENDPOINT_ID(dst_part_id),
 			.a2 = 0,
 			.a3 = msg->data0,
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/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] 35+ messages in thread

* [PATCH v5 03/22] arm-ffa: add runtime-safe FF-A SMC wrapper
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 01/22] efi_loader: add runtime memset helper Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 02/22] arm-ffa: store boot-discovered runtime data separately Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 04/22] arm-ffa: add runtime direct-message support Harsimran Singh Tungal
                   ` (18 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Add FF-A runtime annotations and expose invoke_ffa_fn_runtime() for code
that must remain available after ExitBootServices().

Provide implementations for the Arm FF-A driver and sandbox emulator so
later runtime direct-message helpers can use the same SMC entry point in
both environments.

Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v2:

Simon:

- Fix style issues
---
 drivers/firmware/arm-ffa/arm-ffa.c         | 16 ++++++++-
 drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 +++++++
 include/arm_ffa_runtime.h                  | 41 ++++++++++++++++++++++
 3 files changed, 68 insertions(+), 1 deletion(-)
 create mode 100644 include/arm_ffa_runtime.h

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_runtime.h b/include/arm_ffa_runtime.h
new file mode 100644
index 00000000000..66096db3d24
--- /dev/null
+++ b/include/arm_ffa_runtime.h
@@ -0,0 +1,41 @@
+/* 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 <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);
+
+#endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 04/22] arm-ffa: add runtime direct-message support
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (2 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 03/22] arm-ffa: add runtime-safe FF-A SMC wrapper Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 05/22] arm-ffa: reuse direct-message helper at boot time Harsimran Singh Tungal
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Add the FF-A runtime transport implementation needed after
ExitBootServices() so EFI runtime services can continue to exchange
direct messages with secure partitions. The runtime code keeps resident
FF-A private data, tracks whether the runtime context is ready,
translates FF-A error codes, and exposes ffa_sync_send_receive_runtime()
for FFA_MSG_SEND_DIRECT_REQ/RESP.

Add the ARM_FFA_RT_MODE Kconfig option and build arm-ffa-runtime.c when
FF-A transport and EFI loader support are enabled. Move FF-A errno
translation out of arm-ffa-uclass.c so boot-time and runtime callers use
the same mapping.

Tag the runtime code and data with __efi_runtime and __efi_runtime_data
so they remain available after ExitBootServices(). The runtime
direct-message path uses invoke_ffa_fn_runtime() and rejects requests
until the runtime context has been enabled.

Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Rename the runtime-context helpers to the ffa_runtime_context_* form
- Fix commit message styling

v2:

Simon:

- Keep the runtime-enabled flag separate from copied boot-time data
- Remove unused global-data plumbing
- Switch to IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
- Fix style issues
---
 drivers/firmware/arm-ffa/Kconfig           |  11 +
 drivers/firmware/arm-ffa/Makefile          |   4 +-
 drivers/firmware/arm-ffa/arm-ffa-runtime.c | 251 +++++++++++++++++++++
 drivers/firmware/arm-ffa/arm-ffa-uclass.c  |  35 +--
 include/arm_ffa_runtime.h                  | 132 +++++++++++
 5 files changed, 397 insertions(+), 36 deletions(-)
 create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c

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..d761ec9ee07
--- /dev/null
+++ b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
@@ -0,0 +1,251 @@
+// 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)
+
+/**
+ * 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_runtime_context_enable() - 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_runtime_context_enable(void)
+{
+	ffa_runtime_enabled = true;
+}
+
+/**
+ * ffa_runtime_context_reset() - 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_runtime_context_reset(void)
+{
+	struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
+
+	*priv_rt = (struct ffa_priv_runtime){0};
+	ffa_runtime_enabled = false;
+}
+
+/**
+ * ffa_runtime_context_ready() - 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_runtime_context_enable()
+ * 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_runtime_context_ready(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_runtime_context_ready())
+		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 eb159dbfade..13e22a1b7f7 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -7,6 +7,7 @@
  */
 #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
diff --git a/include/arm_ffa_runtime.h b/include/arm_ffa_runtime.h
index 66096db3d24..77b528745e8 100644
--- a/include/arm_ffa_runtime.h
+++ b/include/arm_ffa_runtime.h
@@ -12,6 +12,7 @@
 
 #include <linux/types.h>
 #include <arm_ffa.h>
+#include <arm_ffa_priv.h>
 #include <efi_loader.h>
 
 /**
@@ -38,4 +39,135 @@
  */
 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_runtime_context_enable() - 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_runtime_context_enable(void);
+
+/**
+ * ffa_runtime_context_reset() - 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_runtime_context_reset(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_runtime_context_ready() - 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_runtime_context_enable()
+ * 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_runtime_context_ready(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
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 05/22] arm-ffa: reuse direct-message helper at boot time
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (3 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 04/22] arm-ffa: add runtime direct-message support Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 06/22] arm-ffa: enable runtime context at ExitBootServices Harsimran Singh Tungal
                   ` (16 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

The runtime transport adds ffa_invoke_msg_send_direct_req() as the common
implementation for FFA_MSG_SEND_DIRECT_REQ/RESP. Use the same helper from
the boot-time ffa_msg_send_direct_req_hdlr() instead of keeping a second
copy of the direct-message sequence in arm-ffa-uclass.c.

This keeps boot-time and runtime direct-message handling aligned.

Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Fix commit message styling
---
 drivers/firmware/arm-ffa/arm-ffa-uclass.c | 60 ++---------------------
 include/arm_ffa.h                         | 16 ++----
 2 files changed, 7 insertions(+), 69 deletions(-)

diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 13e22a1b7f7..668c2156f8b 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -818,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:
  *
@@ -836,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);
@@ -847,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->rt.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)*/
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:
  *
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 06/22] arm-ffa: enable runtime context at ExitBootServices
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (4 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 05/22] arm-ffa: reuse direct-message helper at boot time Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 07/22] arm: cache: keep range maintenance available at EFI runtime Harsimran Singh Tungal
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Register an ExitBootServices event after the FF-A bus has completed
probe.

The callback copies the boot-discovered runtime fields into
resident storage and marks the FF-A runtime context ready.
EFI runtime services can then use the runtime transport without
depending on driver model state.

Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Move ExitBootServices event registration to the end of probe
- Use an early-return guard and log missing-context with log_warning()
- Drop the unrelated whitespace-only hunk
- Fix commit message styling

v2:

Simon:

- Leave runtime mode disabled if private data is missing and update the
  log message
- Register the ExitBootServices event earlier in probe
---
 drivers/firmware/arm-ffa/arm-ffa-runtime.c | 43 ++++++++++++++++++++++
 drivers/firmware/arm-ffa/arm-ffa-uclass.c  |  9 +++++
 include/arm_ffa_runtime.h                  | 18 +++++++++
 3 files changed, 70 insertions(+)

diff --git a/drivers/firmware/arm-ffa/arm-ffa-runtime.c b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
index d761ec9ee07..84c1a203d40 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-runtime.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
@@ -37,6 +37,49 @@ static const __ffa_runtime_data struct ffa_bus_ops_runtime ffa_ops_rt = {
 #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) {
+		log_warning("FF-A: runtime data missing, keeping RT mode disabled\n");
+		return;
+	}
+
+	ffa_copy_runtime_priv(&priv->rt);
+	ffa_runtime_context_enable();
+}
+
+/**
+ * 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
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
index 668c2156f8b..d21cc4cc35c 100644
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
@@ -937,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)
@@ -960,6 +961,14 @@ 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) {
+			ffa_unmap_rxtx_buffers_hdlr(dev);
+			return ret;
+		}
+	}
+
 	return 0;
 }
 
diff --git a/include/arm_ffa_runtime.h b/include/arm_ffa_runtime.h
index 77b528745e8..bfc4d387660 100644
--- a/include/arm_ffa_runtime.h
+++ b/include/arm_ffa_runtime.h
@@ -84,6 +84,24 @@ void ffa_runtime_context_reset(void);
  */
 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_runtime_context_ready() - Query FF-A runtime readiness
  *
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 07/22] arm: cache: keep range maintenance available at EFI runtime
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (5 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 06/22] arm-ffa: enable runtime context at ExitBootServices Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 08/22] efi_loader: add MM SP status mapping for FF-A variables Harsimran Singh Tungal
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

The FF-A EFI runtime variable path uses a shared MM communication buffer
after ExitBootServices(). Before sending a request to the MM secure
partition the buffer range must be flushed, and after the response the
same range must be invalidated.

Keep flush_dcache_range() and invalidate_dcache_range() available from
EFI runtime code on arm64, together with the underlying assembly range
helpers, so the FF-A runtime transport can maintain the shared buffer
without using whole-cache operations after ExitBootServices().

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v5:

Ilias:

- Split the ARMv8 cache range-maintenance runtime annotations out of
  the EFI variable TEE runtime patch.
---
 arch/arm/cpu/armv8/cache.S    |  8 ++++++++
 arch/arm/cpu/armv8/cache_v8.c | 20 ++++++++++++++++----
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S
index c9e46859b4f..386b62c2d81 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_ARM_FFA_RT_MODE
+.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_ARM_FFA_RT_MODE
+.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 e59528e576e..edde8f73a6b 100644
--- a/arch/arm/cpu/armv8/cache_v8.c
+++ b/arch/arm/cpu/armv8/cache_v8.c
@@ -8,6 +8,12 @@
  */
 
 #include <cpu_func.h>
+#if IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+#include <efi_loader.h>
+#define CACHE_RUNTIME_ATTR __efi_runtime
+#else
+#define CACHE_RUNTIME_ATTR
+#endif
 #include <hang.h>
 #include <log.h>
 #include <asm/cache.h>
@@ -915,7 +921,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 CACHE_RUNTIME_ATTR invalidate_dcache_range(unsigned long start,
+						unsigned long stop)
 {
 	__asm_invalidate_dcache_range(start, stop);
 }
@@ -923,20 +930,25 @@ 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 CACHE_RUNTIME_ATTR 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 CACHE_RUNTIME_ATTR invalidate_dcache_range(unsigned long start,
+						unsigned long stop)
 {
 }
 
-void flush_dcache_range(unsigned long start, unsigned long stop)
+void CACHE_RUNTIME_ATTR flush_dcache_range(unsigned long start,
+					   unsigned long stop)
 {
 }
 #endif /* CONFIG_SYS_DISABLE_DCACHE_OPS */
 
+#undef CACHE_RUNTIME_ATTR
+
 void dcache_enable(void)
 {
 	/* The data cache is not active unless the mmu is enabled */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 08/22] efi_loader: add MM SP status mapping for FF-A variables
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (6 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 07/22] arm: cache: keep range maintenance available at EFI runtime Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-18 17:19   ` Ilias Apalodimas
  2026-09-14 11:00 ` [PATCH v5 09/22] efi_loader: make MM transport selection runtime-safe Harsimran Singh Tungal
                   ` (13 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Define the MM SP status values as an enum and add a runtime-safe helper
for translating MM SP notification results to U-Boot errno values.

The FF-A notification path uses the same mapping during boot and after
ExitBootServices(), so keep the mapping table in EFI runtime rodata.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v5:

Ilias:

- Include MM_SUCCESS in the MM SP response map

v4:

Ilias:

- Replace MM status macros with an enum

v3:

Simon:

- Add a comment explaining the sparse MM SP error map indexing

v2:

Ilias, Simon:

- Reuse common MM SP error mapping
---
 lib/efi_loader/efi_variable_tee.c | 50 ++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 7 deletions(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 6a1fa39bb6f..bc15795e94f 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>
@@ -21,18 +21,34 @@
 #include <efi_api.h>
 #include <efi_loader.h>
 #include <efi_variable.h>
+#include <linux/kernel.h>
 #include <malloc.h>
 #include <mapmem.h>
 #include <mm_communication.h>
 #include <tee.h>
 
 #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
-/* MM return codes */
-#define MM_SUCCESS (0)
-#define MM_NOT_SUPPORTED (-1)
-#define MM_INVALID_PARAMETER (-2)
-#define MM_DENIED (-3)
-#define MM_NO_MEMORY (-5)
+enum mm_sp_status {
+	MM_SUCCESS = 0,
+	MM_NOT_SUPPORTED = -1,
+	MM_INVALID_PARAMETER = -2,
+	MM_DENIED = -3,
+	MM_NO_MEMORY = -5,
+};
+
+/*
+ * MM_* failure codes are negative. Use -MM_* as sparse positive indices so
+ * ffa_map_sp_event() can look up mm_sp_resp_map[-sp_event_ret]. The
+ * unassigned gap between MM_DENIED and MM_NO_MEMORY maps to -EACCES.
+ */
+static const int __efi_runtime_rodata mm_sp_resp_map[] = {
+	[MM_SUCCESS]		 = 0,
+	[-MM_NOT_SUPPORTED]	 = -EINVAL,
+	[-MM_INVALID_PARAMETER]	 = -EPERM,
+	[-MM_DENIED]		 = -EACCES,
+	[-MM_NO_MEMORY - 1]	 = -EACCES,
+	[-MM_NO_MEMORY]		 = -EBUSY,
+};
 
 static const char *mm_sp_svc_uuid = MM_SP_UUID;
 static u16 mm_sp_id;
@@ -169,6 +185,26 @@ 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 (idx >= 0 && idx < (int)ARRAY_SIZE(mm_sp_resp_map))
+		return mm_sp_resp_map[idx];
+
+	return -EACCES;
+}
+
 /**
  * ffa_notify_mm_sp() - Announce there is data in the shared buffer
  *
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 09/22] efi_loader: make MM transport selection runtime-safe
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (7 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 08/22] efi_loader: add MM SP status mapping for FF-A variables Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 10/22] efi_loader: make FF-A MM SP notification runtime-safe Harsimran Singh Tungal
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Track when ExitBootServices() has been called and make the MM transport
selection helper callable from EFI runtime code.

At runtime, select the FF-A transport only when FF-A runtime mode is
enabled. Otherwise keep using the OP-TEE MM communication path so builds
without CONFIG_ARM_FFA_RT_MODE do not lose their existing runtime
backend.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v4:

Ilias:

- Keep OP-TEE as the runtime fallback without FF-A RT mode

v2:

Ilias, Simon:

- Rename runtime-phase tracking to efi_at_runtime()
---
 lib/efi_loader/efi_variable_tee.c | 44 +++++++++++++++++++++++--------
 1 file changed, 33 insertions(+), 11 deletions(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index bc15795e94f..50a98a1dd0a 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -58,12 +58,28 @@ 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 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.
  *
@@ -399,27 +415,30 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
 /**
  * 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.
+ * 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, use FF-A only when FF-A runtime mode is
+ * enabled; otherwise keep using OP-TEE comms.
  *
- * If FF-A bus is not ready, use OPTEE comms.
+ * If FF-A bus is not ready at boot, use OP-TEE comms.
  *
- * Return:
- *
- * MM_COMMS_FFA or MM_COMMS_OPTEE
+ * Return: MM_COMMS_FFA or MM_COMMS_OPTEE
  */
-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;
 
-	ret = uclass_first_device_err(UCLASS_FFA, &dev);
-	if (ret) {
-		log_debug("EFI: Cannot find FF-A bus device, trying Optee comms\n");
+	if (efi_at_runtime()) {
+		if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE))
+			return MM_COMMS_FFA;
 		return MM_COMMS_OPTEE;
 	}
 
+	ret = uclass_first_device_err(UCLASS_FFA, &dev);
+	if (ret)
+		return MM_COMMS_OPTEE;
+
 	return MM_COMMS_FFA;
 }
 #endif
@@ -1018,6 +1037,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;
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 10/22] efi_loader: make FF-A MM SP notification runtime-safe
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (8 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 09/22] efi_loader: make MM transport selection runtime-safe Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 11/22] efi_loader: make FF-A MM communication runtime-safe Harsimran Singh Tungal
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Make the FF-A MM SP notification helper usable after ExitBootServices().
The boot path continues to use the FF-A driver-model operation, while
the runtime path uses the resident FF-A runtime transport.

This keeps the notification path shared while avoiding driver-model
access from EFI runtime code.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Ilias:

- Remove log calls from the runtime MM SP notification path

v2:

Ilias, Simon:

- Fold runtime MM SP notification into the common path
---
 lib/efi_loader/efi_variable_tee.c | 53 +++++++++++--------------------
 1 file changed, 18 insertions(+), 35 deletions(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 50a98a1dd0a..9cae7b7e5ac 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -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>
@@ -51,7 +52,7 @@ static const int __efi_runtime_rodata mm_sp_resp_map[] = {
 };
 
 static const char *mm_sp_svc_uuid = MM_SP_UUID;
-static u16 mm_sp_id;
+static u16 __efi_runtime_data mm_sp_id;
 #endif
 
 extern struct efi_var_file __efi_runtime_data *efi_var_buf;
@@ -229,52 +230,34 @@ static int __efi_runtime ffa_map_sp_event(int sp_event_ret)
  * 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;
 
-	msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET; /* x3 */
+	if (at_runtime) {
+		ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
+	} else {
+		struct udevice *dev;
 
-	ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
+		ret = uclass_first_device_err(UCLASS_FFA, &dev);
+		if (ret)
+			return ret;
+
+		ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
+	}
 	if (ret)
 		return ret;
 
-	sp_event_ret = msg.data0; /* x3 */
+	sp_event_ret = msg.data0;
 
-	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;
-	}
-
-	return ret;
+	return ffa_map_sp_event(sp_event_ret);
 }
 
 /**
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 11/22] efi_loader: make FF-A MM communication runtime-safe
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (9 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 10/22] efi_loader: make FF-A MM SP notification runtime-safe Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables Harsimran Singh Tungal
                   ` (10 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Make the FF-A MM communication helper usable from EFI runtime code. The
boot path copies requests into the configured FF-A shared buffer, while
the runtime path operates directly on the runtime communication buffer.

Use range-based cache maintenance on the active shared-buffer request
and response sizes, and document the shared-buffer cacheline-alignment
requirements in Kconfig.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Restrict arm64 cache maintenance to the cacheline-rounded request and
  response sizes
- Reword the commit message for the BUILD_BUG_ON() checks

v2:

Ilias, Simon:

- Collapse boot and runtime MM communication helpers
- Document the FF-A shared buffer cacheline-alignment requirement and
  add BUILD_BUG_ON() checks for the address and size
---
 lib/efi_loader/Kconfig            |   4 +
 lib/efi_loader/efi_variable_tee.c | 130 +++++++++++++++++++++---------
 2 files changed, 95 insertions(+), 39 deletions(-)

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 9cae7b7e5ac..7f35ac7dd22 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -22,6 +22,7 @@
 #include <efi_api.h>
 #include <efi_loader.h>
 #include <efi_variable.h>
+#include <linux/build_bug.h>
 #include <linux/kernel.h>
 #include <malloc.h>
 #include <mapmem.h>
@@ -301,77 +302,128 @@ 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.
+ * 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.
  *
- * Return:
- *
- * 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 hdr_cache_size;
 	ulong tx_data_size;
+	ulong tx_cache_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())
+			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);
+	hdr_cache_size = ALIGN(sizeof(*mm_hdr), CONFIG_SYS_CACHELINE_SIZE);
+	tx_cache_size = ALIGN(tx_data_size, CONFIG_SYS_CACHELINE_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 +
+					   tx_cache_size));
+	}
 
 	/* Announce there is data in the shared buffer */
-
 	ffa_ret = ffa_notify_mm_sp();
 
 	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 +
+		ulong rx_cache_size;
+
+		if (IS_ENABLED(CONFIG_ARM64))
+			invalidate_dcache_range((unsigned long)shared_buf,
+						(unsigned long)(shared_buf +
+							hdr_cache_size));
+
+		rx_data_size = ((struct efi_mm_communicate_header *)shared_buf)->message_len +
 			sizeof(efi_guid_t) +
 			sizeof(size_t);
 
-		if (rx_data_size > comm_buf_size) {
+		if (rx_data_size > comm_buf_size ||
+		    rx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE) {
 			efi_ret = EFI_OUT_OF_RESOURCES;
 			break;
 		}
 
-		memcpy(comm_buf, virt_shared_buf, rx_data_size);
+		if (IS_ENABLED(CONFIG_ARM64)) {
+			rx_cache_size = ALIGN(rx_data_size,
+					      CONFIG_SYS_CACHELINE_SIZE);
+			if (rx_cache_size > hdr_cache_size)
+				invalidate_dcache_range((unsigned long)(shared_buf +
+							hdr_cache_size),
+						(unsigned long)(shared_buf +
+							rx_cache_size));
+		}
+
+		if (!at_runtime)
+			memcpy(comm_buf, shared_buf, rx_data_size);
 		efi_ret = EFI_SUCCESS;
 		break;
 	}
@@ -391,7 +443,8 @@ 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;
 }
 
@@ -427,8 +480,8 @@ static enum mm_comms_select __efi_runtime 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
@@ -438,11 +491,12 @@ static enum mm_comms_select __efi_runtime 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)
@@ -457,16 +511,14 @@ 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 (ret != EFI_SUCCESS)
 		return ret;
-	}
 
 	return var_hdr->ret_status;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (10 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 11/22] efi_loader: make FF-A MM communication runtime-safe Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-18 18:30   ` Ilias Apalodimas
  2026-09-14 11:00 ` [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A Harsimran Singh Tungal
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Use the statically reserved FF-A shared MM buffer for EFI variable
runtime communication after ExitBootServices(), since dynamic allocation
is no longer available.

Keep the shared-buffer pointer convertible across
SetVirtualAddressMap(), add the buffer to the EFI runtime memory map,
and reject runtime requests that do not fit in the configured shared
buffer.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v5:

Ilias:

  - Guard FF-A shared-buffer references for OP-TEE-only builds

v3:

Simon:

- Document the get_comm_buf() ownership contract for boot and runtime
- Zero only the active comm_buf_size in the runtime shared-buffer path
- Add SetVirtualAddressMap() handling for ffa_shared_buf via
  efi_convert_pointer()
- Add a BUILD_BUG_ON() for EFI-page alignment of
  CONFIG_FFA_SHARED_MM_BUF_ADDR

v2:

Ilias, Simon:

- 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 scope
- Update the copyright header
---
 lib/efi_loader/efi_variable_tee.c | 130 +++++++++++++++++++++++++++---
 1 file changed, 119 insertions(+), 11 deletions(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 7f35ac7dd22..a03f2091eb4 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -56,9 +56,12 @@ static const char *mm_sp_svc_uuid = MM_SP_UUID;
 static u16 __efi_runtime_data mm_sp_id;
 #endif
 
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+static void *__efi_runtime_data ffa_shared_buf;
+#endif
 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;
 
@@ -524,8 +527,64 @@ static efi_status_t __efi_runtime mm_communicate(u8 *comm_buf,
 }
 
 /**
- * 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.
+ *
+ * The caller owns the returned buffer only during the boot phase and
+ * must release it with free(). During the runtime phase, the returned
+ * pointer aliases the static FF-A shared buffer and must not be freed.
+ *
+ * Return:
+ *   Pointer to a valid communication buffer on success.
+ *   NULL if no suitable communication buffer is available.
+ */
+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 CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+		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, comm_buf_size);
+		} else {
+			return NULL;
+		}
+#else
+		return NULL;
+#endif
+	} 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
@@ -534,10 +593,11 @@ static efi_status_t __efi_runtime mm_communicate(u8 *comm_buf,
  * @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;
@@ -555,16 +615,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;
@@ -1077,6 +1136,20 @@ void efi_variables_boot_exit_notify(void)
 	ebs_called = true;
 }
 
+/**
+ * ffa_shared_buf_notify_virtual_address_map() - SetVirtualAddressMap callback
+ *
+ * @event:	callback event
+ * @context:	callback context
+ */
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+static void EFIAPI __efi_runtime
+ffa_shared_buf_notify_virtual_address_map(struct efi_event *event, void *context)
+{
+	efi_convert_pointer(0, (void **)&ffa_shared_buf);
+}
+#endif
+
 /**
  * efi_init_variables() - initialize variable services
  *
@@ -1085,6 +1158,9 @@ void efi_variables_boot_exit_notify(void)
 efi_status_t efi_init_variables(void)
 {
 	efi_status_t ret;
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+	struct efi_event *event;
+#endif
 
 	/* Create a cached copy of the variables that will be enabled on ExitBootServices() */
 	ret = efi_var_mem_init();
@@ -1103,5 +1179,37 @@ efi_status_t efi_init_variables(void)
 	if (ret != EFI_SUCCESS)
 		return ret;
 
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
+	if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
+		/*
+		 * The FF-A shared buffer is accessed by EFI runtime services, so
+		 * keep the resident pointer convertible across
+		 * SetVirtualAddressMap() and mark the region as runtime memory.
+		 *
+		 * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
+		 */
+		BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR & EFI_PAGE_MASK);
+		ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
+		ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+				       TPL_CALLBACK,
+				       ffa_shared_buf_notify_virtual_address_map,
+				       NULL, NULL, &event);
+		if (ret != EFI_SUCCESS)
+			return ret;
+		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) {
+			efi_close_event(event);
+			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);
+	}
+#endif
+
 	return EFI_SUCCESS;
 }
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (11 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-18 18:20   ` Ilias Apalodimas
  2026-09-14 11:00 ` [PATCH v5 14/22] efi_loader: enable TEE runtime GetVariable() " Harsimran Singh Tungal
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Add the TEE-backed runtime SetVariable() implementation for the FF-A/MM
variable backend. The runtime path uses EFI runtime-safe memory helpers
and the shared MM communication path so SetVariable() can reach the MM
secure partition after ExitBootServices().

Add runtime-safe variable-property helpers for the SetVariable() path
and use the original data_size argument when restoring the read-only
property maxsize, instead of relying on the MM response buffer.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v4:

Ilias:

- Split the runtime SetVariable() support out of the combined runtime
  variable-services patch.

v3:

Simon:

- Return early on the EFI_NOT_FOUND property-get path at runtime
- Use the original data_size for the read-only property maxsize update

Ilias:
- Rename TEE/FF-A runtime handlers to private *_int_runtime names

v2:

Simon:

- Move the read-only property check before `setup_mm_hdr()` in
  efi_set_variable_runtime
- Drop the stale copied boot-path comment
---
 lib/efi_loader/efi_variable_tee.c | 147 ++++++++++++++++++++++++++++--
 1 file changed, 140 insertions(+), 7 deletions(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index a03f2091eb4..5f494731ae5 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -723,6 +723,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,
@@ -768,6 +800,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)
+		return EFI_SUCCESS;
+	if (ret != EFI_SUCCESS)
+		return ret;
+	efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
+
+	return EFI_SUCCESS;
+}
+
 efi_status_t efi_get_variable_int(const u16 *variable_name,
 				  const efi_guid_t *vendor,
 				  u32 *attributes, efi_uintn_t *data_size,
@@ -1001,7 +1076,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
 		var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
 		var_property.attributes = attributes;
 		var_property.minsize = 1;
-		var_property.maxsize = var_acc->data_size;
+		var_property.maxsize = data_size;
 		ret = set_property_int(variable_name, name_size, vendor, &var_property);
 	}
 
@@ -1078,7 +1153,7 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
 }
 
 /**
- * efi_set_variable_runtime() - runtime implementation of SetVariable()
+ * efi_set_variable_int_runtime() - runtime implementation of SetVariable()
  *
  * @variable_name:	name of the variable
  * @guid:		vendor GUID
@@ -1088,11 +1163,69 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
  * Return:		status code
  */
 static efi_status_t __efi_runtime EFIAPI
-efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
-			 u32 attributes, efi_uintn_t data_size,
-			 const void *data)
+efi_set_variable_int_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 = data_size;
+		ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
+	}
+
+	return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
 }
 
 /**
@@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
 	efi_runtime_services.get_variable = efi_get_variable_runtime;
 	efi_runtime_services.get_next_variable_name =
 			efi_get_next_variable_name_runtime;
-	efi_runtime_services.set_variable = efi_set_variable_runtime;
+	efi_runtime_services.set_variable = efi_set_variable_int_runtime;
 	efi_update_table_header_crc32(&efi_runtime_services.hdr);
 
 	/* Record that ExitBootServices() has been called */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 14/22] efi_loader: enable TEE runtime GetVariable() over FF-A
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (12 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:00 ` [PATCH v5 15/22] efi_loader: enable TEE runtime GetNextVariableName() " Harsimran Singh Tungal
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Add the TEE-backed runtime GetVariable() implementation for the FF-A/MM
variable backend. The runtime path builds the MM request using EFI
runtime-safe memory helpers and uses the shared MM communication path
after ExitBootServices().

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v4:

Ilias:

- Split the runtime GetVariable() support out of the combined runtime
  variable-services patch.

v3:

Ilias:

- Rename TEE/FF-A runtime handlers to private *_int_runtime names

Simon:

- Cache attributes before reusing the FF-A shared buffer
- Add EFIAPI to the runtime GetVariable() helper
---
 lib/efi_loader/efi_variable_tee.c | 89 ++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 5f494731ae5..254d6bf8909 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -994,6 +994,93 @@ out:
 	return ret;
 }
 
+efi_status_t __efi_runtime EFIAPI
+efi_get_variable_int_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_set_variable_int(const u16 *variable_name,
 				  const efi_guid_t *vendor, u32 attributes,
 				  efi_uintn_t data_size, const void *data,
@@ -1259,7 +1346,7 @@ void efi_variables_boot_exit_notify(void)
 	/* Update runtime service table */
 	efi_runtime_services.query_variable_info =
 			efi_query_variable_info_runtime;
-	efi_runtime_services.get_variable = efi_get_variable_runtime;
+	efi_runtime_services.get_variable = efi_get_variable_int_runtime;
 	efi_runtime_services.get_next_variable_name =
 			efi_get_next_variable_name_runtime;
 	efi_runtime_services.set_variable = efi_set_variable_int_runtime;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 15/22] efi_loader: enable TEE runtime GetNextVariableName() over FF-A
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (13 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 14/22] efi_loader: enable TEE runtime GetVariable() " Harsimran Singh Tungal
@ 2026-09-14 11:00 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 16/22] efi_loader: enable TEE runtime QueryVariableInfo() " Harsimran Singh Tungal
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:00 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Add the TEE-backed runtime GetNextVariableName() implementation for the
FF-A/MM variable backend. The runtime path uses EFI runtime-safe memory
helpers and the shared MM communication path so variable enumeration can
continue after ExitBootServices().

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v4:

Ilias:

- Split the runtime GetNextVariableName() support out of the combined
  runtime variable-services patch.

v3:

Ilias:

- Rename TEE/FF-A runtime handlers to private *_int_runtime names

Simon:

- Add EFIAPI to the runtime GetNextVariableName() helper
---
 lib/efi_loader/efi_variable_tee.c | 64 ++++++++++++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 254d6bf8909..0de9949344e 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -1081,6 +1081,68 @@ efi_get_variable_int_runtime(u16 *variable_name, const efi_guid_t *vendor,
 	return ret;
 }
 
+efi_status_t __efi_runtime EFIAPI
+efi_get_next_variable_name_int_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,
@@ -1348,7 +1410,7 @@ void efi_variables_boot_exit_notify(void)
 			efi_query_variable_info_runtime;
 	efi_runtime_services.get_variable = efi_get_variable_int_runtime;
 	efi_runtime_services.get_next_variable_name =
-			efi_get_next_variable_name_runtime;
+			efi_get_next_variable_name_int_runtime;
 	efi_runtime_services.set_variable = efi_set_variable_int_runtime;
 	efi_update_table_header_crc32(&efi_runtime_services.hdr);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 16/22] efi_loader: enable TEE runtime QueryVariableInfo() over FF-A
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (14 preceding siblings ...)
  2026-09-14 11:00 ` [PATCH v5 15/22] efi_loader: enable TEE runtime GetNextVariableName() " Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 17/22] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	Harsimran Singh Tungal

Add the TEE-backed runtime QueryVariableInfo() implementation for the
FF-A/MM variable backend. The runtime path uses the shared MM
communication path after ExitBootServices() and returns the variable
storage limits reported by the MM secure partition.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v4:

Ilias:

- Split the runtime QueryVariableInfo() support out of the combined
  runtime variable-services patch.

v3:

Ilias:

- Rename TEE/FF-A runtime handlers to private *_int_runtime names
---
 lib/efi_loader/efi_variable_tee.c | 44 ++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 0de9949344e..3e4fd33dca6 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -1276,7 +1276,7 @@ out:
 }
 
 /**
- * efi_query_variable_info() - get information about EFI variables
+ * efi_query_variable_info_int_runtime() - get information about EFI variables
  *
  * This function implements the QueryVariableInfo() runtime service.
  *
@@ -1285,20 +1285,46 @@ 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
  */
 efi_status_t EFIAPI __efi_runtime
-efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
-				u64 *remain_variable_storage_size,
-				u64 *max_variable_size)
+efi_query_variable_info_int_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;
 }
 
 /**
@@ -1407,7 +1433,7 @@ void efi_variables_boot_exit_notify(void)
 
 	/* Update runtime service table */
 	efi_runtime_services.query_variable_info =
-			efi_query_variable_info_runtime;
+			efi_query_variable_info_int_runtime;
 	efi_runtime_services.get_variable = efi_get_variable_int_runtime;
 	efi_runtime_services.get_next_variable_name =
 			efi_get_next_variable_name_int_runtime;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 17/22] charset: mark u16_strsize() as __efi_runtime
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (15 preceding siblings ...)
  2026-09-14 11:01 ` [PATCH v5 16/22] efi_loader: enable TEE runtime QueryVariableInfo() " Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 18/22] corstone1000: enable bootefi selftest Harsimran Singh Tungal
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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().

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v2:

Simon:

- Split the `u16_strsize()` runtime annotation to a separate patch
---
 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] 35+ messages in thread

* [PATCH v5 18/22] corstone1000: enable bootefi selftest
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (16 preceding siblings ...)
  2026-09-14 11:01 ` [PATCH v5 17/22] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 19/22] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
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 876b915b6a4..e16b13043ac 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
@@ -62,6 +64,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] 35+ messages in thread

* [PATCH v5 19/22] efi: selftest: add runtime variable tests with non-volatile storage
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (17 preceding siblings ...)
  2026-09-14 11:01 ` [PATCH v5 18/22] corstone1000: enable bootefi selftest Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 20/22] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

- Fix the expected QueryVariableInfo() return status for the TEE-backed runtime path

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          | 715 ++++++++++++------
 1 file changed, 482 insertions(+), 233 deletions(-)

diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
index fd570d673f0..90ec568ca3a 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,294 +18,542 @@
 #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 {
 		ret = st_runtime->query_variable_info(
 			EFI_VARIABLE_BOOTSERVICE_ACCESS, &max_storage,
 			&rem_storage, &max_size);
-		if (ret != EFI_UNSUPPORTED) {
-			efi_st_error("QueryVariableInfo failed\n");
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("%s: QueryVariableInfo returned status=%x\n",
+				     phase, (u32)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] 35+ messages in thread

* [PATCH v5 20/22] test: dm: add sandbox FF-A runtime transport tests
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (18 preceding siblings ...)
  2026-09-14 11:01 ` [PATCH v5 19/22] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 21/22] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 22/22] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Drop (void)uts; from dm_test_ffa_to_std_errno()
- Refactor the repeated runtime setup/reset flow into shared helpers
- Use 0xffff in the nack test to hit the intended invalid-SP path
- Remove the stray blank line in the sandbox partition table

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 |  37 +++++--
 test/dm/Makefile                           |   3 +-
 test/dm/ffa_runtime.c                      | 123 +++++++++++++++++++++
 4 files changed, 166 insertions(+), 13 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..3351d2e2edd 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,42 +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,
-		}
-	}
-
+		},
+	},
 };
 
 /* The emulator functions */
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 76aa1fff9ba..2c213c95a09 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.
@@ -99,6 +99,7 @@ obj-$(CONFIG_CMD_PMBUS) += pmbus.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..3820628f86b
--- /dev/null
+++ b/test/dm/ffa_runtime.c
@@ -0,0 +1,123 @@
+// 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 void ffa_runtime_teardown(void)
+{
+	ffa_runtime_context_reset();
+}
+
+static int ffa_runtime_setup(struct unit_test_state *uts, u16 *sp_id)
+{
+	ffa_runtime_teardown();
+	ut_assert(!ffa_runtime_context_ready());
+	ut_assertok(ffa_runtime_prepare(uts, sp_id));
+
+	ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
+		.id = NS_PHYS_ENDPOINT_ID,
+	});
+	ffa_runtime_context_enable();
+
+	/* Ensure runtime context is available before attempting runtime-only paths */
+	ut_assert(ffa_runtime_context_ready());
+
+	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_runtime_teardown();
+	ut_assert(!ffa_runtime_context_ready());
+
+	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_runtime_teardown();
+	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)
+{
+	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;
+
+	ut_assertok(ffa_runtime_setup(uts, &sp_id));
+
+	/* 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_runtime_teardown();
+	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};
+
+	ut_assertok(ffa_runtime_setup(uts, NULL));
+
+	/* Invalid partition IDs must be rejected and mapped to -EINVAL */
+	ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0xffff, &msg, true));
+
+	ffa_runtime_teardown();
+	return 0;
+}
+
+DM_TEST(dm_test_ffa_runtime_nack, UTF_SCAN_FDT | UTF_CONSOLE);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v5 21/22] doc: arm64: document FF-A runtime path for EFI variables
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (19 preceding siblings ...)
  2026-09-14 11:01 ` [PATCH v5 20/22] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  2026-09-14 11:01 ` [PATCH v5 22/22] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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.

Reviewed-by: Simon Glass <sjg@chromium.org>
Acked-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Name the exported FF-A runtime entry points in the arm64
  documentation

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   | 88 ++++++++++++++++++++++++++++++++++++----
 doc/usage/cmd/armffa.rst | 11 +++++
 2 files changed, 92 insertions(+), 7 deletions(-)

diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
index f966f8ba6af..145bb70abce 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,73 @@ 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 helpers exported by ``include/arm_ffa_runtime.h``. In particular,
+``ffa_runtime_context_ready()`` verifies that the resident runtime context
+is available and ``ffa_sync_send_receive_runtime()`` issues direct FF-A
+messages after ExitBootServices().
+
+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 +329,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] 35+ messages in thread

* [PATCH v5 22/22] doc: bootefi: note two-phase runtime variables selftest
  2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
                   ` (20 preceding siblings ...)
  2026-09-14 11:01 ` [PATCH v5 21/22] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
@ 2026-09-14 11:01 ` Harsimran Singh Tungal
  21 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-09-14 11:01 UTC (permalink / raw)
  To: u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Ilias Apalodimas,
	Heinrich Schuchardt, Simon Glass, Devaraj Ranganna,
	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.

Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>

---
Changelog:
===============

v3:

Simon:

- Clarify the volatile-store runtime-variable test flow
- Note that the split-phase tests only run when selected through
  efi_selftest

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 | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
index 7c5448586b7..0a7800b93ce 100644
--- a/doc/usage/cmd/bootefi.rst
+++ b/doc/usage/cmd/bootefi.rst
@@ -160,6 +160,37 @@ 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 within one *bootefi selftest* run, so
+it does not depend on preserving state across multiple runs. It still
+executes ExitBootServices(), so a board reset is required afterwards
+before returning to the command line.
+
+::
+
+    => 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.
+Both phases are on-request tests, so they only run when selected by
+``efi_selftest``.
+
+::
+
+    => 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] 35+ messages in thread

* Re: [PATCH v5 08/22] efi_loader: add MM SP status mapping for FF-A variables
  2026-09-14 11:00 ` [PATCH v5 08/22] efi_loader: add MM SP status mapping for FF-A variables Harsimran Singh Tungal
@ 2026-09-18 17:19   ` Ilias Apalodimas
  0 siblings, 0 replies; 35+ messages in thread
From: Ilias Apalodimas @ 2026-09-18 17:19 UTC (permalink / raw)
  To: Harsimran Singh Tungal, u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt, Simon Glass,
	Devaraj Ranganna

On Mon Sep 14, 2026 at 2:00 PM EEST, Harsimran Singh Tungal wrote:
> Define the MM SP status values as an enum and add a runtime-safe helper
> for translating MM SP notification results to U-Boot errno values.
>
> The FF-A notification path uses the same mapping during boot and after
> ExitBootServices(), so keep the mapping table in EFI runtime rodata.
>
> Reviewed-by: Simon Glass <sjg@chromium.org>
> Reviewed-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
> Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
>

Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>

> ---
> Changelog:
> ===============
>
> v5:
>
> Ilias:
>
> - Include MM_SUCCESS in the MM SP response map
>
> v4:
>
> Ilias:
>
> - Replace MM status macros with an enum
>
> v3:
>
> Simon:
>
> - Add a comment explaining the sparse MM SP error map indexing
>
> v2:
>
> Ilias, Simon:
>
> - Reuse common MM SP error mapping
> ---
>  lib/efi_loader/efi_variable_tee.c | 50 ++++++++++++++++++++++++++-----
>  1 file changed, 43 insertions(+), 7 deletions(-)
>
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> index 6a1fa39bb6f..bc15795e94f 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>
> @@ -21,18 +21,34 @@
>  #include <efi_api.h>
>  #include <efi_loader.h>
>  #include <efi_variable.h>
> +#include <linux/kernel.h>
>  #include <malloc.h>
>  #include <mapmem.h>
>  #include <mm_communication.h>
>  #include <tee.h>
>
>  #if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> -/* MM return codes */
> -#define MM_SUCCESS (0)
> -#define MM_NOT_SUPPORTED (-1)
> -#define MM_INVALID_PARAMETER (-2)
> -#define MM_DENIED (-3)
> -#define MM_NO_MEMORY (-5)
> +enum mm_sp_status {
> +	MM_SUCCESS = 0,
> +	MM_NOT_SUPPORTED = -1,
> +	MM_INVALID_PARAMETER = -2,
> +	MM_DENIED = -3,
> +	MM_NO_MEMORY = -5,
> +};
> +
> +/*
> + * MM_* failure codes are negative. Use -MM_* as sparse positive indices so
> + * ffa_map_sp_event() can look up mm_sp_resp_map[-sp_event_ret]. The
> + * unassigned gap between MM_DENIED and MM_NO_MEMORY maps to -EACCES.
> + */
> +static const int __efi_runtime_rodata mm_sp_resp_map[] = {
> +	[MM_SUCCESS]		 = 0,
> +	[-MM_NOT_SUPPORTED]	 = -EINVAL,
> +	[-MM_INVALID_PARAMETER]	 = -EPERM,
> +	[-MM_DENIED]		 = -EACCES,
> +	[-MM_NO_MEMORY - 1]	 = -EACCES,
> +	[-MM_NO_MEMORY]		 = -EBUSY,
> +};
>
>  static const char *mm_sp_svc_uuid = MM_SP_UUID;
>  static u16 mm_sp_id;
> @@ -169,6 +185,26 @@ 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 (idx >= 0 && idx < (int)ARRAY_SIZE(mm_sp_resp_map))
> +		return mm_sp_resp_map[idx];
> +
> +	return -EACCES;
> +}
> +
>  /**
>   * ffa_notify_mm_sp() - Announce there is data in the shared buffer
>   *


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-09-14 11:00 ` [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A Harsimran Singh Tungal
@ 2026-09-18 18:20   ` Ilias Apalodimas
  2026-10-05 13:06     ` Harsimran Singh Tungal
  0 siblings, 1 reply; 35+ messages in thread
From: Ilias Apalodimas @ 2026-09-18 18:20 UTC (permalink / raw)
  To: Harsimran Singh Tungal, u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt, Simon Glass,
	Devaraj Ranganna

Hi Harsimran


[...]

> +							   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,
> @@ -768,6 +800,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)
> +{

The changes between this and the non-runtime version are limited to a few memcpy/memset calls.
It's pretty easy to only keep the runtime version and get rid of all the duplication. Same
goes for the set_property_int()

> +	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)
> +		return EFI_SUCCESS;
> +	if (ret != EFI_SUCCESS)
> +		return ret;
> +	efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
> +
> +	return EFI_SUCCESS;
> +}
> +
>  efi_status_t efi_get_variable_int(const u16 *variable_name,
>  				  const efi_guid_t *vendor,
>  				  u32 *attributes, efi_uintn_t *data_size,
> @@ -1001,7 +1076,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
>  		var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
>  		var_property.attributes = attributes;
>  		var_property.minsize = 1;
> -		var_property.maxsize = var_acc->data_size;
> +		var_property.maxsize = data_size;
>  		ret = set_property_int(variable_name, name_size, vendor, &var_property);
>  	}
>
> @@ -1078,7 +1153,7 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
>  }
>
>  /**
> - * efi_set_variable_runtime() - runtime implementation of SetVariable()
> + * efi_set_variable_int_runtime() - runtime implementation of SetVariable()
>   *
>   * @variable_name:	name of the variable
>   * @guid:		vendor GUID
> @@ -1088,11 +1163,69 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
>   * Return:		status code
>   */
>  static efi_status_t __efi_runtime EFIAPI
> -efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> -			 u32 attributes, efi_uintn_t data_size,
> -			 const void *data)
> +efi_set_variable_int_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 = data_size;
> +		ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
> +	}
> +
> +	return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
>  }
>
>  /**
> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
>  	efi_runtime_services.get_variable = efi_get_variable_runtime;
>  	efi_runtime_services.get_next_variable_name =
>  			efi_get_next_variable_name_runtime;


All the get_variable*() calls used to point to the function from efi_var_common.c.
By changing this you are breaking the runtime case for OP-TEE since now we will get
EFI_OUT_OF_RESOURCES.
There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
with an internal OP-TEE call if it's part of the firmware and announces it can provide
EFI runtime services. However, the default uuse case, which we don't support SetVariable
at runtime only needs to keep working.

I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.

Cheers
/Ilias

> -	efi_runtime_services.set_variable = efi_set_variable_runtime;
> +	efi_runtime_services.set_variable = efi_set_variable_int_runtime;
>  	efi_update_table_header_crc32(&efi_runtime_services.hdr);
>
>  	/* Record that ExitBootServices() has been called */


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables
  2026-09-14 11:00 ` [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables Harsimran Singh Tungal
@ 2026-09-18 18:30   ` Ilias Apalodimas
  2026-10-05 11:12     ` Harsimran Singh Tungal
  0 siblings, 1 reply; 35+ messages in thread
From: Ilias Apalodimas @ 2026-09-18 18:30 UTC (permalink / raw)
  To: Harsimran Singh Tungal, u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt, Simon Glass,
	Devaraj Ranganna

Hi Harsimran

>
>  /**
> - * 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.
> + *
> + * The caller owns the returned buffer only during the boot phase and
> + * must release it with free(). During the runtime phase, the returned
> + * pointer aliases the static FF-A shared buffer and must not be freed.
> + *
> + * Return:
> + *   Pointer to a valid communication buffer on success.
> + *   NULL if no suitable communication buffer is available.
> + */
> +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 CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> +		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, comm_buf_size);
> +		} else {
> +			return NULL;

This is problematic for the existing use case. With  the changes in the later patches
that swap all runtime call unconditionally every call to setup_mm_hdr() will return
EFI_OUT_OF_RESOURCES and none of the runtime services will work without FF-A.
There's nothing elegant we can do about this .We either Let the fucntions from efi_var_common.c
deal with the runtime part (which I think I prefer), or we define a similar runtime
available buffer for comm_buf.

> +		}
> +#else
> +		return NULL;
> +#endif
> +	} else {
> +		comm_buf = calloc(1, comm_buf_size);
> +		if (!comm_buf)
> +			return NULL;
> +	}
> +	return comm_buf;
> +}
> +
> +/**
> +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;
> @@ -555,16 +615,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;
> @@ -1077,6 +1136,20 @@ void efi_variables_boot_exit_notify(void)
>  	ebs_called = true;
>  }
>
> +/**
> + * ffa_shared_buf_notify_virtual_address_map() - SetVirtualAddressMap callback
> + *
> + * @event:	callback event
> + * @context:	callback context
> + */
> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> +static void EFIAPI __efi_runtime
> +ffa_shared_buf_notify_virtual_address_map(struct efi_event *event, void *context)
> +{
> +	efi_convert_pointer(0, (void **)&ffa_shared_buf);
> +}
> +#endif
> +
>  /**
>   * efi_init_variables() - initialize variable services
>   *
> @@ -1085,6 +1158,9 @@ void efi_variables_boot_exit_notify(void)
>  efi_status_t efi_init_variables(void)
>  {
>  	efi_status_t ret;
> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> +	struct efi_event *event;
> +#endif
>
>  	/* Create a cached copy of the variables that will be enabled on ExitBootServices() */
>  	ret = efi_var_mem_init();
> @@ -1103,5 +1179,37 @@ efi_status_t efi_init_variables(void)
>  	if (ret != EFI_SUCCESS)
>  		return ret;
>
> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> +	if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> +		/*
> +		 * The FF-A shared buffer is accessed by EFI runtime services, so
> +		 * keep the resident pointer convertible across
> +		 * SetVirtualAddressMap() and mark the region as runtime memory.
> +		 *
> +		 * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
> +		 */
> +		BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR & EFI_PAGE_MASK);
> +		ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> +		ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
> +				       TPL_CALLBACK,
> +				       ffa_shared_buf_notify_virtual_address_map,
> +				       NULL, NULL, &event);
> +		if (ret != EFI_SUCCESS)
> +			return ret;
> +		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) {
> +			efi_close_event(event);
> +			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);
> +	}
> +#endif
> +
>  	return EFI_SUCCESS;
>  }


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables
  2026-09-18 18:30   ` Ilias Apalodimas
@ 2026-10-05 11:12     ` Harsimran Singh Tungal
  2026-10-05 11:51       ` Ilias Apalodimas
  0 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-10-05 11:12 UTC (permalink / raw)
  To: Ilias Apalodimas, u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt, Simon Glass,
	Devaraj Ranganna



On 18/09/2026 19:30, Ilias Apalodimas wrote:
> Hi Harsimran
>
>>
>>  /**
>> - * 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.
>> + *
>> + * The caller owns the returned buffer only during the boot phase and
>> + * must release it with free(). During the runtime phase, the returned
>> + * pointer aliases the static FF-A shared buffer and must not be freed.
>> + *
>> + * Return:
>> + *   Pointer to a valid communication buffer on success.
>> + *   NULL if no suitable communication buffer is available.
>> + */
>> +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 CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
>> +            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, comm_buf_size);
>> +            } else {
>> +                    return NULL;
>
> This is problematic for the existing use case. With  the changes in the later patches
> that swap all runtime call unconditionally every call to setup_mm_hdr() will return
> EFI_OUT_OF_RESOURCES and none of the runtime services will work without FF-A.
> There's nothing elegant we can do about this .We either Let the fucntions from efi_var_common.c
> deal with the runtime part (which I think I prefer), or we define a similar runtime
> available buffer for comm_buf.
>
Thanks Ilias.

Yes, I agree this would break the existing non-FF-A runtime path once
the later patches install the TEE runtime handlers unconditionally.

I am planning to keep the existing efi_var_common.c runtime handlers for
the non-FF-A case, and only replace the runtime service table with the
TEE/FF-A runtime handlers when CONFIG_ARM_FFA_RT_MODE is enabled. That
keeps the existing OP-TEE behaviour unchanged, while the FF-A runtime
transport continues to use the static shared buffer after
ExitBootServices().

Does that approach make sense to you?

Regards
Harsimran Singh Tungal>> +              }
>> +#else
>> +            return NULL;
>> +#endif
>> +    } else {
>> +            comm_buf = calloc(1, comm_buf_size);
>> +            if (!comm_buf)
>> +                    return NULL;
>> +    }
>> +    return comm_buf;
>> +}
>> +
>> +/**
>> +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;
>> @@ -555,16 +615,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;
>> @@ -1077,6 +1136,20 @@ void efi_variables_boot_exit_notify(void)
>>      ebs_called = true;
>>  }
>>
>> +/**
>> + * ffa_shared_buf_notify_virtual_address_map() - SetVirtualAddressMap callback
>> + *
>> + * @event:  callback event
>> + * @context:        callback context
>> + */
>> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
>> +static void EFIAPI __efi_runtime
>> +ffa_shared_buf_notify_virtual_address_map(struct efi_event *event, void *context)
>> +{
>> +    efi_convert_pointer(0, (void **)&ffa_shared_buf);
>> +}
>> +#endif
>> +
>>  /**
>>   * efi_init_variables() - initialize variable services
>>   *
>> @@ -1085,6 +1158,9 @@ void efi_variables_boot_exit_notify(void)
>>  efi_status_t efi_init_variables(void)
>>  {
>>      efi_status_t ret;
>> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
>> +    struct efi_event *event;
>> +#endif
>>
>>      /* Create a cached copy of the variables that will be enabled on ExitBootServices() */
>>      ret = efi_var_mem_init();
>> @@ -1103,5 +1179,37 @@ efi_status_t efi_init_variables(void)
>>      if (ret != EFI_SUCCESS)
>>              return ret;
>>
>> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
>> +    if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
>> +            /*
>> +             * The FF-A shared buffer is accessed by EFI runtime services, so
>> +             * keep the resident pointer convertible across
>> +             * SetVirtualAddressMap() and mark the region as runtime memory.
>> +             *
>> +             * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
>> +             */
>> +            BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR & EFI_PAGE_MASK);
>> +            ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
>> +            ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
>> +                                   TPL_CALLBACK,
>> +                                   ffa_shared_buf_notify_virtual_address_map,
>> +                                   NULL, NULL, &event);
>> +            if (ret != EFI_SUCCESS)
>> +                    return ret;
>> +            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) {
>> +                    efi_close_event(event);
>> +                    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);
>> +    }
>> +#endif
>> +
>>      return EFI_SUCCESS;
>>  }
>

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables
  2026-10-05 11:12     ` Harsimran Singh Tungal
@ 2026-10-05 11:51       ` Ilias Apalodimas
  0 siblings, 0 replies; 35+ messages in thread
From: Ilias Apalodimas @ 2026-10-05 11:51 UTC (permalink / raw)
  To: Harsimran Singh Tungal
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna

On Mon, 5 Oct 2026 at 14:13, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
>
>
> On 18/09/2026 19:30, Ilias Apalodimas wrote:
> > Hi Harsimran
> >
> >>
> >>  /**
> >> - * 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.
> >> + *
> >> + * The caller owns the returned buffer only during the boot phase and
> >> + * must release it with free(). During the runtime phase, the returned
> >> + * pointer aliases the static FF-A shared buffer and must not be freed.
> >> + *
> >> + * Return:
> >> + *   Pointer to a valid communication buffer on success.
> >> + *   NULL if no suitable communication buffer is available.
> >> + */
> >> +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 CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
> >> +            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, comm_buf_size);
> >> +            } else {
> >> +                    return NULL;
> >
> > This is problematic for the existing use case. With  the changes in the later patches
> > that swap all runtime call unconditionally every call to setup_mm_hdr() will return
> > EFI_OUT_OF_RESOURCES and none of the runtime services will work without FF-A.
> > There's nothing elegant we can do about this .We either Let the fucntions from efi_var_common.c
> > deal with the runtime part (which I think I prefer), or we define a similar runtime
> > available buffer for comm_buf.
> >
> Thanks Ilias.
>
> Yes, I agree this would break the existing non-FF-A runtime path once
> the later patches install the TEE runtime handlers unconditionally.
>
> I am planning to keep the existing efi_var_common.c runtime handlers for
> the non-FF-A case, and only replace the runtime service table with the
> TEE/FF-A runtime handlers when CONFIG_ARM_FFA_RT_MODE is enabled. That
> keeps the existing OP-TEE behaviour unchanged, while the FF-A runtime
> transport continues to use the static shared buffer after
> ExitBootServices().
>
> Does that approach make sense to you?
>

Yes it does

Thanks
/Ilias
> Regards
> Harsimran Singh Tungal>> +              }
> >> +#else
> >> +            return NULL;
> >> +#endif
> >> +    } else {
> >> +            comm_buf = calloc(1, comm_buf_size);
> >> +            if (!comm_buf)
> >> +                    return NULL;
> >> +    }
> >> +    return comm_buf;
> >> +}
> >> +
> >> +/**
> >> +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;
> >> @@ -555,16 +615,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;
> >> @@ -1077,6 +1136,20 @@ void efi_variables_boot_exit_notify(void)
> >>      ebs_called = true;
> >>  }
> >>
> >> +/**
> >> + * ffa_shared_buf_notify_virtual_address_map() - SetVirtualAddressMap callback
> >> + *
> >> + * @event:  callback event
> >> + * @context:        callback context
> >> + */
> >> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> >> +static void EFIAPI __efi_runtime
> >> +ffa_shared_buf_notify_virtual_address_map(struct efi_event *event, void *context)
> >> +{
> >> +    efi_convert_pointer(0, (void **)&ffa_shared_buf);
> >> +}
> >> +#endif
> >> +
> >>  /**
> >>   * efi_init_variables() - initialize variable services
> >>   *
> >> @@ -1085,6 +1158,9 @@ void efi_variables_boot_exit_notify(void)
> >>  efi_status_t efi_init_variables(void)
> >>  {
> >>      efi_status_t ret;
> >> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> >> +    struct efi_event *event;
> >> +#endif
> >>
> >>      /* Create a cached copy of the variables that will be enabled on ExitBootServices() */
> >>      ret = efi_var_mem_init();
> >> @@ -1103,5 +1179,37 @@ efi_status_t efi_init_variables(void)
> >>      if (ret != EFI_SUCCESS)
> >>              return ret;
> >>
> >> +#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)
> >> +    if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> >> +            /*
> >> +             * The FF-A shared buffer is accessed by EFI runtime services, so
> >> +             * keep the resident pointer convertible across
> >> +             * SetVirtualAddressMap() and mark the region as runtime memory.
> >> +             *
> >> +             * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
> >> +             */
> >> +            BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR & EFI_PAGE_MASK);
> >> +            ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> >> +            ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
> >> +                                   TPL_CALLBACK,
> >> +                                   ffa_shared_buf_notify_virtual_address_map,
> >> +                                   NULL, NULL, &event);
> >> +            if (ret != EFI_SUCCESS)
> >> +                    return ret;
> >> +            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) {
> >> +                    efi_close_event(event);
> >> +                    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);
> >> +    }
> >> +#endif
> >> +
> >>      return EFI_SUCCESS;
> >>  }
> >
>
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-09-18 18:20   ` Ilias Apalodimas
@ 2026-10-05 13:06     ` Harsimran Singh Tungal
  2026-10-05 13:15       ` Ilias Apalodimas
  0 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-10-05 13:06 UTC (permalink / raw)
  To: Ilias Apalodimas, u-boot
  Cc: Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt, Simon Glass,
	Devaraj Ranganna



On 18/09/2026 19:20, Ilias Apalodimas wrote:
> Hi Harsimran
>
>
> [...]
>
>> +                                                       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,
>> @@ -768,6 +800,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)
>> +{
>
> The changes between this and the non-runtime version are limited to a few memcpy/memset calls.
> It's pretty easy to only keep the runtime version and get rid of all the duplication. Same
> goes for the set_property_int()
>
>> +    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)
>> +            return EFI_SUCCESS;
>> +    if (ret != EFI_SUCCESS)
>> +            return ret;
>> +    efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
>> +
>> +    return EFI_SUCCESS;
>> +}
>> +
>>  efi_status_t efi_get_variable_int(const u16 *variable_name,
>>                                const efi_guid_t *vendor,
>>                                u32 *attributes, efi_uintn_t *data_size,
>> @@ -1001,7 +1076,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
>>              var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
>>              var_property.attributes = attributes;
>>              var_property.minsize = 1;
>> -            var_property.maxsize = var_acc->data_size;
>> +            var_property.maxsize = data_size;
>>              ret = set_property_int(variable_name, name_size, vendor, &var_property);
>>      }
>>
>> @@ -1078,7 +1153,7 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
>>  }
>>
>>  /**
>> - * efi_set_variable_runtime() - runtime implementation of SetVariable()
>> + * efi_set_variable_int_runtime() - runtime implementation of SetVariable()
>>   *
>>   * @variable_name:  name of the variable
>>   * @guid:           vendor GUID
>> @@ -1088,11 +1163,69 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
>>   * Return:          status code
>>   */
>>  static efi_status_t __efi_runtime EFIAPI
>> -efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
>> -                     u32 attributes, efi_uintn_t data_size,
>> -                     const void *data)
>> +efi_set_variable_int_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 = data_size;
>> +            ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
>> +    }
>> +
>> +    return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
>>  }
>>
>>  /**
>> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
>>      efi_runtime_services.get_variable = efi_get_variable_runtime;
>>      efi_runtime_services.get_next_variable_name =
>>                      efi_get_next_variable_name_runtime;
>
>
> All the get_variable*() calls used to point to the function from efi_var_common.c.
> By changing this you are breaking the runtime case for OP-TEE since now we will get
> EFI_OUT_OF_RESOURCES.
> There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
> with an internal OP-TEE call if it's part of the firmware and announces it can provide
> EFI runtime services. However, the default uuse case, which we don't support SetVariable
> at runtime only needs to keep working.
>
> I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
>
> Cheers
> /Ilias
>
Hi Ilias,
Can you please share the script, so that I can replicate and test this
in QEMU with OP-TEE?

Thanks
Harsimran Singh Tungal
>> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
>> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
>>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
>>
>>      /* Record that ExitBootServices() has been called */
>

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-10-05 13:06     ` Harsimran Singh Tungal
@ 2026-10-05 13:15       ` Ilias Apalodimas
  2026-10-08 17:32         ` Harsimran Singh Tungal
  0 siblings, 1 reply; 35+ messages in thread
From: Ilias Apalodimas @ 2026-10-05 13:15 UTC (permalink / raw)
  To: Harsimran Singh Tungal
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna

On Mon, 5 Oct 2026 at 16:06, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
>
>
> On 18/09/2026 19:20, Ilias Apalodimas wrote:
> > Hi Harsimran
> >
> >
> > [...]
> >
> >> +                                                       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,
> >> @@ -768,6 +800,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)
> >> +{
> >
> > The changes between this and the non-runtime version are limited to a few memcpy/memset calls.
> > It's pretty easy to only keep the runtime version and get rid of all the duplication. Same
> > goes for the set_property_int()
> >
> >> +    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)
> >> +            return EFI_SUCCESS;
> >> +    if (ret != EFI_SUCCESS)
> >> +            return ret;
> >> +    efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
> >> +
> >> +    return EFI_SUCCESS;
> >> +}
> >> +
> >>  efi_status_t efi_get_variable_int(const u16 *variable_name,
> >>                                const efi_guid_t *vendor,
> >>                                u32 *attributes, efi_uintn_t *data_size,
> >> @@ -1001,7 +1076,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
> >>              var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
> >>              var_property.attributes = attributes;
> >>              var_property.minsize = 1;
> >> -            var_property.maxsize = var_acc->data_size;
> >> +            var_property.maxsize = data_size;
> >>              ret = set_property_int(variable_name, name_size, vendor, &var_property);
> >>      }
> >>
> >> @@ -1078,7 +1153,7 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
> >>  }
> >>
> >>  /**
> >> - * efi_set_variable_runtime() - runtime implementation of SetVariable()
> >> + * efi_set_variable_int_runtime() - runtime implementation of SetVariable()
> >>   *
> >>   * @variable_name:  name of the variable
> >>   * @guid:           vendor GUID
> >> @@ -1088,11 +1163,69 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
> >>   * Return:          status code
> >>   */
> >>  static efi_status_t __efi_runtime EFIAPI
> >> -efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
> >> -                     u32 attributes, efi_uintn_t data_size,
> >> -                     const void *data)
> >> +efi_set_variable_int_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 = data_size;
> >> +            ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
> >> +    }
> >> +
> >> +    return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
> >>  }
> >>
> >>  /**
> >> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
> >>      efi_runtime_services.get_variable = efi_get_variable_runtime;
> >>      efi_runtime_services.get_next_variable_name =
> >>                      efi_get_next_variable_name_runtime;
> >
> >
> > All the get_variable*() calls used to point to the function from efi_var_common.c.
> > By changing this you are breaking the runtime case for OP-TEE since now we will get
> > EFI_OUT_OF_RESOURCES.
> > There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
> > with an internal OP-TEE call if it's part of the firmware and announces it can provide
> > EFI runtime services. However, the default uuse case, which we don't support SetVariable
> > at runtime only needs to keep working.
> >
> > I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
> >
> > Cheers
> > /Ilias
> >
> Hi Ilias,
> Can you please share the script, so that I can replicate and test this
> in QEMU with OP-TEE?

https://github.com/apalos/efi_optee_variables

make run-fip should give you a QEMU command line. You just have to add
an OS image to test.

Cheers
/Ilias
>
> Thanks
> Harsimran Singh Tungal
> >> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
> >> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
> >>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
> >>
> >>      /* Record that ExitBootServices() has been called */
> >
>
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-10-05 13:15       ` Ilias Apalodimas
@ 2026-10-08 17:32         ` Harsimran Singh Tungal
  2026-10-09  8:19           ` Ilias Apalodimas
  0 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-10-08 17:32 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna



On 05/10/2026 14:15, Ilias Apalodimas wrote:
> On Mon, 5 Oct 2026 at 16:06, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
>>
>>
>>
>> On 18/09/2026 19:20, Ilias Apalodimas wrote:
>>> Hi Harsimran
>>>
>>>
>>> [...]
>>>
>>>> +                                                       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,
>>>> @@ -768,6 +800,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)
>>>> +{
>>>
>>> The changes between this and the non-runtime version are limited to a few memcpy/memset calls.
>>> It's pretty easy to only keep the runtime version and get rid of all the duplication. Same
>>> goes for the set_property_int()
>>>
>>>> +    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)
>>>> +            return EFI_SUCCESS;
>>>> +    if (ret != EFI_SUCCESS)
>>>> +            return ret;
>>>> +    efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
>>>> +
>>>> +    return EFI_SUCCESS;
>>>> +}
>>>> +
>>>>  efi_status_t efi_get_variable_int(const u16 *variable_name,
>>>>                                const efi_guid_t *vendor,
>>>>                                u32 *attributes, efi_uintn_t *data_size,
>>>> @@ -1001,7 +1076,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name,
>>>>              var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
>>>>              var_property.attributes = attributes;
>>>>              var_property.minsize = 1;
>>>> -            var_property.maxsize = var_acc->data_size;
>>>> +            var_property.maxsize = data_size;
>>>>              ret = set_property_int(variable_name, name_size, vendor, &var_property);
>>>>      }
>>>>
>>>> @@ -1078,7 +1153,7 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
>>>>  }
>>>>
>>>>  /**
>>>> - * efi_set_variable_runtime() - runtime implementation of SetVariable()
>>>> + * efi_set_variable_int_runtime() - runtime implementation of SetVariable()
>>>>   *
>>>>   * @variable_name:  name of the variable
>>>>   * @guid:           vendor GUID
>>>> @@ -1088,11 +1163,69 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
>>>>   * Return:          status code
>>>>   */
>>>>  static efi_status_t __efi_runtime EFIAPI
>>>> -efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
>>>> -                     u32 attributes, efi_uintn_t data_size,
>>>> -                     const void *data)
>>>> +efi_set_variable_int_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 = data_size;
>>>> +            ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
>>>> +    }
>>>> +
>>>> +    return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
>>>>  }
>>>>
>>>>  /**
>>>> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
>>>>      efi_runtime_services.get_variable = efi_get_variable_runtime;
>>>>      efi_runtime_services.get_next_variable_name =
>>>>                      efi_get_next_variable_name_runtime;
>>>
>>>
>>> All the get_variable*() calls used to point to the function from efi_var_common.c.
>>> By changing this you are breaking the runtime case for OP-TEE since now we will get
>>> EFI_OUT_OF_RESOURCES.
>>> There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
>>> with an internal OP-TEE call if it's part of the firmware and announces it can provide
>>> EFI runtime services. However, the default uuse case, which we don't support SetVariable
>>> at runtime only needs to keep working.
>>>
>>> I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
>>>
>>> Cheers
>>> /Ilias
>>>
>> Hi Ilias,
>> Can you please share the script, so that I can replicate and test this
>> in QEMU with OP-TEE?
>
> https://github.com/apalos/efi_optee_variables
>
> make run-fip should give you a QEMU command line. You just have to add
> an OS image to test.
>
> Cheers
> /Ilias
>>

Hi Ilias,

Thank you for sharing the repository and instructions.
I tried the OP-TEE/non-FF-A QEMU setup from your repository and it
exposed a regression in my current series.

With CONFIG_EFI_MM_COMM_TEE=y and CONFIG_ARM_FFA_RT_MODE=n, Linux hit
an EFI runtime paging fault when booted through U-Boot EFI. The reason
was that TEE ExitBootServices() path only installed runtime variable
callbacks inside the CONFIG_ARM_FFA_RT_MODE path. That kept the FF-A
case working, but it accidentally stopped the non-FF-A OP-TEE case from
switching to the existing cached-variable runtime callbacks.

I tested a fix by keeping the FF-A/MM runtime callbacks only for
CONFIG_ARM_FFA_RT_MODE=y, and using the common cached-variable runtime
callbacks when CONFIG_ARM_FFA_RT_MODE=n. To make that clean, I plan to
add a small separate commit which moves the common runtime
QueryVariableInfo() and SetVariable() helpers, plus their shared
SetVariable() validation helper, from efi_variable.c into
efi_var_common.c. Then, efi_variable_tee.c can select either the common
cached-variable runtime handlers for OP-TEE/non-FF-A, or the new MM/FF-A
runtime handlers for FF-A runtime mode.

With that change, the same QEMU setup boots Linux through bootefi and a
small initramfs, /sys/firmware/efi is present, and efivarfs mounts
successfully.

Does this direction look reasonable to you?

Regards,
Harsimran Singh Tungal
>> Thanks
>> Harsimran Singh Tungal
>>>> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
>>>> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
>>>>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
>>>>
>>>>      /* Record that ExitBootServices() has been called */
>>>
>>
>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-10-08 17:32         ` Harsimran Singh Tungal
@ 2026-10-09  8:19           ` Ilias Apalodimas
  2026-10-09 11:08             ` Harsimran Singh Tungal
  0 siblings, 1 reply; 35+ messages in thread
From: Ilias Apalodimas @ 2026-10-09  8:19 UTC (permalink / raw)
  To: Harsimran Singh Tungal
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna

[...]

> >>>>  /**
> >>>> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
> >>>>      efi_runtime_services.get_variable = efi_get_variable_runtime;
> >>>>      efi_runtime_services.get_next_variable_name =
> >>>>                      efi_get_next_variable_name_runtime;
> >>>
> >>>
> >>> All the get_variable*() calls used to point to the function from efi_var_common.c.
> >>> By changing this you are breaking the runtime case for OP-TEE since now we will get
> >>> EFI_OUT_OF_RESOURCES.
> >>> There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
> >>> with an internal OP-TEE call if it's part of the firmware and announces it can provide
> >>> EFI runtime services. However, the default uuse case, which we don't support SetVariable
> >>> at runtime only needs to keep working.
> >>>
> >>> I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
> >>>
> >>> Cheers
> >>> /Ilias
> >>>
> >> Hi Ilias,
> >> Can you please share the script, so that I can replicate and test this
> >> in QEMU with OP-TEE?
> >
> > https://github.com/apalos/efi_optee_variables
> >
> > make run-fip should give you a QEMU command line. You just have to add
> > an OS image to test.
> >
> > Cheers
> > /Ilias
> >>
>
> Hi Ilias,
>
> Thank you for sharing the repository and instructions.
> I tried the OP-TEE/non-FF-A QEMU setup from your repository and it
> exposed a regression in my current series.
>
> With CONFIG_EFI_MM_COMM_TEE=y and CONFIG_ARM_FFA_RT_MODE=n, Linux hit
> an EFI runtime paging fault when booted through U-Boot EFI. The reason
> was that TEE ExitBootServices() path only installed runtime variable
> callbacks inside the CONFIG_ARM_FFA_RT_MODE path. That kept the FF-A
> case working, but it accidentally stopped the non-FF-A OP-TEE case from
> switching to the existing cached-variable runtime callbacks.
>
> I tested a fix by keeping the FF-A/MM runtime callbacks only for
> CONFIG_ARM_FFA_RT_MODE=y, and using the common cached-variable runtime
> callbacks when CONFIG_ARM_FFA_RT_MODE=n. To make that clean, I plan to
> add a small separate commit which moves the common runtime
> QueryVariableInfo() and SetVariable() helpers, plus their shared
> SetVariable() validation helper, from efi_variable.c into
> efi_var_common.c.

I am not sure I understand the plan. efi_var_common.c already has
callback for the above, it calls the _int variable for each service.

Thanks
/Ilias
> Then, efi_variable_tee.c can select either the common
> cached-variable runtime handlers for OP-TEE/non-FF-A, or the new MM/FF-A
> runtime handlers for FF-A runtime mode.
>
> With that change, the same QEMU setup boots Linux through bootefi and a
> small initramfs, /sys/firmware/efi is present, and efivarfs mounts
> successfully.
>
> Does this direction look reasonable to you?
>
> Regards,
> Harsimran Singh Tungal
> >> Thanks
> >> Harsimran Singh Tungal
> >>>> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
> >>>> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
> >>>>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
> >>>>
> >>>>      /* Record that ExitBootServices() has been called */
> >>>
> >>
> >> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
>
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-10-09  8:19           ` Ilias Apalodimas
@ 2026-10-09 11:08             ` Harsimran Singh Tungal
  2026-10-09 11:15               ` Ilias Apalodimas
  0 siblings, 1 reply; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-10-09 11:08 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna



On 09/10/2026 09:19, Ilias Apalodimas wrote:
> [...]
>
>>>>>>  /**
>>>>>> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
>>>>>>      efi_runtime_services.get_variable = efi_get_variable_runtime;
>>>>>>      efi_runtime_services.get_next_variable_name =
>>>>>>                      efi_get_next_variable_name_runtime;
>>>>>
>>>>>
>>>>> All the get_variable*() calls used to point to the function from efi_var_common.c.
>>>>> By changing this you are breaking the runtime case for OP-TEE since now we will get
>>>>> EFI_OUT_OF_RESOURCES.
>>>>> There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
>>>>> with an internal OP-TEE call if it's part of the firmware and announces it can provide
>>>>> EFI runtime services. However, the default uuse case, which we don't support SetVariable
>>>>> at runtime only needs to keep working.
>>>>>
>>>>> I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
>>>>>
>>>>> Cheers
>>>>> /Ilias
>>>>>
>>>> Hi Ilias,
>>>> Can you please share the script, so that I can replicate and test this
>>>> in QEMU with OP-TEE?
>>>
>>> https://github.com/apalos/efi_optee_variables
>>>
>>> make run-fip should give you a QEMU command line. You just have to add
>>> an OS image to test.
>>>
>>> Cheers
>>> /Ilias
>>>>
>>
>> Hi Ilias,
>>
>> Thank you for sharing the repository and instructions.
>> I tried the OP-TEE/non-FF-A QEMU setup from your repository and it
>> exposed a regression in my current series.
>>
>> With CONFIG_EFI_MM_COMM_TEE=y and CONFIG_ARM_FFA_RT_MODE=n, Linux hit
>> an EFI runtime paging fault when booted through U-Boot EFI. The reason
>> was that TEE ExitBootServices() path only installed runtime variable
>> callbacks inside the CONFIG_ARM_FFA_RT_MODE path. That kept the FF-A
>> case working, but it accidentally stopped the non-FF-A OP-TEE case from
>> switching to the existing cached-variable runtime callbacks.
>>
>> I tested a fix by keeping the FF-A/MM runtime callbacks only for
>> CONFIG_ARM_FFA_RT_MODE=y, and using the common cached-variable runtime
>> callbacks when CONFIG_ARM_FFA_RT_MODE=n. To make that clean, I plan to
>> add a small separate commit which moves the common runtime
>> QueryVariableInfo() and SetVariable() helpers, plus their shared
>> SetVariable() validation helper, from efi_variable.c into
>> efi_var_common.c.
>
> I am not sure I understand the plan. efi_var_common.c already has
> callback for the above, it calls the _int variable for each service.
>
> Thanks
> /Ilias

Hi Ilias,
Thanks, I rechecked the pre-FF-A runtime TEE code and I understand the
confusion now.







Before the FF-A runtime changes, efi_variable_tee.c already had local
runtime callbacks for QueryVariableInfo() and SetVariable(), and both
returned EFI_UNSUPPORTED as follows:

      static efi_status_t __efi_runtime EFIAPI
      efi_query_variable_info_runtime(u32 attributes,
                                      u64 *max_variable_storage_size,
                                      u64 *remain_variable_storage_size,
                                      u64 *max_variable_size)
      {
              return EFI_UNSUPPORTED;
      }

      static efi_status_t __efi_runtime EFIAPI
      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;
      }

The common callbacks from efi_var_common.c covered GetVariable() and
GetNextVariableName().

The regression was introduced because this series only installed and
renamed the TEE runtime callbacks when CONFIG_ARM_FFA_RT_MODE was
enabled. That made the FF-A case work, but it skipped the previous
OP-TEE/non-FF-A runtime callback setup.

I am planning to restore the pre-FF-A TEE behavior when
CONFIG_ARM_FFA_RT_MODE=n, and only switch to the new MM/FF-A callbacks
when CONFIG_ARM_FFA_RT_MODE=y. The relevant part now looks like below
along redefining efi_query_variable_info_runtime() and
efi_set_variable_runtime() as before in efi_variable_tee.c returning
EFI_UNSUPPORTED:

      if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
              efi_runtime_services.query_variable_info =
                              efi_query_variable_info_int_runtime;
              efi_runtime_services.get_variable =
efi_get_variable_int_runtime;
              efi_runtime_services.get_next_variable_name =
                              efi_get_next_variable_name_int_runtime;
              efi_runtime_services.set_variable =
efi_set_variable_int_runtime;
      } else {
              efi_runtime_services.query_variable_info =
                              efi_query_variable_info_runtime;
              efi_runtime_services.get_variable = efi_get_variable_runtime;
              efi_runtime_services.get_next_variable_name =
                              efi_get_next_variable_name_runtime;
              efi_runtime_services.set_variable = efi_set_variable_runtime;
      }
      efi_update_table_header_crc32(&efi_runtime_services.hdr);

With this, the OP-TEE/non-FF-A case uses the same callbacks as before
the FF-A runtime changes. I tested it with your QEMU OP-TEE setup and it
looks fine to me.

Does this approach make sense to you?


>> Then, efi_variable_tee.c can select either the common
>> cached-variable runtime handlers for OP-TEE/non-FF-A, or the new MM/FF-A
>> runtime handlers for FF-A runtime mode.
>>
>> With that change, the same QEMU setup boots Linux through bootefi and a
>> small initramfs, /sys/firmware/efi is present, and efivarfs mounts
>> successfully.
>>
>> Does this direction look reasonable to you?
>>
>> Regards,
>> Harsimran Singh Tungal
>>>> Thanks
>>>> Harsimran Singh Tungal
>>>>>> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
>>>>>> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
>>>>>>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
>>>>>>
>>>>>>      /* Record that ExitBootServices() has been called */
>>>>>
>>>>
>>>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
>>
>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-10-09 11:08             ` Harsimran Singh Tungal
@ 2026-10-09 11:15               ` Ilias Apalodimas
  2026-10-09 13:25                 ` Harsimran Singh Tungal
  0 siblings, 1 reply; 35+ messages in thread
From: Ilias Apalodimas @ 2026-10-09 11:15 UTC (permalink / raw)
  To: Harsimran Singh Tungal
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna

On Fri, 9 Oct 2026 at 14:08, Harsimran Singh Tungal
<harsimransingh.tungal@arm.com> wrote:
>
>
>
> On 09/10/2026 09:19, Ilias Apalodimas wrote:
> > [...]
> >
> >>>>>>  /**
> >>>>>> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
> >>>>>>      efi_runtime_services.get_variable = efi_get_variable_runtime;
> >>>>>>      efi_runtime_services.get_next_variable_name =
> >>>>>>                      efi_get_next_variable_name_runtime;
> >>>>>
> >>>>>
> >>>>> All the get_variable*() calls used to point to the function from efi_var_common.c.
> >>>>> By changing this you are breaking the runtime case for OP-TEE since now we will get
> >>>>> EFI_OUT_OF_RESOURCES.
> >>>>> There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
> >>>>> with an internal OP-TEE call if it's part of the firmware and announces it can provide
> >>>>> EFI runtime services. However, the default uuse case, which we don't support SetVariable
> >>>>> at runtime only needs to keep working.
> >>>>>
> >>>>> I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
> >>>>>
> >>>>> Cheers
> >>>>> /Ilias
> >>>>>
> >>>> Hi Ilias,
> >>>> Can you please share the script, so that I can replicate and test this
> >>>> in QEMU with OP-TEE?
> >>>
> >>> https://github.com/apalos/efi_optee_variables
> >>>
> >>> make run-fip should give you a QEMU command line. You just have to add
> >>> an OS image to test.
> >>>
> >>> Cheers
> >>> /Ilias
> >>>>
> >>
> >> Hi Ilias,
> >>
> >> Thank you for sharing the repository and instructions.
> >> I tried the OP-TEE/non-FF-A QEMU setup from your repository and it
> >> exposed a regression in my current series.
> >>
> >> With CONFIG_EFI_MM_COMM_TEE=y and CONFIG_ARM_FFA_RT_MODE=n, Linux hit
> >> an EFI runtime paging fault when booted through U-Boot EFI. The reason
> >> was that TEE ExitBootServices() path only installed runtime variable
> >> callbacks inside the CONFIG_ARM_FFA_RT_MODE path. That kept the FF-A
> >> case working, but it accidentally stopped the non-FF-A OP-TEE case from
> >> switching to the existing cached-variable runtime callbacks.
> >>
> >> I tested a fix by keeping the FF-A/MM runtime callbacks only for
> >> CONFIG_ARM_FFA_RT_MODE=y, and using the common cached-variable runtime
> >> callbacks when CONFIG_ARM_FFA_RT_MODE=n. To make that clean, I plan to
> >> add a small separate commit which moves the common runtime
> >> QueryVariableInfo() and SetVariable() helpers, plus their shared
> >> SetVariable() validation helper, from efi_variable.c into
> >> efi_var_common.c.
> >
> > I am not sure I understand the plan. efi_var_common.c already has
> > callback for the above, it calls the _int variable for each service.
> >
> > Thanks
> > /Ilias
>
> Hi Ilias,
> Thanks, I rechecked the pre-FF-A runtime TEE code and I understand the
> confusion now.
>
>
>
>
>
>
>
> Before the FF-A runtime changes, efi_variable_tee.c already had local
> runtime callbacks for QueryVariableInfo() and SetVariable(), and both
> returned EFI_UNSUPPORTED as follows:
>
>       static efi_status_t __efi_runtime EFIAPI
>       efi_query_variable_info_runtime(u32 attributes,
>                                       u64 *max_variable_storage_size,
>                                       u64 *remain_variable_storage_size,
>                                       u64 *max_variable_size)
>       {
>               return EFI_UNSUPPORTED;
>       }
>
>       static efi_status_t __efi_runtime EFIAPI
>       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;
>       }
>
> The common callbacks from efi_var_common.c covered GetVariable() and
> GetNextVariableName().
>
> The regression was introduced because this series only installed and
> renamed the TEE runtime callbacks when CONFIG_ARM_FFA_RT_MODE was
> enabled. That made the FF-A case work, but it skipped the previous
> OP-TEE/non-FF-A runtime callback setup.
>
> I am planning to restore the pre-FF-A TEE behavior when
> CONFIG_ARM_FFA_RT_MODE=n, and only switch to the new MM/FF-A callbacks
> when CONFIG_ARM_FFA_RT_MODE=y. The relevant part now looks like below
> along redefining efi_query_variable_info_runtime() and
> efi_set_variable_runtime() as before in efi_variable_tee.c returning
> EFI_UNSUPPORTED:
>
>       if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
>               efi_runtime_services.query_variable_info =
>                               efi_query_variable_info_int_runtime;

Don't name these _int. Maybe efi_query_variable_info_ffa_runtime?

>               efi_runtime_services.get_variable =
> efi_get_variable_int_runtime;
>               efi_runtime_services.get_next_variable_name =
>                               efi_get_next_variable_name_int_runtime;
>               efi_runtime_services.set_variable =
> efi_set_variable_int_runtime;
>       } else {
>               efi_runtime_services.query_variable_info =
>                               efi_query_variable_info_runtime;
>               efi_runtime_services.get_variable = efi_get_variable_runtime;
>               efi_runtime_services.get_next_variable_name =
>                               efi_get_next_variable_name_runtime;
>               efi_runtime_services.set_variable = efi_set_variable_runtime;
>       }
>       efi_update_table_header_crc32(&efi_runtime_services.hdr);
>
> With this, the OP-TEE/non-FF-A case uses the same callbacks as before
> the FF-A runtime changes. I tested it with your QEMU OP-TEE setup and it
> looks fine to me.
>
> Does this approach make sense to you?

Yes that's why I thought moving function to the 'common' backend didnt
make any sense. This looks reasonable

>
>
> >> Then, efi_variable_tee.c can select either the common
> >> cached-variable runtime handlers for OP-TEE/non-FF-A, or the new MM/FF-A
> >> runtime handlers for FF-A runtime mode.
> >>
> >> With that change, the same QEMU setup boots Linux through bootefi and a
> >> small initramfs, /sys/firmware/efi is present, and efivarfs mounts
> >> successfully.
> >>
> >> Does this direction look reasonable to you?
> >>
> >> Regards,
> >> Harsimran Singh Tungal
> >>>> Thanks
> >>>> Harsimran Singh Tungal
> >>>>>> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
> >>>>>> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
> >>>>>>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
> >>>>>>
> >>>>>>      /* Record that ExitBootServices() has been called */
> >>>>>
> >>>>
> >>>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
> >>
> >> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
>
> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A
  2026-10-09 11:15               ` Ilias Apalodimas
@ 2026-10-09 13:25                 ` Harsimran Singh Tungal
  0 siblings, 0 replies; 35+ messages in thread
From: Harsimran Singh Tungal @ 2026-10-09 13:25 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: u-boot, Abdellatif El Khlifi, Tom Rini, Heinrich Schuchardt,
	Simon Glass, Devaraj Ranganna

On 09/10/2026 12:15, Ilias Apalodimas wrote:
> On Fri, 9 Oct 2026 at 14:08, Harsimran Singh Tungal
> <harsimransingh.tungal@arm.com> wrote:
>>
>>
>>
>> On 09/10/2026 09:19, Ilias Apalodimas wrote:
>>> [...]
>>>
>>>>>>>>  /**
>>>>>>>> @@ -1129,7 +1262,7 @@ void efi_variables_boot_exit_notify(void)
>>>>>>>>      efi_runtime_services.get_variable = efi_get_variable_runtime;
>>>>>>>>      efi_runtime_services.get_next_variable_name =
>>>>>>>>                      efi_get_next_variable_name_runtime;
>>>>>>>
>>>>>>>
>>>>>>> All the get_variable*() calls used to point to the function from efi_var_common.c.
>>>>>>> By changing this you are breaking the runtime case for OP-TEE since now we will get
>>>>>>> EFI_OUT_OF_RESOURCES.
>>>>>>> There's no easy way to fix this at runtime. For OP-TEE the kernel might replace this call
>>>>>>> with an internal OP-TEE call if it's part of the firmware and announces it can provide
>>>>>>> EFI runtime services. However, the default uuse case, which we don't support SetVariable
>>>>>>> at runtime only needs to keep working.
>>>>>>>
>>>>>>> I'll post a script next week so you can replicate and test this in QEMU with OP-TEE etc.
>>>>>>>
>>>>>>> Cheers
>>>>>>> /Ilias
>>>>>>>
>>>>>> Hi Ilias,
>>>>>> Can you please share the script, so that I can replicate and test this
>>>>>> in QEMU with OP-TEE?
>>>>>
>>>>> https://github.com/apalos/efi_optee_variables
>>>>>
>>>>> make run-fip should give you a QEMU command line. You just have to add
>>>>> an OS image to test.
>>>>>
>>>>> Cheers
>>>>> /Ilias
>>>>>>
>>>>
>>>> Hi Ilias,
>>>>
>>>> Thank you for sharing the repository and instructions.
>>>> I tried the OP-TEE/non-FF-A QEMU setup from your repository and it
>>>> exposed a regression in my current series.
>>>>
>>>> With CONFIG_EFI_MM_COMM_TEE=y and CONFIG_ARM_FFA_RT_MODE=n, Linux hit
>>>> an EFI runtime paging fault when booted through U-Boot EFI. The reason
>>>> was that TEE ExitBootServices() path only installed runtime variable
>>>> callbacks inside the CONFIG_ARM_FFA_RT_MODE path. That kept the FF-A
>>>> case working, but it accidentally stopped the non-FF-A OP-TEE case from
>>>> switching to the existing cached-variable runtime callbacks.
>>>>
>>>> I tested a fix by keeping the FF-A/MM runtime callbacks only for
>>>> CONFIG_ARM_FFA_RT_MODE=y, and using the common cached-variable runtime
>>>> callbacks when CONFIG_ARM_FFA_RT_MODE=n. To make that clean, I plan to
>>>> add a small separate commit which moves the common runtime
>>>> QueryVariableInfo() and SetVariable() helpers, plus their shared
>>>> SetVariable() validation helper, from efi_variable.c into
>>>> efi_var_common.c.
>>>
>>> I am not sure I understand the plan. efi_var_common.c already has
>>> callback for the above, it calls the _int variable for each service.
>>>
>>> Thanks
>>> /Ilias
>>
>> Hi Ilias,
>> Thanks, I rechecked the pre-FF-A runtime TEE code and I understand the
>> confusion now.
>>
>>
>>
>>
>>
>>
>>
>> Before the FF-A runtime changes, efi_variable_tee.c already had local
>> runtime callbacks for QueryVariableInfo() and SetVariable(), and both
>> returned EFI_UNSUPPORTED as follows:
>>
>>       static efi_status_t __efi_runtime EFIAPI
>>       efi_query_variable_info_runtime(u32 attributes,
>>                                       u64 *max_variable_storage_size,
>>                                       u64 *remain_variable_storage_size,
>>                                       u64 *max_variable_size)
>>       {
>>               return EFI_UNSUPPORTED;
>>       }
>>
>>       static efi_status_t __efi_runtime EFIAPI
>>       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;
>>       }
>>
>> The common callbacks from efi_var_common.c covered GetVariable() and
>> GetNextVariableName().
>>
>> The regression was introduced because this series only installed and
>> renamed the TEE runtime callbacks when CONFIG_ARM_FFA_RT_MODE was
>> enabled. That made the FF-A case work, but it skipped the previous
>> OP-TEE/non-FF-A runtime callback setup.
>>
>> I am planning to restore the pre-FF-A TEE behavior when
>> CONFIG_ARM_FFA_RT_MODE=n, and only switch to the new MM/FF-A callbacks
>> when CONFIG_ARM_FFA_RT_MODE=y. The relevant part now looks like below
>> along redefining efi_query_variable_info_runtime() and
>> efi_set_variable_runtime() as before in efi_variable_tee.c returning
>> EFI_UNSUPPORTED:
>>
>>       if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
>>               efi_runtime_services.query_variable_info =
>>                               efi_query_variable_info_int_runtime;
>
> Don't name these _int. Maybe efi_query_variable_info_ffa_runtime?
>
>>               efi_runtime_services.get_variable =
>> efi_get_variable_int_runtime;
>>               efi_runtime_services.get_next_variable_name =
>>                               efi_get_next_variable_name_int_runtime;
>>               efi_runtime_services.set_variable =
>> efi_set_variable_int_runtime;
>>       } else {
>>               efi_runtime_services.query_variable_info =
>>                               efi_query_variable_info_runtime;
>>               efi_runtime_services.get_variable = efi_get_variable_runtime;
>>               efi_runtime_services.get_next_variable_name =
>>                               efi_get_next_variable_name_runtime;
>>               efi_runtime_services.set_variable = efi_set_variable_runtime;
>>       }
>>       efi_update_table_header_crc32(&efi_runtime_services.hdr);
>>
>> With this, the OP-TEE/non-FF-A case uses the same callbacks as before
>> the FF-A runtime changes. I tested it with your QEMU OP-TEE setup and it
>> looks fine to me.
>>
>> Does this approach make sense to you?
>
> Yes that's why I thought moving function to the 'common' backend didnt
> make any sense. This looks reasonable
>

Hi Ilias,

I have implemented and tested the changes discussed here.

For CONFIG_ARM_FFA_RT_MODE=n, the TEE backend now keeps the pre-FF-A
runtime callbacks. For CONFIG_ARM_FFA_RT_MODE=y, it switches to the new
FF-A runtime callbacks, now named with the _ffa_runtime suffix.

I tested the OP-TEE/non-FF-A QEMU setup from your repository and it
looks fine to me.

Do you have any further comments, or should I send v6 for review?

Regards
Harsimran Singh Tungal

>>
>>
>>>> Then, efi_variable_tee.c can select either the common
>>>> cached-variable runtime handlers for OP-TEE/non-FF-A, or the new MM/FF-A
>>>> runtime handlers for FF-A runtime mode.
>>>>
>>>> With that change, the same QEMU setup boots Linux through bootefi and a
>>>> small initramfs, /sys/firmware/efi is present, and efivarfs mounts
>>>> successfully.
>>>>
>>>> Does this direction look reasonable to you?
>>>>
>>>> Regards,
>>>> Harsimran Singh Tungal
>>>>>> Thanks
>>>>>> Harsimran Singh Tungal
>>>>>>>> -    efi_runtime_services.set_variable = efi_set_variable_runtime;
>>>>>>>> +    efi_runtime_services.set_variable = efi_set_variable_int_runtime;
>>>>>>>>      efi_update_table_header_crc32(&efi_runtime_services.hdr);
>>>>>>>>
>>>>>>>>      /* Record that ExitBootServices() has been called */
>>>>>>>
>>>>>>
>>>>>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
>>>>
>>>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
>>
>> IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2026-10-09 13:42 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-14 11:00 [PATCH v5 00/22] arm64: FF-A runtime transport for EFI variables Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 01/22] efi_loader: add runtime memset helper Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 02/22] arm-ffa: store boot-discovered runtime data separately Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 03/22] arm-ffa: add runtime-safe FF-A SMC wrapper Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 04/22] arm-ffa: add runtime direct-message support Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 05/22] arm-ffa: reuse direct-message helper at boot time Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 06/22] arm-ffa: enable runtime context at ExitBootServices Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 07/22] arm: cache: keep range maintenance available at EFI runtime Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 08/22] efi_loader: add MM SP status mapping for FF-A variables Harsimran Singh Tungal
2026-09-18 17:19   ` Ilias Apalodimas
2026-09-14 11:00 ` [PATCH v5 09/22] efi_loader: make MM transport selection runtime-safe Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 10/22] efi_loader: make FF-A MM SP notification runtime-safe Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 11/22] efi_loader: make FF-A MM communication runtime-safe Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 12/22] efi_loader: reserve FF-A shared buffer for runtime variables Harsimran Singh Tungal
2026-09-18 18:30   ` Ilias Apalodimas
2026-10-05 11:12     ` Harsimran Singh Tungal
2026-10-05 11:51       ` Ilias Apalodimas
2026-09-14 11:00 ` [PATCH v5 13/22] efi_loader: enable TEE runtime SetVariable() over FF-A Harsimran Singh Tungal
2026-09-18 18:20   ` Ilias Apalodimas
2026-10-05 13:06     ` Harsimran Singh Tungal
2026-10-05 13:15       ` Ilias Apalodimas
2026-10-08 17:32         ` Harsimran Singh Tungal
2026-10-09  8:19           ` Ilias Apalodimas
2026-10-09 11:08             ` Harsimran Singh Tungal
2026-10-09 11:15               ` Ilias Apalodimas
2026-10-09 13:25                 ` Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 14/22] efi_loader: enable TEE runtime GetVariable() " Harsimran Singh Tungal
2026-09-14 11:00 ` [PATCH v5 15/22] efi_loader: enable TEE runtime GetNextVariableName() " Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 16/22] efi_loader: enable TEE runtime QueryVariableInfo() " Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 17/22] charset: mark u16_strsize() as __efi_runtime Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 18/22] corstone1000: enable bootefi selftest Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 19/22] efi: selftest: add runtime variable tests with non-volatile storage Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 20/22] test: dm: add sandbox FF-A runtime transport tests Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 21/22] doc: arm64: document FF-A runtime path for EFI variables Harsimran Singh Tungal
2026-09-14 11:01 ` [PATCH v5 22/22] doc: bootefi: note two-phase runtime variables selftest Harsimran Singh Tungal

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.