[PATCH 03/12] efi_loader: add FF-A runtime support in EFI variable TEE driver
Simon Glass
sjg at chromium.org
Tue Apr 28 20:12:58 CEST 2026
Hi Harsimran,
On 2026-04-24T17:31:50, Harsimran Singh Tungal
<harsimransingh.tungal at arm.com> wrote:
> efi_loader: add FF-A runtime support in EFI variable TEE driver
>
> Enable MM variable services over FF-A after ExitBootServices
>
> This patch extends lib/efi_loader/efi_variable_tee.c to support FF-A
> communication with the secure world during EFI runtime. It enables EFI
> runtime variable access and MM communication using FF-A transport when
> ExitBootServices() has already been called.
>
> Key changes:
> ------------
> - Introduce runtime-safe implementations for MM communication,
> notification, and variable access using FF-A driver.
> - Introduce communication-buffer helper (get_comm_buf()) that switches
> between dynamic allocation (boot phase) and the fixed FF-A shared
> buffer (runtime phase).
> - Mark persistent data and code with __efi_runtime and
> __efi_runtime_data attributes.
> - Use direct physical address mapping for shared buffers since
> U-Boot operates with 1:1 physical-to-virtual mapping.
> [...]
>
> lib/efi_loader/efi_variable_tee.c | 331 ++++++++++++++++++++++++++++++++++++--
> 1 file changed, 319 insertions(+), 12 deletions(-)
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
> +static int __efi_runtime ffa_notify_mm_sp_runtime(void)
> +{
> + struct ffa_send_direct_data msg = {0};
> + int ret;
> + int sp_event_ret;
> +
> + msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
> +
> + ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
> + if (ret)
> + return ret;
> +
> + ret = ffa_map_sp_event_runtime(sp_event_ret);
> + return ret;
> +}
It looks like ''sp_event_ret' is uninitialised. The boot-time twin
sets sp_event_ret = msg.data0 after the FF-A call before mapping it;
that line is missing here, so the runtime path branches on whatever
was on the stack and returns -EACCES (or worse, success) regardless of
the SP reply. Please add the assignment, and ideally a selftest
exercising an SP error return so this would have been caught.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> + ulong comm_buf_size)
> +{
...
> + if (!comm_buf)
> + return EFI_INVALID_PARAMETER;
> +
> + /* Discover MM partition ID at boot time */
> + if (!mm_sp_id)
> + return EFI_UNSUPPORTED;
The comment is copied verbatim from ffa_mm_communicate() but at
runtime we cannot discover anything - we can only check that boot-time
discovery happened. Please rewrite as e.g. 'MM partition ID must have
been discovered at boot time'.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> +static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
> + ulong comm_buf_size)
> +{
...
> + switch (ffa_ret) {
> + case 0: {
...
> + case -EINVAL:
> + efi_ret = EFI_DEVICE_ERROR;
> + break;
Almost the entire body is a copy of ffa_mm_communicate(), including
the long cache-maintenance comment block which patch 12 then
duplicates again into the boot helper. Please factor the shared logic
into one helper that takes a 'runtime' bool (or function pointers for
the FF-A and notify hooks) so we don't carry three near-identical
copies. The current arrangement makes future fixes (like the missing
sp_event_ret assignment above) easy to apply to only one twin.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -386,6 +575,27 @@ static enum mm_comms_select get_mm_comms(void)
> +static enum mm_comms_select __efi_runtime get_mm_comms_runtime(void)
> +{
> + bool ret;
> +
> + ret = efi_is_runtime_enabled();
> + if (!ret)
> + return MM_COMMS_UNDEFINED;
> +
> + return MM_COMMS_FFA;
> +}
But get_mm_comms_runtime() is only reached via the runtime services
table, which is only wired up after efi_variables_boot_exit_notify()
sets efi_runtime_enabled=true, so it always returns MM_COMMS_FFA,
right? Either drop the wrapper and call ffa_mm_communicate_runtime()
directly from mm_communicate_runtime(), or keep an explicit runtime
sanity check, but please don't dress it up as transport selection.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> +static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
> +{
> + u8 *comm_buf;
> +
> + /* After ExitBootServices(), dynamic allocation is no longer permitted.
> + * Use the predefined FF-A shared buffer at runtime; otherwise allocate
> + * a fresh buffer during the boot phase.
> + */
> + if (efi_is_runtime_enabled()) {
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + comm_buf = ffa_shared_buf;
> + if (!comm_buf)
> + return NULL;
> + efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
> + } else {
> + return NULL;
> + }
> + } else {
At runtime there is no validation that 'payload_size + headers' fits
inside CONFIG_FFA_SHARED_MM_BUF_SIZE - the max_buffer_size check in
setup_mm_hdr() compares against the SP-reported limit, which is not
necessarily the same as the static shared buffer size, so an oversized
payload can silently overflow the FF-A buffer when setup_mm_hdr()
writes the header and the caller fills the data. Please add an
explicit size check here, or assert that max_buffer_size <=
CONFIG_FFA_SHARED_MM_BUF_SIZE at init time.
Also: the multi-line comment uses kernel-doc style ('/*' on its own
then '*' lines) elsewhere in this file, but here the first text line
follows '/*' immediately.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -444,10 +731,9 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> /**
> * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
> - * header data.
> + * header data. It is runtime safe.
The function no longer 'allocates' at runtime. It hands back a slot in
the static shared buffer - so the summary is misleading. Please
rewrite the description and drop the trailing 'It is runtime safe'
(already implied by the new __efi_runtime tag).
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -34,20 +35,47 @@
> +static const efi_guid_t __efi_runtime_rodata mm_var_guid_runtime =
> + EFI_MM_VARIABLE_GUID;
Why a separate '_runtime' copy of this GUID? The original mm_var_guid
was a function-local in setup_mm_hdr(), so you can just promote it to
file scope with __efi_runtime_rodata and use it for both phases.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + /*
> + * The FF-A shared buffer is accessed by EFI runtime services, so it must
> + * be marked as runtime memory in the EFI memory map.
> + */
> + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
> + ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
> + CONFIG_FFA_SHARED_MM_BUF_SIZE,
> + EFI_RUNTIME_SERVICES_DATA);
efi_add_memory_map() takes a size in bytes but the underlying
implementation expects a page-count argument in some call sites. Can
you please double-check that CONFIG_FFA_SHARED_MM_BUF_SIZE is
interpreted as bytes here and that the buffer base is page-aligned,
otherwise the OS will see a misdescribed runtime region. Worth a
comment stating the alignment assumption.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -34,20 +35,47 @@
> +static bool __efi_runtime_data efi_runtime_enabled;
We already have a global indicator that boot services have exited:
systab.boottime being set to NULL in efi_exit_boot_services()
Adding a second flag here (and a wrapper efi_is_runtime_enabled() over
it) means we need to keep them in sync. I'd prefer either hooking off
systab.boottime (already __efi_runtime_data) or exposing a single
global helper from efi_runtime.c that everyone uses.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -4,7 +4,7 @@
> * Copyright (C) 2019 Linaro Ltd. <sughosh.ganu at linaro.org>
> * Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas at linaro.org>
> - * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office at arm.com>
> + * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office at arm.com>
How about 2022-2026 ?
The commit message also opens with 'This patch extends ...'; please
use the imperative ('Extend lib/efi_loader/efi_variable_tee.c to ...')
and drop 'This patch'. Same for 'Key changes:' / 'The change reuses
...' - describe what the code does in present tense.
Regards,
Simon
More information about the U-Boot
mailing list