[PATCH v2 03/11] efi_loader: add FF-A runtime support in EFI variable TEE driver
Simon Glass
sjg at chromium.org
Fri May 15 20:35:35 CEST 2026
Hi Harsimran,
On 2026-05-14T12:49:13, 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
>
> Extend lib/efi_loader/efi_variable_tee.c to support FF-A
> communication with the secure world during EFI runtime. Reuse the
> statically reserved FF-A shared buffer after ExitBootServices(),
> make the MM communication path runtime-safe so runtime variable
> operations continue to reach the secure partition.
>
> Share the MM communication and MM SP notification helpers between the
> boot and runtime paths instead of maintaining separate runtime-only
> variants. Select dynamic allocation during boot and the fixed FF-A
> shared buffer at runtime, and reject requests that would exceed the
> shared buffer size.
>
> Mark the required code and data with __efi_runtime and
> __efi_runtime_data, use range-based cache maintenance on the shared
> buffer for the runtime FF-A path, and add the shared buffer to the EFI
> runtime memory map. Document the FF-A shared MM buffer
> [...]
>
> arch/arm/cpu/armv8/cache.S | 8 +
> arch/arm/cpu/armv8/cache_v8.c | 13 +-
> lib/efi_loader/Kconfig | 4 +
> lib/efi_loader/efi_variable_tee.c | 330 +++++++++++++++++++++++++++-----------
> 4 files changed, 260 insertions(+), 95 deletions(-)
Reviewed-by: Simon Glass <sjg at chromium.org>
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -34,20 +36,44 @@
> +static const int __efi_runtime_rodata mm_sp_errmap[] = {
> + [-MM_NOT_SUPPORTED] = -EINVAL,
> + [-MM_INVALID_PARAMETER] = -EPERM,
> + [-MM_DENIED] = -EACCES,
> + [-MM_NO_MEMORY] = -EBUSY,
> +};
Hard to read. The MM_* constants are negative, so the designators
silently become positive indices and the array ends up sparse (slot 4
is implicitly zero, since MM_NO_MEMORY is -5). ffa_map_sp_event() then
uses mm_sp_errmap[idx] as a truthy check to distinguish known error
from uninitialised gap, which only works because every assigned value
happens to be non-zero. Please either pack this as a switch (matching
the original) or store {mm_code, errno} pairs; otherwise add a comment
spelling out the convention.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -304,30 +341,61 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
> + if (IS_ENABLED(CONFIG_ARM64)) {
> + BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR %
> + CONFIG_SYS_CACHELINE_SIZE);
> + BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_SIZE %
> + CONFIG_SYS_CACHELINE_SIZE);
> + flush_dcache_range((unsigned long)shared_buf,
> + (unsigned long)(shared_buf +
> + CONFIG_FFA_SHARED_MM_BUF_SIZE));
> + }
The commit message says the BUILD_BUG_ON() checks are added "in the
arm64 cache-maintenance path", but they live in ffa_mm_communicate() -
please reword.
Second, both the flush and the matching invalidate below cover the
entire CONFIG_FFA_SHARED_MM_BUF_SIZE regardless of tx_data_size. At
boot the input is only tx_data_size bytes and on the response path we
already trust message_len. Using tx_data_size (request) and
rx_data_size (response) rounded up to a cacheline would avoid flushing
megabytes on every call.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -1010,5 +1137,26 @@ efi_status_t efi_init_variables(void)
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + /*
> + * The FF-A shared buffer is accessed by EFI runtime services, so it
> + * must be marked as runtime memory in the EFI memory map.
> + *
> + * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned.
> + */
> + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
This path requires the OS to leave the region identity-mapped, right?
Worth a comment. You could add a BUILD_BUG_ON() to check that it is
EFI-page-aligned.
> diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
> @@ -434,8 +511,55 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
> +static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
> +{
> + efi_uintn_t comm_buf_size;
> + u8 *comm_buf;
> +
> + comm_buf_size = MM_COMMUNICATE_HEADER_SIZE +
> + MM_VARIABLE_COMMUNICATE_SIZE +
> + payload_size;
> +
> + /*
> + * After ExitBootServices(), dynamic allocation is no longer permitted.
> + * Use the predefined FF-A shared buffer at runtime; otherwise allocate
> + * a fresh buffer during the boot phase.
> + */
> + if (efi_at_runtime()) {
> + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
> + if (comm_buf_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
> + return NULL;
> + comm_buf = ffa_shared_buf;
> + if (!comm_buf)
> + return NULL;
> + efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
Implicit contract here that bites later: at runtime this returns the
static shared buffer, so callers must NOT free() it. The boot-time
setup_mm_hdr() callers all do free(comm_buf), and the runtime variants
in patch 4 carefully don't. Please either document the ownership
contract in the kerneldoc, or expose a paired release helper so
callers don't need to know which phase they are in.
Also, memset'ing the full CONFIG_FFA_SHARED_MM_BUF_SIZE for every
runtime request is wasteful; zeroing comm_buf_size would be enough.
Regards,
Simon
More information about the U-Boot
mailing list