mirror of
https://git.yoctoproject.org/meta-arm
synced 2026-05-30 12:30:14 +00:00
arm-bsp: corstone1000: Enable FF-A-backed EFI runtime variables and selftests
This series wires up Arm FF-A support for EFI runtime services by factoring runtime-safe helpers into the FF-A bus, layer the EFI variable TEE transport on top, and then rehome the helper exports so there’s a single implementation shared between boot and runtime paths. Corstone1000 enables the self-test command and expands the runtime variable selftest so it exercises non-volatile storage across reboots. Key Changes =========== - Add the FF-A runtime transport patch stack to the corstone1000 U-Boot recipe. - Enable EFI runtime variable handling over FF-A and include the bootefi selftests and sandbox FF-A runtime transport test. - Increase the FIP partition sizes from 2MiB to 2.5MiB and update TFA_FIP_RE_SIGN_BIN_SIZE from 0x00200000 to 0x00280000 to reflect the new allocation. The size of u-boot-EFI-2025.10-r0.bin has increased from ~707KB to ~944KB following the FF-A/EFI runtime related changes. As this binary is packaged within the FIP, the overall signed FIP size has grown accordingly. - Add a Yocto patch to increase the FIP partition size from 2MB to 2.5MB in the TF-M flash layout for Corstone-1000. Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com> Signed-off-by: Jon Mason <jon.mason@arm.com>
This commit is contained in:
committed by
Jon Mason
parent
da39013db9
commit
1843e9e2eb
@@ -23,7 +23,7 @@ part --source rawcopy --size 144k --sourceparams="file=trusted-firmware-m/bl2_si
|
||||
part --source rawcopy --size 320k --sourceparams="file=trusted-firmware-m/tfm_s_signed.bin" --align 4 --part-name="tfm_primary" --uuid 07F9616C-1233-439C-ACBA-72D75421BF70 --part-type 7FAD470E-5EC5-5C03-A2C1-4756B495DE61
|
||||
|
||||
# Rawcopy of the FIP binary
|
||||
part --source rawcopy --size 2 --sourceparams="file=signed_fip.bin" --align 4 --part-name="FIP_A" --uuid B9C7AC9D-40FF-4675-956B-EEF4DE9DF1C5 --part-type F1933675-5A8C-5B6D-9EF4-846739E89BC8
|
||||
part --source rawcopy --size 2560k --sourceparams="file=signed_fip.bin" --align 4 --part-name="FIP_A" --uuid B9C7AC9D-40FF-4675-956B-EEF4DE9DF1C5 --part-type F1933675-5A8C-5B6D-9EF4-846739E89BC8
|
||||
|
||||
# Rawcopy of kernel with initramfs
|
||||
part --source rawcopy --size 12 --sourceparams="file=Image.gz-initramfs-${MACHINE}.bin" --align 4 --part-name="kernel_primary" --uuid BF7A6142-0662-47FD-9434-6A8811980816 --part-type F771AFF9-C7E9-5F99-9EDA-2369DD694F61
|
||||
|
||||
@@ -160,7 +160,7 @@ TFA_FIP_BINARY = "fip.bin"
|
||||
TFA_BL2_RE_IMAGE_LOAD_ADDRESS = "0x62353000"
|
||||
TFA_BL2_RE_SIGN_BIN_SIZE = "0x2d000"
|
||||
TFA_FIP_RE_IMAGE_LOAD_ADDRESS = "0x68130000"
|
||||
TFA_FIP_RE_SIGN_BIN_SIZE = "0x00200000"
|
||||
TFA_FIP_RE_SIGN_BIN_SIZE = "0x00280000"
|
||||
RE_LAYOUT_WRAPPER_VERSION = "0.0.7"
|
||||
TFM_SIGN_PRIVATE_KEY = "${libdir}/tfm-scripts/root-EC-P256_1.pem"
|
||||
RE_IMAGE_OFFSET = "0x1000"
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
From 9edcdd272a7d2d872f7e04b3a9db5185fd24fd97 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Tue, 28 Apr 2026 08:57:06 +0100
|
||||
Subject: [PATCH] platform: corstone1000: Increase FIP partition size
|
||||
|
||||
Increase the FIP partition size from 2MB to 2.5MB in the
|
||||
Corstone-1000 flash layout.
|
||||
|
||||
The previous size is insufficient for current FIP images,
|
||||
which may lead to overflow during image generation or
|
||||
deployment. Expanding the partition ensures adequate
|
||||
space for firmware components packaged in the FIP.
|
||||
|
||||
Upstream-Status: Submitted [https://review.trustedfirmware.org/c/TF-M/trusted-firmware-m/+/50628]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
platform/ext/target/arm/corstone1000/partition/flash_layout.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/platform/ext/target/arm/corstone1000/partition/flash_layout.h b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
|
||||
index e2219d80a..b7282beb2 100644
|
||||
--- a/platform/ext/target/arm/corstone1000/partition/flash_layout.h
|
||||
+++ b/platform/ext/target/arm/corstone1000/partition/flash_layout.h
|
||||
@@ -139,7 +139,7 @@
|
||||
#define TFM_PARTITION_SIZE (0x50000) /* 320 KB */
|
||||
#define TFM_PARTITION_BANK_OFFSET (SE_BL2_PARTITION_SIZE)
|
||||
|
||||
-#define FIP_PARTITION_SIZE (0x200000) /* 2 MB */
|
||||
+#define FIP_PARTITION_SIZE (0x280000) /* 2.5 MB */
|
||||
#define FIP_PARTITION_BANK_OFFSET (TFM_PARTITION_BANK_OFFSET + TFM_PARTITION_SIZE)
|
||||
|
||||
#define INITRAMFS_PARTITION_SIZE (0xC00000) /* 12 MB */
|
||||
@@ -91,6 +91,7 @@ SRC_URI:append:corstone1000 = " \
|
||||
file://0057-plat-cs1k-Add-flash-erase-protection.patch \
|
||||
file://0058-plat-cs1k-Remove-unused-FWU-partitions-upon-version-.patch \
|
||||
file://0059-plat-cs1k-Duplicate-old-images-in-FWU.patch \
|
||||
file://0060-platform-corstone1000-Increase-FIP-partition-size.patch \
|
||||
"
|
||||
|
||||
SRCREV_tfm-psa-adac:corstone1000 = "f2809ae231be33a1afcd7714f40756c67d846c88"
|
||||
|
||||
@@ -86,6 +86,24 @@ SRC_URI:append = " \
|
||||
file://0040-configs-corstone1000-disable-EFI-debug-support.patch \
|
||||
"
|
||||
|
||||
# Add FF-A bus runtime support
|
||||
SRC_URI:append = " \
|
||||
file://0041-efi_loader-add-runtime-memset-helper.patch \
|
||||
file://0042-arm-ffa-add-FF-A-bus-runtime-support.patch \
|
||||
file://0043-efi_loader-add-FF-A-runtime-support-in-EFI-variable-.patch \
|
||||
file://0044-efi_loader-enable-EFI-runtime-SetVariable-GetVariabl.patch \
|
||||
file://0045-efi_loader-move-runtime-GetVariable-helpers-to-efi_v.patch \
|
||||
file://0046-corstone1000-enable-bootefi-selftest.patch \
|
||||
file://0047-efi-selftest-add-runtime-variable-tests-with-non-vol.patch \
|
||||
file://0048-test-dm-add-sandbox-FF-A-runtime-transport-tests.patch \
|
||||
file://0049-sandbox-ffa-share-synthetic-partition-metadata-via-m.patch \
|
||||
file://0050-doc-arm64-document-FF-A-runtime-path-for-EFI-variabl.patch \
|
||||
file://0051-doc-bootefi-note-two-phase-runtime-variables-selftes.patch \
|
||||
file://0052-efi_loader-align-FF-A-cache-maintenance-with-runtime.patch \
|
||||
file://0053-efi_loader-fix-AllocatePages-overlap-status.patch \
|
||||
file://0054-corstone1000-a320-enable-bootefi-selftest.patch \
|
||||
"
|
||||
|
||||
uboot_configure_config:append() {
|
||||
openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ -keyout ${B}/CRT.key -out ${S}/CRT.crt -nodes -days 365
|
||||
}
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
From 7e878429dc5f186ff945281513593c54beaf03f6 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Fri, 10 Apr 2026 17:20:59 +0100
|
||||
Subject: [PATCH 41/53] efi_loader: add runtime memset helper
|
||||
|
||||
Add efi_memset_runtime() for EFI runtime paths
|
||||
|
||||
This keeps buffer initialization in runtime-resident code after
|
||||
ExitBootServices() and avoids relying on non-runtime helpers.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
include/efi_loader.h | 3 +++
|
||||
lib/efi_loader/efi_runtime.c | 21 +++++++++++++++++++++
|
||||
2 files changed, 24 insertions(+)
|
||||
|
||||
diff --git a/include/efi_loader.h b/include/efi_loader.h
|
||||
index 0340847c0b4..ec30042665b 100644
|
||||
--- a/include/efi_loader.h
|
||||
+++ b/include/efi_loader.h
|
||||
@@ -1149,6 +1149,9 @@ struct pkcs7_message *efi_parse_pkcs7_header(const void *buf,
|
||||
/* runtime implementation of memcpy() */
|
||||
void efi_memcpy_runtime(void *dest, const void *src, size_t n);
|
||||
|
||||
+/* runtime implementation of memset */
|
||||
+__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n);
|
||||
+
|
||||
/* commonly used helper functions */
|
||||
u16 *efi_create_indexed_name(u16 *buffer, size_t buffer_size, const char *name,
|
||||
unsigned int index);
|
||||
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
|
||||
index 35eb6a77766..e91b1583b6e 100644
|
||||
--- a/lib/efi_loader/efi_runtime.c
|
||||
+++ b/lib/efi_loader/efi_runtime.c
|
||||
@@ -209,6 +209,27 @@ void __efi_runtime efi_memcpy_runtime(void *dest, const void *src, size_t n)
|
||||
*d++ = *s++;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * efi_memset_runtime() - fill a memory region with a byte value
|
||||
+ *
|
||||
+ * At runtime memset() is not available.
|
||||
+ *
|
||||
+ * @dest: pointer to the block of memory to fill.
|
||||
+ * @c: value to be set. The value is passed as an int, but the
|
||||
+ * function fills the block of memory using the u8 conversion of this value.
|
||||
+ * @n: number of bytes to be set to the value.
|
||||
+ * Return: dest is returned
|
||||
+ */
|
||||
+__efi_runtime void *efi_memset_runtime(void *dest, int c, size_t n)
|
||||
+{
|
||||
+ u8 *d = dest;
|
||||
+
|
||||
+ for (; n; --n)
|
||||
+ *d++ = c;
|
||||
+
|
||||
+ return dest;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* efi_update_table_header_crc32() - Update crc32 in table header
|
||||
*
|
||||
+975
@@ -0,0 +1,975 @@
|
||||
From 2f4000043db3a5658e946a66f1e2b8b8c48dffc7 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Thu, 20 Nov 2025 21:56:22 +0000
|
||||
Subject: [PATCH 42/53] arm-ffa: add FF-A bus runtime support
|
||||
|
||||
Enable FF-A runtime transport for EFI services
|
||||
|
||||
This patch introduces the FF-A runtime infrastructure that enables
|
||||
U-Boot to use the Arm Firmware Framework for Arm A-profile (FF-A)
|
||||
transport layer after ExitBootServices().
|
||||
The runtime transport provides persistent, runtime-safe
|
||||
implementations of key FF-A functions used by EFI runtime services.
|
||||
|
||||
Summary of key changes:
|
||||
-----------------------
|
||||
- Add drivers/firmware/arm-ffa/arm-ffa-runtime.c implementing FF-A
|
||||
runtime operations.
|
||||
- Introduce include/arm_ffa_runtime.h exporting FF-A runtime
|
||||
functions and data structures.
|
||||
- Move FF-A error mapping into runtime context.
|
||||
- Introduce invoke_ffa_fn_runtime() as runtime safe SMC wrapper.
|
||||
- Add runtime SMC wrapper for sandbox emulation.
|
||||
- Add ARM_FFA_RT_MODE Kconfig to enable runtime support.
|
||||
- Register ExitBootServices hook for runtime context.
|
||||
- Copy ffa_priv runtime fields into resident storage at
|
||||
ExitBootServices.
|
||||
- Extend Makefile to build arm-ffa-runtime.c.
|
||||
|
||||
All runtime functions and global data are tagged with __efi_runtime or
|
||||
__efi_runtime_data to ensure persistence after ExitBootServices().
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
drivers/firmware/arm-ffa/Kconfig | 11 +
|
||||
drivers/firmware/arm-ffa/Makefile | 4 +-
|
||||
drivers/firmware/arm-ffa/arm-ffa-runtime.c | 293 +++++++++++++++++++++
|
||||
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 113 ++------
|
||||
drivers/firmware/arm-ffa/arm-ffa.c | 16 +-
|
||||
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 12 +
|
||||
include/arm_ffa.h | 16 +-
|
||||
include/arm_ffa_priv.h | 24 +-
|
||||
include/arm_ffa_runtime.h | 189 +++++++++++++
|
||||
test/dm/ffa.c | 6 +-
|
||||
10 files changed, 564 insertions(+), 120 deletions(-)
|
||||
create mode 100644 drivers/firmware/arm-ffa/arm-ffa-runtime.c
|
||||
create mode 100644 include/arm_ffa_runtime.h
|
||||
|
||||
diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
|
||||
index d75f8b53fd8..1be9adeb1db 100644
|
||||
--- a/drivers/firmware/arm-ffa/Kconfig
|
||||
+++ b/drivers/firmware/arm-ffa/Kconfig
|
||||
@@ -17,6 +17,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
|
||||
@@ -40,3 +43,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..82c75da7d4b
|
||||
--- /dev/null
|
||||
+++ b/drivers/firmware/arm-ffa/arm-ffa-runtime.c
|
||||
@@ -0,0 +1,293 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
+ */
|
||||
+
|
||||
+#include <arm_ffa_runtime.h>
|
||||
+#include <arm_ffa_priv.h>
|
||||
+#include <log.h>
|
||||
+#include <asm/global_data.h>
|
||||
+#include <linux/errno.h>
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+DECLARE_GLOBAL_DATA_PTR;
|
||||
+
|
||||
+/* Error mapping declarations */
|
||||
+
|
||||
+int __ffa_runtime_data ffa_to_std_errmap[MAX_NUMBER_FFA_ERR] = {
|
||||
+ [NOT_SUPPORTED] = -EOPNOTSUPP,
|
||||
+ [INVALID_PARAMETERS] = -EINVAL,
|
||||
+ [NO_MEMORY] = -ENOMEM,
|
||||
+ [BUSY] = -EBUSY,
|
||||
+ [INTERRUPTED] = -EINTR,
|
||||
+ [DENIED] = -EACCES,
|
||||
+ [RETRY] = -EAGAIN,
|
||||
+ [ABORTED] = -ECANCELED,
|
||||
+};
|
||||
+
|
||||
+static __ffa_runtime_data struct ffa_priv_runtime ffa_priv_rt = {0};
|
||||
+
|
||||
+/* Arm FF-A driver runtime operations */
|
||||
+static const __ffa_runtime_data struct ffa_bus_ops_runtime ffa_ops_rt = {
|
||||
+ .sync_send_receive = ffa_msg_send_direct_req_hdlr_runtime,
|
||||
+};
|
||||
+
|
||||
+#define ffa_get_ops_runtime() (&ffa_ops_rt)
|
||||
+#define ffa_get_priv_runtime() (&ffa_priv_rt)
|
||||
+
|
||||
+#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
|
||||
+static void EFIAPI ffa_rt_exit_boot_services_notify(struct efi_event *event,
|
||||
+ void *context)
|
||||
+{
|
||||
+ struct ffa_priv *priv = context;
|
||||
+
|
||||
+ if (priv)
|
||||
+ ffa_copy_runtime_priv(&priv->rt);
|
||||
+ else
|
||||
+ log_err("FF-A: Entering RT mode without FF-A runtime data information\n");
|
||||
+
|
||||
+ ffa_enable_runtime_context();
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ffa_setup_efi_exit_boot_services_event() - register ExitBootServices event
|
||||
+ * @priv: pointer to the FF-A private data
|
||||
+ *
|
||||
+ * Register an EFI event that enables the FF-A runtime context when
|
||||
+ * ExitBootServices() is invoked.
|
||||
+ *
|
||||
+ * Return: 0 on success, -EPERM on failure to create the event.
|
||||
+ */
|
||||
+int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv)
|
||||
+{
|
||||
+ efi_status_t efi_ret;
|
||||
+ struct efi_event *evt = NULL;
|
||||
+
|
||||
+ efi_ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
|
||||
+ ffa_rt_exit_boot_services_notify, priv,
|
||||
+ &efi_guid_event_group_exit_boot_services,
|
||||
+ &evt);
|
||||
+ if (efi_ret != EFI_SUCCESS) {
|
||||
+ log_err("FF-A: cannot install ExitBootServices event %p, err (%lu)\n",
|
||||
+ evt, efi_ret);
|
||||
+ return -EPERM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/**
|
||||
+ * ffa_copy_runtime_priv() - copy runtime data into resident storage
|
||||
+ * @priv: pointer to the runtime private data
|
||||
+ *
|
||||
+ * Copy boot-time runtime data into the resident runtime storage to be used
|
||||
+ * after ExitBootServices().
|
||||
+ */
|
||||
+void ffa_copy_runtime_priv(const struct ffa_priv_runtime *priv)
|
||||
+{
|
||||
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
|
||||
+
|
||||
+ if (priv)
|
||||
+ *priv_rt = *priv;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ffa_enable_runtime_context() - Enable FF-A runtime context
|
||||
+ *
|
||||
+ * This function marks the FF-A runtime environment as ready for use by
|
||||
+ * EFI runtime services. It is called when ExitBootServices() is invoked,
|
||||
+ * after the FF-A bus device has successfully probed and U-Boot’s FF-A
|
||||
+ * endpoint ID has been discovered and stored in the runtime private data
|
||||
+ * structure.
|
||||
+ *
|
||||
+ * The FF-A runtime flag allows the EFI runtime layer to verify that the
|
||||
+ * FF-A transport was initialized during the boot phase and that all
|
||||
+ * runtime-safe FF-A operations may now be used after ExitBootServices().
|
||||
+ *
|
||||
+ */
|
||||
+void ffa_enable_runtime_context(void)
|
||||
+{
|
||||
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
|
||||
+
|
||||
+ priv_rt->use_ffa_runtime = true;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ffa_get_status_runtime_context() - Query FF-A runtime readiness
|
||||
+ *
|
||||
+ * This helper returns whether the FF-A runtime environment has been
|
||||
+ * enabled during the boot phase. Runtime FF-A operations must check this
|
||||
+ * flag before attempting any FF-A access, as the U-Boot driver model
|
||||
+ * (DM/uclass) is no longer available after ExitBootServices().
|
||||
+ *
|
||||
+ * The runtime context becomes enabled when ffa_enable_runtime_context()
|
||||
+ * is called, typically after the FF-A bus device has probed and the
|
||||
+ * endpoint ID has been discovered and stored in the runtime private
|
||||
+ * data structure.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ * true FF-A runtime support is ready
|
||||
+ * false FF-A runtime environment is not ready
|
||||
+ */
|
||||
+bool __ffa_runtime ffa_get_status_runtime_context(void)
|
||||
+{
|
||||
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
|
||||
+
|
||||
+ return priv_rt->use_ffa_runtime;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ffa_to_std_errno() - convert FF-A error code to standard error code
|
||||
+ * @ffa_errno: Error code returned by the FF-A ABI
|
||||
+ *
|
||||
+ * Map the given FF-A error code as specified
|
||||
+ * by the spec to a u-boot standard error code.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * The standard error code on success. . Otherwise, failure
|
||||
+ */
|
||||
+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. 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)
|
||||
+{
|
||||
+ int ffa_errno;
|
||||
+ u64 req_mode;
|
||||
+ ffa_value_t ffa_args_rt;
|
||||
+ ffa_value_t ffa_res_rt;
|
||||
+
|
||||
+ if (is_smc64) {
|
||||
+ req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
|
||||
+ } else {
|
||||
+ req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
|
||||
+ }
|
||||
+
|
||||
+ efi_memset_runtime(&ffa_args_rt, 0, sizeof(ffa_args_rt));
|
||||
+ efi_memset_runtime(&ffa_res_rt, 0, sizeof(ffa_res_rt));
|
||||
+ ffa_args_rt.a0 = req_mode;
|
||||
+ ffa_args_rt.a1 = PREP_SELF_ENDPOINT_ID(endpoint_id) |
|
||||
+ PREP_PART_ENDPOINT_ID(dst_part_id);
|
||||
+ ffa_args_rt.a2 = 0;
|
||||
+ ffa_args_rt.a3 = msg->data0;
|
||||
+ ffa_args_rt.a4 = msg->data1;
|
||||
+ ffa_args_rt.a5 = msg->data2;
|
||||
+ ffa_args_rt.a6 = msg->data3;
|
||||
+ ffa_args_rt.a7 = msg->data4;
|
||||
+
|
||||
+ invoke_ffa_fn_runtime(&ffa_args_rt, &ffa_res_rt);
|
||||
+
|
||||
+ while (ffa_res_rt.a0 == FFA_SMC_32(FFA_INTERRUPT) ||
|
||||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_INTERRUPT)) {
|
||||
+ efi_memset_runtime(&ffa_args_rt, 0, sizeof(ffa_args_rt));
|
||||
+ ffa_args_rt.a0 = (ffa_res_rt.a0 == FFA_SMC_64(FFA_INTERRUPT)) ?
|
||||
+ FFA_SMC_64(FFA_RUN) : FFA_SMC_32(FFA_RUN);
|
||||
+ ffa_args_rt.a1 = ffa_res_rt.a1;
|
||||
+
|
||||
+ invoke_ffa_fn_runtime(&ffa_args_rt, &ffa_res_rt);
|
||||
+ }
|
||||
+ if (ffa_res_rt.a0 == FFA_SMC_32(FFA_SUCCESS) ||
|
||||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_SUCCESS)) {
|
||||
+ /* Message sent with no response */
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (ffa_res_rt.a0 == FFA_SMC_32(FFA_MSG_SEND_DIRECT_RESP) ||
|
||||
+ ffa_res_rt.a0 == FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP)) {
|
||||
+ /* Message sent with response extract the return data */
|
||||
+ msg->data0 = ffa_res_rt.a3;
|
||||
+ msg->data1 = ffa_res_rt.a4;
|
||||
+ msg->data2 = ffa_res_rt.a5;
|
||||
+ msg->data3 = ffa_res_rt.a6;
|
||||
+ msg->data4 = ffa_res_rt.a7;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ ffa_errno = ffa_res_rt.a2;
|
||||
+ return ffa_to_std_errno(ffa_errno);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ffa_msg_send_direct_req_hdlr_runtime() - Runtime implementation of
|
||||
+ * FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
|
||||
+ * @dst_part_id: destination partition ID
|
||||
+ * @msg: pointer to the message data preallocated by the client (in/out)
|
||||
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
|
||||
+ *
|
||||
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
|
||||
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * 0 on success. Otherwise, failure
|
||||
+ */
|
||||
+int __ffa_runtime ffa_msg_send_direct_req_hdlr_runtime(u16 dst_part_id,
|
||||
+ struct ffa_send_direct_data *msg,
|
||||
+ bool is_smc64)
|
||||
+{
|
||||
+ struct ffa_priv_runtime *priv_rt = ffa_get_priv_runtime();
|
||||
+
|
||||
+ return ffa_invoke_msg_send_direct_req(priv_rt->id, dst_part_id, msg, is_smc64);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ffa_sync_send_receive_runtime() - Runtime implementation of
|
||||
+ * ffa_sync_send_receive()
|
||||
+ * @dst_part_id: destination partition ID
|
||||
+ * @msg: pointer to the message data preallocated by the client (in/out)
|
||||
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
|
||||
+ *
|
||||
+ * Please see ffa_msg_send_direct_req_hdlr_runtime() description for more details.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * 0 on success. Otherwise, failure
|
||||
+ */
|
||||
+int __ffa_runtime ffa_sync_send_receive_runtime(u16 dst_part_id,
|
||||
+ struct ffa_send_direct_data *msg,
|
||||
+ bool is_smc64)
|
||||
+{
|
||||
+ const struct ffa_bus_ops_runtime *ops_rt = ffa_get_ops_runtime();
|
||||
+
|
||||
+ if (!ffa_get_status_runtime_context())
|
||||
+ return -EPERM;
|
||||
+
|
||||
+ if (!ops_rt->sync_send_receive)
|
||||
+ return -ENOSYS;
|
||||
+
|
||||
+ return ops_rt->sync_send_receive(dst_part_id, msg, is_smc64);
|
||||
+}
|
||||
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
|
||||
index 597b4e994b4..f769e0e9b05 100644
|
||||
--- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c
|
||||
+++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c
|
||||
@@ -1,12 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
- * Copyright 2022-2023, 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* Authors:
|
||||
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
*/
|
||||
#include <arm_ffa.h>
|
||||
#include <arm_ffa_priv.h>
|
||||
+#include <arm_ffa_runtime.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
#include <malloc.h>
|
||||
@@ -21,19 +22,6 @@
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
-/* 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)] = {
|
||||
{
|
||||
@@ -123,27 +111,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
|
||||
@@ -233,7 +200,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;
|
||||
@@ -267,8 +234,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;
|
||||
}
|
||||
@@ -490,7 +457,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)) {
|
||||
@@ -880,16 +847,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:
|
||||
*
|
||||
@@ -898,9 +857,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);
|
||||
@@ -909,50 +865,7 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
|
||||
if (!uc_priv->partitions.count || !uc_priv->partitions.descs)
|
||||
return -ENODEV;
|
||||
|
||||
- if (is_smc64) {
|
||||
- req_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ);
|
||||
- resp_mode = FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP);
|
||||
- } else {
|
||||
- req_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_REQ);
|
||||
- resp_mode = FFA_SMC_32(FFA_MSG_SEND_DIRECT_RESP);
|
||||
- }
|
||||
-
|
||||
- invoke_ffa_fn((ffa_value_t){
|
||||
- .a0 = req_mode,
|
||||
- .a1 = PREP_SELF_ENDPOINT_ID(uc_priv->id) |
|
||||
- PREP_PART_ENDPOINT_ID(dst_part_id),
|
||||
- .a2 = 0,
|
||||
- .a3 = msg->data0,
|
||||
- .a4 = msg->data1,
|
||||
- .a5 = msg->data2,
|
||||
- .a6 = msg->data3,
|
||||
- .a7 = msg->data4,
|
||||
- }, &res);
|
||||
-
|
||||
- while (res.a0 == FFA_SMC_32(FFA_INTERRUPT))
|
||||
- invoke_ffa_fn((ffa_value_t){
|
||||
- .a0 = FFA_SMC_32(FFA_RUN),
|
||||
- .a1 = res.a1,
|
||||
- }, &res);
|
||||
-
|
||||
- if (res.a0 == FFA_SMC_32(FFA_SUCCESS)) {
|
||||
- /* Message sent with no response */
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- if (res.a0 == resp_mode) {
|
||||
- /* Message sent with response extract the return data */
|
||||
- msg->data0 = res.a3;
|
||||
- msg->data1 = res.a4;
|
||||
- msg->data2 = res.a5;
|
||||
- msg->data3 = res.a6;
|
||||
- msg->data4 = res.a7;
|
||||
-
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- ffa_errno = res.a2;
|
||||
- return ffa_to_std_errno(ffa_errno);
|
||||
+return ffa_invoke_msg_send_direct_req(uc_priv->rt.id, dst_part_id, msg, is_smc64);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1008,7 +921,7 @@ static int ffa_setup_and_transmit(struct udevice *dev, u32 func_id,
|
||||
|
||||
mem_region->tag = args->tag;
|
||||
mem_region->flags = args->flags;
|
||||
- mem_region->sender_id = uc_priv->id;
|
||||
+ mem_region->sender_id = uc_priv->rt.id;
|
||||
|
||||
/*
|
||||
* These attributes are only valid for FFA_MEM_SHARE.
|
||||
@@ -1322,6 +1235,7 @@ int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags)
|
||||
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)
|
||||
@@ -1345,6 +1259,11 @@ static int ffa_do_probe(struct udevice *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
|
||||
+ ret = ffa_setup_efi_exit_boot_services_event(uc_priv);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
return 0;
|
||||
}
|
||||
|
||||
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c
|
||||
index de36f5647d2..0d451c0ddc7 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, 2025 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 <asm/global_data.h>
|
||||
@@ -28,6 +29,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 a630392b6d1..531ecb12f3a 100644
|
||||
--- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c
|
||||
+++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
|
||||
@@ -758,6 +758,18 @@ void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
|
||||
sandbox_arm_ffa_smccc_smc(&args, res);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
|
||||
+ * @args: FF-A ABI arguments to be copied to Xn registers
|
||||
+ * @res: FF-A ABI return data to be copied from Xn registers
|
||||
+ *
|
||||
+ * Calls the emulated SMC call.
|
||||
+ */
|
||||
+void invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res)
|
||||
+{
|
||||
+ sandbox_arm_ffa_smccc_smc(args, res);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* ffa_emul_find() - Find the FF-A emulator
|
||||
* @dev: the sandbox FF-A device (sandbox-arm-ffa)
|
||||
diff --git a/include/arm_ffa.h b/include/arm_ffa.h
|
||||
index 1229e6e3d02..f19a9759e55 100644
|
||||
--- a/include/arm_ffa.h
|
||||
+++ b/include/arm_ffa.h
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
- * Copyright 2022-2023, 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ * Copyright 2022-2023, 2025-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* Authors:
|
||||
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
@@ -195,21 +195,13 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id,
|
||||
|
||||
/**
|
||||
* ffa_msg_send_direct_req_hdlr() - FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
|
||||
- * @dev: The arm_ffa bus device
|
||||
+ * @dev: The FF-A bus device
|
||||
* @dst_part_id: destination partition ID
|
||||
* @msg: pointer to the message data preallocated by the client (in/out)
|
||||
* @is_smc64: select 64-bit or 32-bit FF-A ABI
|
||||
*
|
||||
- * This function implements FFA_MSG_SEND_DIRECT_{REQ,RESP}
|
||||
- * FF-A functions.
|
||||
- *
|
||||
- * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
|
||||
- * The response from the secure partition is handled by reading the
|
||||
- * FFA_MSG_SEND_DIRECT_RESP arguments.
|
||||
- *
|
||||
- * The maximum size of the data that can be exchanged is 40 bytes which is
|
||||
- * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
|
||||
- * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
|
||||
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
|
||||
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
|
||||
*
|
||||
* Return:
|
||||
*
|
||||
diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h
|
||||
index 54196199ce3..73eba942e3b 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, 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ * Copyright 2022-2023, 2025-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* Authors:
|
||||
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
@@ -202,11 +202,26 @@ struct ffa_partitions {
|
||||
};
|
||||
|
||||
/**
|
||||
- * struct ffa_priv - the driver private data structure
|
||||
+ * struct ffa_priv_runtime - the driver's private runtime data structure
|
||||
*
|
||||
+ * @use_ffa_runtime: Whether FF-A runtime is available to use or not
|
||||
* @fwk_version: FF-A framework version
|
||||
- * @emul: FF-A sandbox emulator
|
||||
* @id: u-boot endpoint ID
|
||||
+ *
|
||||
+ * The device private runtime data structure containing all the
|
||||
+ * data read from secure world.
|
||||
+ */
|
||||
+struct ffa_priv_runtime {
|
||||
+ bool use_ffa_runtime;
|
||||
+ u32 fwk_version;
|
||||
+ u16 id;
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * struct ffa_priv - the driver private data structure
|
||||
+ *
|
||||
+ * @rt: Runtime data captured at boot time
|
||||
+ * @emul: FF-A sandbox emulator
|
||||
* @partitions: The partitions descriptors structure
|
||||
* @pair: The RX/TX buffers pair
|
||||
*
|
||||
@@ -214,9 +229,8 @@ struct ffa_partitions {
|
||||
* data read from secure world.
|
||||
*/
|
||||
struct ffa_priv {
|
||||
- u32 fwk_version;
|
||||
+ struct ffa_priv_runtime rt;
|
||||
struct udevice *emul;
|
||||
- u16 id;
|
||||
struct ffa_partitions partitions;
|
||||
struct ffa_rxtxpair pair;
|
||||
};
|
||||
diff --git a/include/arm_ffa_runtime.h b/include/arm_ffa_runtime.h
|
||||
new file mode 100644
|
||||
index 00000000000..b6ddda68f4b
|
||||
--- /dev/null
|
||||
+++ b/include/arm_ffa_runtime.h
|
||||
@@ -0,0 +1,189 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
+/*
|
||||
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
+ */
|
||||
+
|
||||
+#ifndef __ARM_FFA_RUNTIME_H
|
||||
+#define __ARM_FFA_RUNTIME_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <arm_ffa.h>
|
||||
+#include <arm_ffa_priv.h>
|
||||
+#include <efi_loader.h>
|
||||
+
|
||||
+/**
|
||||
+ * __ffa_runtime - controls whether functions are
|
||||
+ * available after calling the EFI ExitBootServices service.
|
||||
+ * Functions tagged with these keywords are resident (available at boot time and
|
||||
+ * at runtime)
|
||||
+ */
|
||||
+#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
|
||||
+#define __ffa_runtime_data __efi_runtime_data
|
||||
+#define __ffa_runtime __efi_runtime
|
||||
+#else
|
||||
+#define __ffa_runtime_data
|
||||
+#define __ffa_runtime
|
||||
+#endif
|
||||
+
|
||||
+/**
|
||||
+ * invoke_ffa_fn_runtime() - Runtime-safe SMC wrapper
|
||||
+ * @args: FF-A ABI arguments to be copied to Xn registers
|
||||
+ * @res: FF-A ABI return values copied from Xn registers
|
||||
+ *
|
||||
+ * Calls low level SMC implementation. This wrapper
|
||||
+ * is marked __ffa_runtime so it remains available after ExitBootServices().
|
||||
+ */
|
||||
+void __ffa_runtime invoke_ffa_fn_runtime(ffa_value_t *args, ffa_value_t *res);
|
||||
+
|
||||
+/**
|
||||
+ * struct ffa_bus_ops_runtime - Operations for FF-A runtime
|
||||
+ * @sync_send_receive: callback for the FFA_MSG_SEND_DIRECT_REQ
|
||||
+ *
|
||||
+ * The data structure providing all the runtime operations supported by the driver.
|
||||
+ * This structure is an EFI runtime resident.
|
||||
+ */
|
||||
+struct ffa_bus_ops_runtime {
|
||||
+ int (*sync_send_receive)(u16 dst_part_id, struct ffa_send_direct_data *msg,
|
||||
+ bool is_smc64);
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * ffa_enable_runtime_context() - Enable FF-A runtime context
|
||||
+ *
|
||||
+ * This function marks the FF-A runtime environment as ready for use by
|
||||
+ * EFI runtime services. It is called when ExitBootServices() is invoked,
|
||||
+ * after the FF-A bus device has successfully probed and U-Boot’s FF-A
|
||||
+ * endpoint ID has been discovered and stored in the runtime private data
|
||||
+ * structure.
|
||||
+ *
|
||||
+ * The FF-A runtime flag allows the EFI runtime layer to verify that the
|
||||
+ * FF-A transport was initialized during the boot phase and that all
|
||||
+ * runtime-safe FF-A operations may now be used after ExitBootServices().
|
||||
+ *
|
||||
+ */
|
||||
+void ffa_enable_runtime_context(void);
|
||||
+
|
||||
+/**
|
||||
+ * ffa_copy_runtime_priv() - copy runtime data into resident storage
|
||||
+ * @priv: pointer to the runtime private data
|
||||
+ *
|
||||
+ * Copy boot-time runtime data into the resident runtime storage to be used
|
||||
+ * after ExitBootServices().
|
||||
+ */
|
||||
+void ffa_copy_runtime_priv(const struct ffa_priv_runtime *priv);
|
||||
+
|
||||
+/**
|
||||
+ * ffa_setup_efi_exit_boot_services_event() - register ExitBootServices event
|
||||
+ * @priv: pointer to the FF-A private data
|
||||
+ *
|
||||
+ * Register an EFI event that enables the FF-A runtime context when
|
||||
+ * ExitBootServices() is invoked.
|
||||
+ *
|
||||
+ * Return: 0 on success, -EPERM on failure to create the event.
|
||||
+ */
|
||||
+#if CONFIG_IS_ENABLED(ARM_FFA_RT_MODE)
|
||||
+int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv);
|
||||
+#else
|
||||
+static inline int ffa_setup_efi_exit_boot_services_event(struct ffa_priv *priv)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/**
|
||||
+ * ffa_get_status_runtime_context() - Query FF-A runtime readiness
|
||||
+ *
|
||||
+ * This helper returns whether the FF-A runtime environment has been
|
||||
+ * enabled during the boot phase. Runtime FF-A operations must check this
|
||||
+ * flag before attempting any FF-A access, as the U-Boot driver model
|
||||
+ * (DM/uclass) is no longer available after ExitBootServices().
|
||||
+ *
|
||||
+ * The runtime context becomes enabled when ffa_enable_runtime_context()
|
||||
+ * is called, typically after the FF-A bus device has probed and the
|
||||
+ * endpoint ID has been discovered and stored in the runtime private
|
||||
+ * data structure.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ * true FF-A runtime support is ready
|
||||
+ * false FF-A runtime environment is not ready
|
||||
+ */
|
||||
+bool __ffa_runtime ffa_get_status_runtime_context(void);
|
||||
+
|
||||
+/**
|
||||
+ * ffa_to_std_errno() - convert FF-A error code to standard error code
|
||||
+ * @ffa_errno: Error code returned by the FF-A ABI
|
||||
+ *
|
||||
+ * Map the given FF-A error code as specified
|
||||
+ * by the spec to a u-boot standard error code.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * The standard error code on success. . Otherwise, failure
|
||||
+ */
|
||||
+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. Otherwise, failure
|
||||
+ */
|
||||
+int __ffa_runtime ffa_sync_send_receive_runtime(u16 dst_part_id,
|
||||
+ struct ffa_send_direct_data *msg,
|
||||
+ bool is_smc64);
|
||||
+
|
||||
+/**
|
||||
+ * ffa_invoke_msg_send_direct_req() - Invokes FFA_MSG_SEND_DIRECT_{REQ,RESP}
|
||||
+ * @endpoint_id: u-boot endpoint id
|
||||
+ * @dst_part_id: destination partition ID
|
||||
+ * @msg: pointer to the message data preallocated by the client (in/out)
|
||||
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
|
||||
+ *
|
||||
+ * This function invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
|
||||
+ *
|
||||
+ * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition.
|
||||
+ * The response from the secure partition is handled by reading the
|
||||
+ * FFA_MSG_SEND_DIRECT_RESP arguments.
|
||||
+ *
|
||||
+ * The maximum size of the data that can be exchanged is 40 bytes which is
|
||||
+ * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0
|
||||
+ * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP}
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * 0 on success. Otherwise, error on failure
|
||||
+ */
|
||||
+int __ffa_runtime ffa_invoke_msg_send_direct_req(u16 endpoint_id, u16 dst_part_id,
|
||||
+ struct ffa_send_direct_data *msg,
|
||||
+ bool is_smc64);
|
||||
+
|
||||
+/**
|
||||
+ * ffa_msg_send_direct_req_hdlr_runtime() - Runtime implementation of
|
||||
+ * FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
|
||||
+ * @dst_part_id: destination partition ID
|
||||
+ * @msg: pointer to the message data preallocated by the client (in/out)
|
||||
+ * @is_smc64: select 64-bit or 32-bit FF-A ABI
|
||||
+ *
|
||||
+ * This function calls the ffa_invoke_msg_send_direct_req() function which
|
||||
+ * invokes FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A functions.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * 0 on success. Otherwise, failure
|
||||
+ */
|
||||
+int __ffa_runtime ffa_msg_send_direct_req_hdlr_runtime(u16 dst_part_id,
|
||||
+ struct ffa_send_direct_data *msg,
|
||||
+ bool is_smc64);
|
||||
+
|
||||
+#endif
|
||||
diff --git a/test/dm/ffa.c b/test/dm/ffa.c
|
||||
index f4a6716cfd8..1240bb4141a 100644
|
||||
--- a/test/dm/ffa.c
|
||||
+++ b/test/dm/ffa.c
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* Functional tests for UCLASS_FFA class
|
||||
*
|
||||
- * Copyright 2022-2023, 2025 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>
|
||||
@@ -27,14 +27,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;
|
||||
}
|
||||
+478
@@ -0,0 +1,478 @@
|
||||
From dd992d82e9958786bd8367a8b7018648d217d552 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Thu, 20 Nov 2025 22:19:01 +0000
|
||||
Subject: [PATCH 43/53] 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.
|
||||
- Only per-buffer cache maintenance is performed at runtime,
|
||||
as whole D-cache invalidation would violate the OS coherency model
|
||||
after ExitBootServices().
|
||||
- Add runtime-phase tracking (efi_runtime_enabled).
|
||||
|
||||
The change reuses the statically reserved shared buffer, replaces
|
||||
allocations with __efi_runtime copies, and updates the runtime service
|
||||
table so EFI variable runtime calls reach the secure partition via FF-A.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
lib/efi_loader/efi_variable_tee.c | 331 ++++++++++++++++++++++++++++--
|
||||
1 file changed, 319 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
|
||||
index 6a1fa39bb6f..e4d97dc55ab 100644
|
||||
--- a/lib/efi_loader/efi_variable_tee.c
|
||||
+++ b/lib/efi_loader/efi_variable_tee.c
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
|
||||
* Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
|
||||
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* Authors:
|
||||
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
||||
#include <arm_ffa.h>
|
||||
+#include <arm_ffa_runtime.h>
|
||||
#endif
|
||||
#include <cpu_func.h>
|
||||
#include <dm.h>
|
||||
@@ -34,20 +35,47 @@
|
||||
#define MM_DENIED (-3)
|
||||
#define MM_NO_MEMORY (-5)
|
||||
|
||||
+static const int __efi_runtime_rodata mm_sp_errmap[] = {
|
||||
+ [-MM_NOT_SUPPORTED] = -EINVAL,
|
||||
+ [-MM_INVALID_PARAMETER] = -EPERM,
|
||||
+ [-MM_DENIED] = -EACCES,
|
||||
+ [-MM_NO_MEMORY] = -EBUSY,
|
||||
+};
|
||||
+
|
||||
static const char *mm_sp_svc_uuid = MM_SP_UUID;
|
||||
-static u16 mm_sp_id;
|
||||
+static u16 __efi_runtime_data mm_sp_id;
|
||||
#endif
|
||||
|
||||
+static void *__efi_runtime_data ffa_shared_buf;
|
||||
+static const efi_guid_t __efi_runtime_rodata mm_var_guid_runtime =
|
||||
+ EFI_MM_VARIABLE_GUID;
|
||||
+
|
||||
extern struct efi_var_file __efi_runtime_data *efi_var_buf;
|
||||
-static efi_uintn_t max_buffer_size; /* comm + var + func + data */
|
||||
-static efi_uintn_t max_payload_size; /* func + data */
|
||||
+static efi_uintn_t __efi_runtime_data max_buffer_size; /* comm + var + func + data */
|
||||
+static efi_uintn_t __efi_runtime_data max_payload_size; /* func + data */
|
||||
static const u16 __efi_runtime_rodata pk[] = u"PK";
|
||||
+static bool __efi_runtime_data efi_runtime_enabled;
|
||||
|
||||
struct mm_connection {
|
||||
struct udevice *tee;
|
||||
u32 session;
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * efi_is_runtime_enabled() - Indicate whether the system is in the UEFI runtime phase
|
||||
+ *
|
||||
+ * This helper returns whether the firmware has transitioned into the
|
||||
+ * UEFI runtime phase, meaning that ExitBootServices() has been invoked.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ * true - The system is operating in UEFI runtime mode.
|
||||
+ * false - The system is still in the boot services phase.
|
||||
+ */
|
||||
+static bool __efi_runtime efi_is_runtime_enabled(void)
|
||||
+{
|
||||
+ return efi_runtime_enabled;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* get_connection() - Retrieve OP-TEE session for a specific UUID.
|
||||
*
|
||||
@@ -169,6 +197,28 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
||||
+/**
|
||||
+ * ffa_map_sp_event_runtime() - Map MM SP response to errno (runtime-safe)
|
||||
+ * @sp_event_ret: MM SP return code from ffa_notify_mm_sp_runtime()
|
||||
+ *
|
||||
+ * Convert the MM SP return code into a standard U-Boot errno. This helper
|
||||
+ * is marked __efi_runtime to ensure it is safe to call after
|
||||
+ * ExitBootServices().
|
||||
+ *
|
||||
+ * Return: 0 on success, negative errno on failure
|
||||
+ */
|
||||
+static __efi_runtime int ffa_map_sp_event_runtime(int sp_event_ret)
|
||||
+{
|
||||
+ int idx = -sp_event_ret;
|
||||
+
|
||||
+ if (sp_event_ret == MM_SUCCESS)
|
||||
+ return 0;
|
||||
+ if (idx > 0 && idx < (int)ARRAY_SIZE(mm_sp_errmap) &&
|
||||
+ mm_sp_errmap[idx])
|
||||
+ return mm_sp_errmap[idx];
|
||||
+ return -EACCES;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* ffa_notify_mm_sp() - Announce there is data in the shared buffer
|
||||
*
|
||||
@@ -225,6 +275,35 @@ static int ffa_notify_mm_sp(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * ffa_notify_mm_sp_runtime() - Runtime implementation of
|
||||
+ * ffa_notify_mm_sp()
|
||||
+ *
|
||||
+ * Notify the MM partition in the trusted world that
|
||||
+ * data is available in the shared buffer.
|
||||
+ * This is a blocking call during which trusted world has exclusive access
|
||||
+ * to the MM shared buffer.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * 0 on success
|
||||
+ */
|
||||
+static int __efi_runtime ffa_notify_mm_sp_runtime(void)
|
||||
+{
|
||||
+ struct ffa_send_direct_data msg = {0};
|
||||
+ int ret;
|
||||
+ int sp_event_ret;
|
||||
+
|
||||
+ msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET;
|
||||
+
|
||||
+ ret = ffa_sync_send_receive_runtime(mm_sp_id, &msg, 1);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = ffa_map_sp_event_runtime(sp_event_ret);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* ffa_discover_mm_sp_id() - Query the MM partition ID
|
||||
*
|
||||
@@ -360,6 +439,116 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
|
||||
return efi_ret;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * ffa_mm_communicate_runtime() - Runtime implementation of ffa_mm_communicate()
|
||||
+ * @comm_buf: locally allocated communication buffer used for rx/tx
|
||||
+ * @comm_buf_size: communication buffer size
|
||||
+ *
|
||||
+ * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
|
||||
+ * that there is data to read from the shared buffer.
|
||||
+ * Communication with the MM SP is performed using FF-A transport.
|
||||
+ * On the event, MM SP can read the data from the buffer and
|
||||
+ * update the MM shared buffer with response data.
|
||||
+ * The response data is copied back to the communication buffer.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * EFI status code
|
||||
+ */
|
||||
+static efi_status_t __efi_runtime ffa_mm_communicate_runtime(void *comm_buf,
|
||||
+ ulong comm_buf_size)
|
||||
+{
|
||||
+ ulong tx_data_size;
|
||||
+ int ffa_ret;
|
||||
+ efi_status_t efi_ret;
|
||||
+ struct efi_mm_communicate_header *mm_hdr;
|
||||
+
|
||||
+ if (!comm_buf)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ /* Discover MM partition ID at boot time */
|
||||
+ if (!mm_sp_id)
|
||||
+ return EFI_UNSUPPORTED;
|
||||
+
|
||||
+ mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
|
||||
+ tx_data_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
|
||||
+
|
||||
+ if (comm_buf_size != tx_data_size || tx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ /*
|
||||
+ * Shared buffer cache maintenance for FF-A / OP-TEE communication:
|
||||
+ *
|
||||
+ * NS -> S (request path):
|
||||
+ *
|
||||
+ * The non-secure side populates the shared buffer. If the buffer is cached
|
||||
+ * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
|
||||
+ * visible in DDR. Since the secure world typically reads the shared buffer
|
||||
+ * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
|
||||
+ * must clean the corresponding cache lines to the Point of Coherency (PoC)
|
||||
+ * before entering secure world.
|
||||
+ *
|
||||
+ * S -> NS (response path):
|
||||
+ *
|
||||
+ * The secure world may update the same shared buffer in DDR. After returning
|
||||
+ * to non-secure, any cached copies of that region in NS may be stale. We
|
||||
+ * therefore invalidate the shared buffer range after the FF-A call to drop
|
||||
+ * those lines and force subsequent reads to fetch the latest data from DDR.
|
||||
+ *
|
||||
+ * Note: Whole-cache invalidation must not be used in EFI runtime context.
|
||||
+ * After ExitBootServices(), the OS owns the cache hierarchy; global invalidation
|
||||
+ * could drop OS dirty lines and violate the OS coherency model. Always operate
|
||||
+ * on the shared buffer range only.
|
||||
+ */
|
||||
+ if (IS_ENABLED(CONFIG_ARM64))
|
||||
+ flush_dcache_range((unsigned long)comm_buf,
|
||||
+ (unsigned long)((u8 *)comm_buf +
|
||||
+ CONFIG_FFA_SHARED_MM_BUF_SIZE));
|
||||
+
|
||||
+ /* Announce there is data in the shared buffer */
|
||||
+
|
||||
+ ffa_ret = ffa_notify_mm_sp_runtime();
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_ARM64))
|
||||
+ invalidate_dcache_range((unsigned long)comm_buf,
|
||||
+ (unsigned long)((u8 *)comm_buf +
|
||||
+ CONFIG_FFA_SHARED_MM_BUF_SIZE));
|
||||
+
|
||||
+ switch (ffa_ret) {
|
||||
+ case 0: {
|
||||
+ ulong rx_data_size;
|
||||
+
|
||||
+ rx_data_size = ((struct efi_mm_communicate_header *)comm_buf)->message_len +
|
||||
+ sizeof(efi_guid_t) +
|
||||
+ sizeof(size_t);
|
||||
+
|
||||
+ if (rx_data_size > comm_buf_size) {
|
||||
+ efi_ret = EFI_OUT_OF_RESOURCES;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ efi_ret = EFI_SUCCESS;
|
||||
+ break;
|
||||
+ }
|
||||
+ case -EINVAL:
|
||||
+ efi_ret = EFI_DEVICE_ERROR;
|
||||
+ break;
|
||||
+ case -EPERM:
|
||||
+ efi_ret = EFI_INVALID_PARAMETER;
|
||||
+ break;
|
||||
+ case -EACCES:
|
||||
+ efi_ret = EFI_ACCESS_DENIED;
|
||||
+ break;
|
||||
+ case -EBUSY:
|
||||
+ efi_ret = EFI_OUT_OF_RESOURCES;
|
||||
+ break;
|
||||
+ default:
|
||||
+ efi_ret = EFI_ACCESS_DENIED;
|
||||
+ }
|
||||
+
|
||||
+ return efi_ret;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* get_mm_comms() - detect the available MM transport
|
||||
*
|
||||
@@ -386,6 +575,27 @@ static enum mm_comms_select get_mm_comms(void)
|
||||
|
||||
return MM_COMMS_FFA;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * get_mm_comms_runtime() - detect the available MM transport at runtime
|
||||
+ *
|
||||
+ * Make sure the FF-A bus is available at runtime and ready
|
||||
+ * for use.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ *
|
||||
+ * MM_COMMS_FFA or MM_COMMS_UNDEFINED
|
||||
+ */
|
||||
+static enum mm_comms_select __efi_runtime get_mm_comms_runtime(void)
|
||||
+{
|
||||
+ bool ret;
|
||||
+
|
||||
+ ret = efi_is_runtime_enabled();
|
||||
+ if (!ret)
|
||||
+ return MM_COMMS_UNDEFINED;
|
||||
+
|
||||
+ return MM_COMMS_FFA;
|
||||
+}
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -433,9 +643,86 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
|
||||
return var_hdr->ret_status;
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * mm_communicate_runtime() - Runtime implementation of mm_communicate()
|
||||
+ *
|
||||
+ * @comm_buf: locally allocated communication buffer
|
||||
+ * @dsize: buffer size
|
||||
+ *
|
||||
+ * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
|
||||
+ * The comm_buf format is the same for both partitions.
|
||||
+ * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
|
||||
+ * When using the u-boot FF-A driver, any MM SP is supported.
|
||||
+ *
|
||||
+ * Return: status code
|
||||
+ */
|
||||
+static efi_status_t __efi_runtime mm_communicate_runtime(u8 *comm_buf, efi_uintn_t dsize)
|
||||
+{
|
||||
+ efi_status_t ret = EFI_UNSUPPORTED;
|
||||
+ struct efi_mm_communicate_header *mm_hdr;
|
||||
+ struct smm_variable_communicate_header *var_hdr;
|
||||
+ enum mm_comms_select mm_comms;
|
||||
+
|
||||
+ dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
|
||||
+ mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
|
||||
+ var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) {
|
||||
+ mm_comms = get_mm_comms_runtime();
|
||||
+ if (mm_comms == MM_COMMS_FFA)
|
||||
+ ret = ffa_mm_communicate_runtime(comm_buf, dsize);
|
||||
+ }
|
||||
+
|
||||
+ if (ret != EFI_SUCCESS)
|
||||
+ return ret;
|
||||
+
|
||||
+ return var_hdr->ret_status;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * get_comm_buf() - Obtain a communication buffer for MM/FF-A exchange
|
||||
+ * @payload_size: size of the payload that will be appended to the
|
||||
+ * MM communication header
|
||||
+ * This helper returns a buffer suitable for constructing an
|
||||
+ * EFI_MM_COMMUNICATE message. During the boot phase a new buffer is
|
||||
+ * dynamically allocated. After ExitBootServices(), dynamic
|
||||
+ * allocation is no longer permitted, and all runtime communication must
|
||||
+ * use the statically reserved FF-A shared buffer.
|
||||
+ *
|
||||
+ * Return:
|
||||
+ * Pointer to a valid communication buffer on success,
|
||||
+ * NULL if allocation fails during the boot phase.
|
||||
+ */
|
||||
+static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size)
|
||||
+{
|
||||
+ u8 *comm_buf;
|
||||
+
|
||||
+ /* After ExitBootServices(), dynamic allocation is no longer permitted.
|
||||
+ * Use the predefined FF-A shared buffer at runtime; otherwise allocate
|
||||
+ * a fresh buffer during the boot phase.
|
||||
+ */
|
||||
+ if (efi_is_runtime_enabled()) {
|
||||
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
|
||||
+ comm_buf = ffa_shared_buf;
|
||||
+ if (!comm_buf)
|
||||
+ return NULL;
|
||||
+ efi_memset_runtime(comm_buf, 0, CONFIG_FFA_SHARED_MM_BUF_SIZE);
|
||||
+ } else {
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ } else {
|
||||
+ comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
|
||||
+ MM_VARIABLE_COMMUNICATE_SIZE +
|
||||
+ payload_size);
|
||||
+ if (!comm_buf)
|
||||
+ return NULL;
|
||||
+ }
|
||||
+ return comm_buf;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the
|
||||
- * header data.
|
||||
+ * header data. It is runtime safe.
|
||||
*
|
||||
* @dptr: pointer address of the corresponding StandAloneMM
|
||||
* function
|
||||
@@ -444,10 +731,9 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
|
||||
* @ret: EFI return code
|
||||
* Return: buffer or NULL
|
||||
*/
|
||||
-static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
|
||||
- efi_uintn_t func, efi_status_t *ret)
|
||||
+static __efi_runtime u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
|
||||
+ efi_uintn_t func, efi_status_t *ret)
|
||||
{
|
||||
- const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID;
|
||||
struct efi_mm_communicate_header *mm_hdr;
|
||||
struct smm_variable_communicate_header *var_hdr;
|
||||
u8 *comm_buf;
|
||||
@@ -465,16 +751,15 @@ static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE +
|
||||
- MM_VARIABLE_COMMUNICATE_SIZE +
|
||||
- payload_size);
|
||||
+ comm_buf = get_comm_buf(payload_size);
|
||||
if (!comm_buf) {
|
||||
*ret = EFI_OUT_OF_RESOURCES;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
|
||||
- guidcpy(&mm_hdr->header_guid, &mm_var_guid);
|
||||
+ efi_memcpy_runtime(&mm_hdr->header_guid, &mm_var_guid_runtime,
|
||||
+ sizeof(mm_hdr->header_guid));
|
||||
mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size;
|
||||
|
||||
var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
|
||||
@@ -982,6 +1267,9 @@ void efi_variables_boot_exit_notify(void)
|
||||
efi_get_next_variable_name_runtime;
|
||||
efi_runtime_services.set_variable = efi_set_variable_runtime;
|
||||
efi_update_table_header_crc32(&efi_runtime_services.hdr);
|
||||
+
|
||||
+ /* Set efi_runtime_enabled as true after ExitBootServices */
|
||||
+ efi_runtime_enabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -993,6 +1281,25 @@ efi_status_t efi_init_variables(void)
|
||||
{
|
||||
efi_status_t ret;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) {
|
||||
+ /*
|
||||
+ * The FF-A shared buffer is accessed by EFI runtime services, so it must
|
||||
+ * be marked as runtime memory in the EFI memory map.
|
||||
+ */
|
||||
+ ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR;
|
||||
+ ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR,
|
||||
+ CONFIG_FFA_SHARED_MM_BUF_SIZE,
|
||||
+ EFI_RUNTIME_SERVICES_DATA);
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
+ log_err("EFI: failed to add FF-A shared buffer to runtime map (%lu)\n",
|
||||
+ ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ log_info("EFI: FF-A shared buffer runtime map: addr=0x%lx size=0x%lx\n",
|
||||
+ (ulong)CONFIG_FFA_SHARED_MM_BUF_ADDR,
|
||||
+ (ulong)CONFIG_FFA_SHARED_MM_BUF_SIZE);
|
||||
+ }
|
||||
+
|
||||
/* Create a cached copy of the variables that will be enabled on ExitBootServices() */
|
||||
ret = efi_var_mem_init();
|
||||
if (ret != EFI_SUCCESS)
|
||||
+418
@@ -0,0 +1,418 @@
|
||||
From 119d43911b72f8c90b09e91b727d33d21d539c49 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Thu, 11 Dec 2025 15:28:39 +0000
|
||||
Subject: [PATCH 44/53] efi_loader: enable EFI runtime
|
||||
SetVariable()/GetVariable() using FF-A transport
|
||||
|
||||
Route EFI runtime variable APIs through FF-A MM communication
|
||||
|
||||
This patch implements full EFI Runtime Variable Services (GetVariable,
|
||||
SetVariable, GetNextVariableName, and QueryVariableInfo) using the
|
||||
FF-A/MM communication backend. Once ExitBootServices() has been invoked,
|
||||
all variable operations now use the runtime-safe FF-A transport instead
|
||||
of the boot-time communication paths.
|
||||
|
||||
Key changes:
|
||||
============
|
||||
|
||||
- Add runtime-safe variable property handling via FF-A MM SP.
|
||||
- Add runtime versions of variable access and property operations.
|
||||
- Replace all standard memory operations with EFI-runtime-safe variants.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
lib/charset.c | 2 +-
|
||||
lib/efi_loader/efi_variable_tee.c | 322 +++++++++++++++++++++++++++++-
|
||||
2 files changed, 318 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/lib/charset.c b/lib/charset.c
|
||||
index 182c92a50c4..738ad1352de 100644
|
||||
--- a/lib/charset.c
|
||||
+++ b/lib/charset.c
|
||||
@@ -407,7 +407,7 @@ size_t __efi_runtime u16_strnlen(const u16 *in, size_t count)
|
||||
return i;
|
||||
}
|
||||
|
||||
-size_t u16_strsize(const void *in)
|
||||
+size_t __efi_runtime u16_strsize(const void *in)
|
||||
{
|
||||
return (u16_strlen(in) + 1) * sizeof(u16);
|
||||
}
|
||||
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
|
||||
index e4d97dc55ab..30687c21b8e 100644
|
||||
--- a/lib/efi_loader/efi_variable_tee.c
|
||||
+++ b/lib/efi_loader/efi_variable_tee.c
|
||||
@@ -859,6 +859,38 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static efi_status_t __efi_runtime set_property_int_runtime(const u16 *variable_name,
|
||||
+ efi_uintn_t name_size,
|
||||
+ const efi_guid_t *vendor,
|
||||
+ struct var_check_property *var_property)
|
||||
+{
|
||||
+ struct smm_variable_var_check_property *smm_property;
|
||||
+ efi_uintn_t payload_size;
|
||||
+ u8 *comm_buf = NULL;
|
||||
+ efi_status_t ret;
|
||||
+
|
||||
+ payload_size = sizeof(*smm_property) + name_size;
|
||||
+ if (payload_size > max_payload_size) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+ comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
|
||||
+ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET,
|
||||
+ &ret);
|
||||
+ if (!comm_buf)
|
||||
+ return ret;
|
||||
+
|
||||
+ efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(*vendor));
|
||||
+ smm_property->name_size = name_size;
|
||||
+ efi_memcpy_runtime(&smm_property->property, var_property,
|
||||
+ sizeof(smm_property->property));
|
||||
+ efi_memcpy_runtime(smm_property->name, variable_name, name_size);
|
||||
+
|
||||
+ ret = mm_communicate_runtime(comm_buf, payload_size);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static efi_status_t get_property_int(const u16 *variable_name,
|
||||
efi_uintn_t name_size,
|
||||
const efi_guid_t *vendor,
|
||||
@@ -904,6 +936,49 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static efi_status_t __efi_runtime get_property_int_runtime(const u16 *variable_name,
|
||||
+ efi_uintn_t name_size,
|
||||
+ const efi_guid_t *vendor,
|
||||
+ struct var_check_property *var_property)
|
||||
+{
|
||||
+ struct smm_variable_var_check_property *smm_property;
|
||||
+ efi_uintn_t payload_size;
|
||||
+ u8 *comm_buf = NULL;
|
||||
+ efi_status_t ret;
|
||||
+
|
||||
+ efi_memset_runtime(var_property, 0, sizeof(*var_property));
|
||||
+ payload_size = sizeof(*smm_property) + name_size;
|
||||
+ if (payload_size > max_payload_size) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+ comm_buf = setup_mm_hdr((void **)&smm_property, payload_size,
|
||||
+ SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET,
|
||||
+ &ret);
|
||||
+ if (!comm_buf)
|
||||
+ return ret;
|
||||
+
|
||||
+ efi_memcpy_runtime(&smm_property->guid, vendor, sizeof(smm_property->guid));
|
||||
+ smm_property->name_size = name_size;
|
||||
+ efi_memcpy_runtime(smm_property->name, variable_name, name_size);
|
||||
+
|
||||
+ ret = mm_communicate_runtime(comm_buf, payload_size);
|
||||
+ /*
|
||||
+ * Currently only R/O property is supported in StMM.
|
||||
+ * Variables that are not set to R/O will not set the property in StMM
|
||||
+ * and the call will return EFI_NOT_FOUND. We are setting the
|
||||
+ * properties to 0x0 so checking against that is enough for the
|
||||
+ * EFI_NOT_FOUND case.
|
||||
+ */
|
||||
+ if (ret == EFI_NOT_FOUND)
|
||||
+ ret = EFI_SUCCESS;
|
||||
+ if (ret != EFI_SUCCESS)
|
||||
+ return ret;
|
||||
+ efi_memcpy_runtime(var_property, &smm_property->property, sizeof(*var_property));
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
efi_status_t efi_get_variable_int(const u16 *variable_name,
|
||||
const efi_guid_t *vendor,
|
||||
u32 *attributes, efi_uintn_t *data_size,
|
||||
@@ -991,6 +1066,92 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+efi_status_t __efi_runtime efi_get_variable_runtime(u16 *variable_name,
|
||||
+ const efi_guid_t *vendor,
|
||||
+ u32 *attributes,
|
||||
+ efi_uintn_t *data_size,
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct var_check_property var_property;
|
||||
+ struct smm_variable_access *var_acc;
|
||||
+ efi_uintn_t payload_size;
|
||||
+ efi_uintn_t name_size;
|
||||
+ efi_uintn_t tmp_dsize;
|
||||
+ u8 *comm_buf = NULL;
|
||||
+ efi_status_t ret, tmp;
|
||||
+
|
||||
+ if (!variable_name || !vendor || !data_size) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Check payload size */
|
||||
+ name_size = u16_strsize(variable_name);
|
||||
+ if (name_size > max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Trim output buffer size */
|
||||
+ tmp_dsize = *data_size;
|
||||
+ if (name_size + tmp_dsize >
|
||||
+ max_payload_size - MM_VARIABLE_ACCESS_HEADER_SIZE) {
|
||||
+ tmp_dsize = max_payload_size -
|
||||
+ MM_VARIABLE_ACCESS_HEADER_SIZE -
|
||||
+ name_size;
|
||||
+ }
|
||||
+
|
||||
+ /* Get communication buffer and initialize header */
|
||||
+ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + tmp_dsize;
|
||||
+ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
|
||||
+ SMM_VARIABLE_FUNCTION_GET_VARIABLE, &ret);
|
||||
+ if (!comm_buf)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Fill in contents */
|
||||
+ efi_memcpy_runtime(&var_acc->guid, vendor, sizeof(var_acc->guid));
|
||||
+ var_acc->data_size = tmp_dsize;
|
||||
+ var_acc->name_size = name_size;
|
||||
+ var_acc->attr = attributes ? *attributes : 0;
|
||||
+ efi_memcpy_runtime(var_acc->name, variable_name, name_size);
|
||||
+
|
||||
+ /* Communicate */
|
||||
+ ret = mm_communicate_runtime(comm_buf, payload_size);
|
||||
+ if (ret != EFI_SUCCESS && ret != EFI_BUFFER_TOO_SMALL)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Update with reported data size for trimmed case */
|
||||
+ *data_size = var_acc->data_size;
|
||||
+
|
||||
+ /* Copy the data if ret is EFI_SUCCESS */
|
||||
+ if (ret == EFI_SUCCESS) {
|
||||
+ if (data)
|
||||
+ efi_memcpy_runtime(data, (u8 *)var_acc->name + var_acc->name_size,
|
||||
+ var_acc->data_size);
|
||||
+ else
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * UEFI > 2.7 needs the attributes set even if the buffer is
|
||||
+ * smaller
|
||||
+ */
|
||||
+ if (attributes) {
|
||||
+ tmp = get_property_int_runtime(variable_name, name_size, vendor,
|
||||
+ &var_property);
|
||||
+ if (tmp != EFI_SUCCESS) {
|
||||
+ ret = tmp;
|
||||
+ return ret;
|
||||
+ }
|
||||
+ *attributes = var_acc->attr;
|
||||
+ if (var_property.property &
|
||||
+ VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
|
||||
+ *attributes |= EFI_VARIABLE_READ_ONLY;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size,
|
||||
u16 *variable_name,
|
||||
efi_guid_t *guid)
|
||||
@@ -1055,6 +1216,68 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+efi_status_t __efi_runtime efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
|
||||
+ u16 *variable_name,
|
||||
+ efi_guid_t *guid)
|
||||
+{
|
||||
+ struct smm_variable_getnext *var_getnext;
|
||||
+ efi_uintn_t payload_size;
|
||||
+ efi_uintn_t out_name_size;
|
||||
+ efi_uintn_t in_name_size;
|
||||
+ u8 *comm_buf = NULL;
|
||||
+ efi_status_t ret;
|
||||
+
|
||||
+ if (!variable_name_size || !variable_name || !guid) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ out_name_size = *variable_name_size;
|
||||
+ in_name_size = u16_strsize(variable_name);
|
||||
+
|
||||
+ if (out_name_size < in_name_size) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ if (in_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE) {
|
||||
+ ret = EFI_INVALID_PARAMETER;
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /* Trim output buffer size */
|
||||
+ if (out_name_size > max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE)
|
||||
+ out_name_size = max_payload_size - MM_VARIABLE_GET_NEXT_HEADER_SIZE;
|
||||
+
|
||||
+ payload_size = MM_VARIABLE_GET_NEXT_HEADER_SIZE + out_name_size;
|
||||
+ comm_buf = setup_mm_hdr((void **)&var_getnext, payload_size,
|
||||
+ SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME,
|
||||
+ &ret);
|
||||
+ if (!comm_buf)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Fill in contents */
|
||||
+ efi_memcpy_runtime(&var_getnext->guid, guid, sizeof(*guid));
|
||||
+ var_getnext->name_size = out_name_size;
|
||||
+ efi_memcpy_runtime(var_getnext->name, variable_name, in_name_size);
|
||||
+ efi_memset_runtime((u8 *)var_getnext->name + in_name_size, 0x0,
|
||||
+ out_name_size - in_name_size);
|
||||
+
|
||||
+ /* Communicate */
|
||||
+ ret = mm_communicate_runtime(comm_buf, payload_size);
|
||||
+ if (ret == EFI_SUCCESS || ret == EFI_BUFFER_TOO_SMALL) {
|
||||
+ /* Update with reported data size for trimmed case */
|
||||
+ *variable_name_size = var_getnext->name_size;
|
||||
+ }
|
||||
+ if (ret != EFI_SUCCESS)
|
||||
+ return ret;
|
||||
+
|
||||
+ efi_memcpy_runtime(guid, &var_getnext->guid, sizeof(*guid));
|
||||
+ efi_memcpy_runtime(variable_name, var_getnext->name, var_getnext->name_size);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
efi_status_t efi_set_variable_int(const u16 *variable_name,
|
||||
const efi_guid_t *vendor, u32 attributes,
|
||||
efi_uintn_t data_size, const void *data,
|
||||
@@ -1197,11 +1420,11 @@ out:
|
||||
*
|
||||
* @attributes: bitmask to select variables to be
|
||||
* queried
|
||||
- * @maximum_variable_storage_size: maximum size of storage area for the
|
||||
+ * @max_variable_storage_size: maximum size of storage area for the
|
||||
* selected variable types
|
||||
- * @remaining_variable_storage_size: remaining size of storage are for the
|
||||
+ * @remain_variable_storage_size: remaining size of storage are for the
|
||||
* selected variable types
|
||||
- * @maximum_variable_size: maximum size of a variable of the
|
||||
+ * @max_variable_size: maximum size of a variable of the
|
||||
* selected type
|
||||
* Return: status code
|
||||
*/
|
||||
@@ -1210,7 +1433,33 @@ efi_query_variable_info_runtime(u32 attributes, u64 *max_variable_storage_size,
|
||||
u64 *remain_variable_storage_size,
|
||||
u64 *max_variable_size)
|
||||
{
|
||||
- return EFI_UNSUPPORTED;
|
||||
+ struct smm_variable_query_info *mm_query_info;
|
||||
+ efi_uintn_t payload_size;
|
||||
+ efi_status_t ret;
|
||||
+ u8 *comm_buf;
|
||||
+
|
||||
+ if (!max_variable_storage_size ||
|
||||
+ !remain_variable_storage_size ||
|
||||
+ !max_variable_size || !attributes)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ payload_size = sizeof(*mm_query_info);
|
||||
+ comm_buf = setup_mm_hdr((void **)&mm_query_info, payload_size,
|
||||
+ SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO,
|
||||
+ &ret);
|
||||
+ if (!comm_buf)
|
||||
+ return ret;
|
||||
+
|
||||
+ mm_query_info->attr = attributes;
|
||||
+ ret = mm_communicate_runtime(comm_buf, payload_size);
|
||||
+ if (ret != EFI_SUCCESS)
|
||||
+ return ret;
|
||||
+ *max_variable_storage_size = mm_query_info->max_variable_storage;
|
||||
+ *remain_variable_storage_size =
|
||||
+ mm_query_info->remaining_variable_storage;
|
||||
+ *max_variable_size = mm_query_info->max_variable_size;
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1228,7 +1477,70 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
|
||||
u32 attributes, efi_uintn_t data_size,
|
||||
const void *data)
|
||||
{
|
||||
- return EFI_UNSUPPORTED;
|
||||
+ efi_status_t ret, mm_communicate_ret = EFI_SUCCESS;
|
||||
+ struct var_check_property var_property;
|
||||
+ struct smm_variable_access *var_acc;
|
||||
+ efi_uintn_t payload_size;
|
||||
+ efi_uintn_t name_size;
|
||||
+ u8 *comm_buf = NULL;
|
||||
+ bool ro;
|
||||
+
|
||||
+ if (!variable_name || variable_name[0] == 0 || !guid)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ if (data_size > 0 && !data)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ /* Check payload size */
|
||||
+ name_size = u16_strsize(variable_name);
|
||||
+ payload_size = MM_VARIABLE_ACCESS_HEADER_SIZE + name_size + data_size;
|
||||
+ if (payload_size > max_payload_size)
|
||||
+ return EFI_INVALID_PARAMETER;
|
||||
+
|
||||
+ ro = !!(attributes & EFI_VARIABLE_READ_ONLY);
|
||||
+ attributes &= EFI_VARIABLE_MASK;
|
||||
+
|
||||
+ ret = get_property_int_runtime(variable_name, name_size, guid,
|
||||
+ &var_property);
|
||||
+ if (ret != EFI_SUCCESS)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Allocate the buffer early, before switching to RW (if needed)
|
||||
+ * so we won't need to account for any failures in reading/setting
|
||||
+ * the properties, if the allocation fails
|
||||
+ */
|
||||
+ comm_buf = setup_mm_hdr((void **)&var_acc, payload_size,
|
||||
+ SMM_VARIABLE_FUNCTION_SET_VARIABLE, &ret);
|
||||
+ if (!comm_buf)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)
|
||||
+ return EFI_WRITE_PROTECTED;
|
||||
+
|
||||
+ /* Fill in contents */
|
||||
+ efi_memcpy_runtime(&var_acc->guid, guid, sizeof(*guid));
|
||||
+ var_acc->data_size = data_size;
|
||||
+ var_acc->name_size = name_size;
|
||||
+ var_acc->attr = attributes;
|
||||
+ efi_memcpy_runtime(var_acc->name, variable_name, name_size);
|
||||
+ efi_memcpy_runtime((u8 *)var_acc->name + name_size, data, data_size);
|
||||
+
|
||||
+ /* Communicate */
|
||||
+ ret = mm_communicate_runtime(comm_buf, payload_size);
|
||||
+ if (ret != EFI_SUCCESS)
|
||||
+ mm_communicate_ret = ret;
|
||||
+
|
||||
+ if (ro && !(var_property.property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY)) {
|
||||
+ var_property.revision = VAR_CHECK_VARIABLE_PROPERTY_REVISION;
|
||||
+ var_property.property |= VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY;
|
||||
+ var_property.attributes = attributes;
|
||||
+ var_property.minsize = 1;
|
||||
+ var_property.maxsize = var_acc->data_size;
|
||||
+ ret = set_property_int_runtime(variable_name, name_size, guid, &var_property);
|
||||
+ }
|
||||
+
|
||||
+ return (mm_communicate_ret == EFI_SUCCESS) ? ret : mm_communicate_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
From 5c2b1f517c97f3349108bfd9fef9aac40ba236ac Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Fri, 12 Dec 2025 10:59:47 +0000
|
||||
Subject: [PATCH 45/53] efi_loader: move runtime GetVariable() helpers to
|
||||
efi_variable.c
|
||||
|
||||
Consolidate runtime GetVariable helpers to avoid duplicates
|
||||
|
||||
The functions efi_get_variable_runtime() and
|
||||
efi_get_next_variable_name_runtime() were implemented in
|
||||
efi_variable_tee.c as part of the FF-A runtime variable handling work.
|
||||
However, default implementations for these same runtime helpers also
|
||||
exist in efi_var_common.c. This results in duplicate symbol definitions.
|
||||
To resolve the conflict and centralize the runtime API, this patch moves
|
||||
the default implementations of the two runtime GetVariable() helpers
|
||||
from efi_var_common.c to efi_variable.c. This ensures that:
|
||||
|
||||
- only a single definition of each runtime helper exists,
|
||||
- backend-specific implementations can override these cleanly,
|
||||
- the EFI runtime variable service table continues to reference the
|
||||
correct functions.
|
||||
|
||||
No functional changes are introduced; this is a structural cleanup to
|
||||
avoid build-time conflicts and consolidate EFI runtime variable support
|
||||
in the appropriate file.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
lib/efi_loader/efi_var_common.c | 24 ------------------------
|
||||
lib/efi_loader/efi_variable.c | 24 ++++++++++++++++++++++++
|
||||
2 files changed, 24 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c
|
||||
index 4b34a58b4cf..0eaf89112e6 100644
|
||||
--- a/lib/efi_loader/efi_var_common.c
|
||||
+++ b/lib/efi_loader/efi_var_common.c
|
||||
@@ -172,30 +172,6 @@ efi_status_t EFIAPI efi_query_variable_info(
|
||||
return EFI_EXIT(ret);
|
||||
}
|
||||
|
||||
-efi_status_t __efi_runtime EFIAPI
|
||||
-efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
|
||||
- u32 *attributes, efi_uintn_t *data_size, void *data)
|
||||
-{
|
||||
- efi_status_t ret;
|
||||
-
|
||||
- ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
|
||||
- data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
|
||||
-
|
||||
- /* Remove EFI_VARIABLE_READ_ONLY flag */
|
||||
- if (attributes)
|
||||
- *attributes &= EFI_VARIABLE_MASK;
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-efi_status_t __efi_runtime EFIAPI
|
||||
-efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
|
||||
- u16 *variable_name, efi_guid_t *guid)
|
||||
-{
|
||||
- return efi_get_next_variable_name_mem(variable_name_size, variable_name,
|
||||
- guid, EFI_VARIABLE_RUNTIME_ACCESS);
|
||||
-}
|
||||
-
|
||||
/**
|
||||
* efi_set_secure_state - modify secure boot state variables
|
||||
* @secure_boot: value of SecureBoot
|
||||
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
|
||||
index f3533f4def3..a688c6da58d 100644
|
||||
--- a/lib/efi_loader/efi_variable.c
|
||||
+++ b/lib/efi_loader/efi_variable.c
|
||||
@@ -566,6 +566,30 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor,
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
+efi_status_t __efi_runtime EFIAPI
|
||||
+efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid,
|
||||
+ u32 *attributes, efi_uintn_t *data_size, void *data)
|
||||
+{
|
||||
+ efi_status_t ret;
|
||||
+
|
||||
+ ret = efi_get_variable_mem(variable_name, guid, attributes, data_size,
|
||||
+ data, NULL, EFI_VARIABLE_RUNTIME_ACCESS);
|
||||
+
|
||||
+ /* Remove EFI_VARIABLE_READ_ONLY flag */
|
||||
+ if (attributes)
|
||||
+ *attributes &= EFI_VARIABLE_MASK;
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+efi_status_t __efi_runtime EFIAPI
|
||||
+efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size,
|
||||
+ u16 *variable_name, efi_guid_t *guid)
|
||||
+{
|
||||
+ return efi_get_next_variable_name_mem(variable_name_size, variable_name,
|
||||
+ guid, EFI_VARIABLE_RUNTIME_ACCESS);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* efi_variables_boot_exit_notify() - notify ExitBootServices() is called
|
||||
*/
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
From 4c8504fe21f91bf462486afdfe4113f8bbc9f930 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Sun, 11 Jan 2026 20:34:13 +0000
|
||||
Subject: [PATCH 46/53] corstone1000: enable bootefi selftest
|
||||
|
||||
Enable UEFI selftest command in Corstone-1000 defconfig
|
||||
|
||||
Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
|
||||
so the board can run the built-in UEFI self-test suite during
|
||||
development and validation.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
configs/corstone1000_defconfig | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig
|
||||
index 350607892fa..8de2f9bd440 100644
|
||||
--- a/configs/corstone1000_defconfig
|
||||
+++ b/configs/corstone1000_defconfig
|
||||
@@ -41,6 +41,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_NVEDIT_EFI=y
|
||||
CONFIG_CMD_GPT=y
|
||||
@@ -79,6 +81,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_VIRTIO_MMIO=y
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
From 85edddc46913a19ce9e2dd0cb802a2dac60c9b9d Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Sun, 11 Jan 2026 20:36:45 +0000
|
||||
Subject: [PATCH 47/53] efi: selftest: add runtime variable tests with
|
||||
non-volatile storage
|
||||
|
||||
Extend runtime variable tests for persistent storage
|
||||
|
||||
Previously, EFI selftesting of runtime variables was only supported
|
||||
under CONFIG_EFI_RT_VOLATILE_STORE, which uses VarToFile to simulate
|
||||
non-volatile variable storage. This commit adds new test cases that
|
||||
exercise runtime variable operations for persistent storage.
|
||||
|
||||
Features tested:
|
||||
- Creation of runtime-accessible variables (set)
|
||||
- Retrieval of runtime variables (get)
|
||||
- Deletion using SetVariable() with size = 0
|
||||
- Append operation using EFI_VARIABLE_APPEND_WRITE
|
||||
|
||||
This improves EFI compliance validation for non-volatile runtime storage
|
||||
scenarios and ensures proper attribute enforcement and variable
|
||||
management.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
.../efi_selftest_variables_runtime.c | 108 +++++++++++++++++-
|
||||
1 file changed, 105 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c
|
||||
index 379c4f9c47b..7c14b9fefd4 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():
|
||||
@@ -40,7 +41,13 @@ static int setup(const efi_handle_t img_handle,
|
||||
/**
|
||||
* execute() - execute unit test
|
||||
*
|
||||
- * As runtime support is not implmented expect EFI_UNSUPPORTED to be returned.
|
||||
+ * For EFI variables in non-volatile storage, these tests have to be executed in two phases
|
||||
+ * 1. During first phase, run these tests and it creates EFI variable in persistent storage.
|
||||
+ * 2. Then reboot and run the test again to verify if the variable created above is still
|
||||
+ * available in non-volatile storage. If available, validate the EFI variable, append
|
||||
+ * it, and validate it again. If validation is successful, delete the same variable.
|
||||
+ *
|
||||
+ * Return: EFI_ST_SUCCESS on success, EFI_ST_FAILURE on failure
|
||||
*/
|
||||
static int execute(void)
|
||||
{
|
||||
@@ -57,6 +64,80 @@ static int execute(void)
|
||||
u64 max_storage, rem_storage, max_size;
|
||||
int test_ret;
|
||||
|
||||
+ /* Compare the value of EFI variable if it already exists in non volatile storage */
|
||||
+ if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) {
|
||||
+ len = sizeof(v) / 2;
|
||||
+ ret = runtime->get_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ &attr, &len, data);
|
||||
+ if (ret == EFI_SUCCESS) {
|
||||
+ efi_st_printf("EFI Variable efi_st_var0 found. Executing Second Phase\n");
|
||||
+ if (len != sizeof(v) / 2) {
|
||||
+ efi_st_error("GetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+ if (memcmp(data, v, len)) {
|
||||
+ efi_st_error("GetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ /* Append an existing variable */
|
||||
+ append_len = sizeof(v) - len;
|
||||
+ ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
+ EFI_VARIABLE_RUNTIME_ACCESS |
|
||||
+ EFI_VARIABLE_APPEND_WRITE |
|
||||
+ EFI_VARIABLE_NON_VOLATILE,
|
||||
+ append_len, (v + len));
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
+ efi_st_error("SetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ len = sizeof(v);
|
||||
+ ret = runtime->get_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ &attr, &len, data);
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
+ efi_st_error("GetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ if (len != sizeof(v)) {
|
||||
+ efi_st_error("GetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ if (memcmp(data, v, len)) {
|
||||
+ efi_st_error("GetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ /* Delete it by setting the size to 0 */
|
||||
+ ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
+ EFI_VARIABLE_RUNTIME_ACCESS |
|
||||
+ EFI_VARIABLE_NON_VOLATILE,
|
||||
+ 0, NULL);
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
+ efi_st_error("SetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ ret = runtime->get_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ &attr, &len, data);
|
||||
+ if (ret != EFI_NOT_FOUND) {
|
||||
+ efi_st_error("GetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ return EFI_ST_SUCCESS;
|
||||
+ } else {
|
||||
+ if (ret == EFI_NOT_FOUND) {
|
||||
+ efi_st_printf("EFI Variable efi_st_var0 not found. "
|
||||
+ "Executing First Phase\n");
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
memset(v2, 0x1, sizeof(v2));
|
||||
|
||||
if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE)) {
|
||||
@@ -70,7 +151,7 @@ static int execute(void)
|
||||
ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS,
|
||||
&max_storage, &rem_storage,
|
||||
&max_size);
|
||||
- if (ret != EFI_UNSUPPORTED) {
|
||||
+ if (ret != EFI_ST_SUCCESS) {
|
||||
efi_st_error("QueryVariableInfo failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
@@ -286,7 +367,28 @@ static int execute(void)
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
} else {
|
||||
- if (ret != EFI_UNSUPPORTED) {
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
+ efi_st_error("SetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ /* Delete it by setting the size to 0 */
|
||||
+ ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
+ EFI_VARIABLE_RUNTIME_ACCESS,
|
||||
+ 0, NULL);
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
+ efi_st_error("SetVariable failed\n");
|
||||
+ return EFI_ST_FAILURE;
|
||||
+ }
|
||||
+
|
||||
+ /* Add an 8byte aligned variable */
|
||||
+ ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0,
|
||||
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
|
||||
+ EFI_VARIABLE_RUNTIME_ACCESS |
|
||||
+ EFI_VARIABLE_NON_VOLATILE,
|
||||
+ sizeof(v) / 2, v);
|
||||
+ if (ret != EFI_SUCCESS) {
|
||||
efi_st_error("SetVariable failed\n");
|
||||
return EFI_ST_FAILURE;
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
From d12b38b7af88fdb37487d5196e214c8a4ad561fc Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Wed, 14 Jan 2026 13:55:02 +0000
|
||||
Subject: [PATCH 48/53] test: dm: add sandbox FF-A runtime transport tests
|
||||
|
||||
Exercise FF-A runtime helpers via sandbox DM tests
|
||||
|
||||
Add driver-model unit tests that exercise the FF-A runtime helpers on
|
||||
sandbox. The new tests reuse the sandbox emulator to validate both the
|
||||
positive direct-request flow and failure handling, priming the emulator
|
||||
state so the runtime path can be executed.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
arch/sandbox/include/asm/sandbox_arm_ffa.h | 16 ++++-
|
||||
test/dm/Makefile | 3 +-
|
||||
test/dm/ffa_runtime.c | 82 ++++++++++++++++++++++
|
||||
3 files changed, 99 insertions(+), 2 deletions(-)
|
||||
create mode 100644 test/dm/ffa_runtime.c
|
||||
|
||||
diff --git a/arch/sandbox/include/asm/sandbox_arm_ffa.h b/arch/sandbox/include/asm/sandbox_arm_ffa.h
|
||||
index be2790f4960..a20eb159b73 100644
|
||||
--- a/arch/sandbox/include/asm/sandbox_arm_ffa.h
|
||||
+++ b/arch/sandbox/include/asm/sandbox_arm_ffa.h
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
- * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ * Copyright 2022-2023, 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* Authors:
|
||||
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
@@ -26,6 +26,20 @@
|
||||
#define SANDBOX_SP3_ID 0x6452
|
||||
#define SANDBOX_SP4_ID 0x7814
|
||||
|
||||
+/*
|
||||
+ * The sandbox FF-A emulator uses fixed, synthetic execution-context counts and
|
||||
+ * property bitfields for each partition.
|
||||
+ */
|
||||
+#define SANDBOX_SP1_EXEC_CTXT 0x5687
|
||||
+#define SANDBOX_SP2_EXEC_CTXT 0x9587
|
||||
+#define SANDBOX_SP3_EXEC_CTXT 0x7687
|
||||
+#define SANDBOX_SP4_EXEC_CTXT 0x1487
|
||||
+
|
||||
+#define SANDBOX_SP1_PROPERTIES 0x89325621
|
||||
+#define SANDBOX_SP2_PROPERTIES 0x45325621
|
||||
+#define SANDBOX_SP3_PROPERTIES 0x23325621
|
||||
+#define SANDBOX_SP4_PROPERTIES 0x70325621
|
||||
+
|
||||
/* Invalid service UUID (no matching SP) */
|
||||
#define SANDBOX_SERVICE3_UUID "55d532ed-0942-e699-722d-c09ca798d9cd"
|
||||
|
||||
diff --git a/test/dm/Makefile b/test/dm/Makefile
|
||||
index 474e77a2151..218b0b1411f 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.
|
||||
@@ -95,6 +95,7 @@ obj-$(CONFIG_ACPI_PMC) += pmc.o
|
||||
obj-$(CONFIG_DM_PMIC) += pmic.o
|
||||
obj-$(CONFIG_DM_PWM) += pwm.o
|
||||
obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa.o
|
||||
+obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa_runtime.o
|
||||
obj-$(CONFIG_QFW) += qfw.o
|
||||
obj-$(CONFIG_RAM) += ram.o
|
||||
obj-y += regmap.o
|
||||
diff --git a/test/dm/ffa_runtime.c b/test/dm/ffa_runtime.c
|
||||
new file mode 100644
|
||||
index 00000000000..4ba859fa314
|
||||
--- /dev/null
|
||||
+++ b/test/dm/ffa_runtime.c
|
||||
@@ -0,0 +1,82 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Functional tests for FF-A runtime helpers
|
||||
+ *
|
||||
+ * Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ *
|
||||
+ * Authors:
|
||||
+ * Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
+ */
|
||||
+
|
||||
+#include <dm.h>
|
||||
+#include <dm/test.h>
|
||||
+#include <asm/sandbox_arm_ffa.h>
|
||||
+#include <asm/sandbox_arm_ffa_priv.h>
|
||||
+#include <arm_ffa_runtime.h>
|
||||
+#include <test/ut.h>
|
||||
+
|
||||
+static int ffa_runtime_get_sp_id(struct unit_test_state *uts, u16 *sp_id)
|
||||
+{
|
||||
+ struct ffa_partition_desc *descs;
|
||||
+ u32 count;
|
||||
+ struct udevice *dev;
|
||||
+ const char *svc_uuid = SANDBOX_SERVICE1_UUID;
|
||||
+
|
||||
+ ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
|
||||
+ ut_assertok(ffa_partition_info_get(dev, svc_uuid, &count, &descs));
|
||||
+ ut_assert(count > 0);
|
||||
+
|
||||
+ *sp_id = descs[0].info.id;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dm_test_ffa_runtime_ack(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct ffa_send_direct_data msg = {0};
|
||||
+ u16 sp_id;
|
||||
+ u8 cnt;
|
||||
+
|
||||
+ ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
|
||||
+
|
||||
+ ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
|
||||
+ .id = NS_PHYS_ENDPOINT_ID,
|
||||
+ });
|
||||
+ ffa_enable_runtime_context();
|
||||
+
|
||||
+ /* Ensure runtime context is available before attempting runtime-only paths */
|
||||
+ ut_assert(ffa_get_status_runtime_context());
|
||||
+
|
||||
+ /* Runtime messaging should reuse the sandbox emulator and return 0xff pattern */
|
||||
+ ut_assertok(ffa_sync_send_receive_runtime(sp_id, &msg, true));
|
||||
+ for (cnt = 0; cnt < sizeof(struct ffa_send_direct_data) / sizeof(u64); cnt++)
|
||||
+ ut_asserteq_64(-1UL, ((u64 *)&msg)[cnt]);
|
||||
+
|
||||
+ /* Validate FF-A error to errno translation helpers */
|
||||
+ ut_asserteq(-EINVAL, ffa_to_std_errno(-INVALID_PARAMETERS));
|
||||
+ ut_asserteq(-EOPNOTSUPP, ffa_to_std_errno(-NOT_SUPPORTED));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_ffa_runtime_ack, UTF_SCAN_FDT | UTF_CONSOLE);
|
||||
+
|
||||
+static int dm_test_ffa_runtime_nack(struct unit_test_state *uts)
|
||||
+{
|
||||
+ struct ffa_send_direct_data msg = {0};
|
||||
+ u16 sp_id;
|
||||
+
|
||||
+ ut_assertok(ffa_runtime_get_sp_id(uts, &sp_id));
|
||||
+
|
||||
+ ffa_copy_runtime_priv(&(struct ffa_priv_runtime){
|
||||
+ .id = NS_PHYS_ENDPOINT_ID,
|
||||
+ });
|
||||
+ ffa_enable_runtime_context();
|
||||
+
|
||||
+ /* Ensure runtime context is available before attempting runtime-only paths */
|
||||
+ ut_assert(ffa_get_status_runtime_context());
|
||||
+
|
||||
+ /* Invalid partition IDs must be rejected and mapped to -EINVAL */
|
||||
+ ut_asserteq(-EINVAL, ffa_sync_send_receive_runtime(0, &msg, true));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+DM_TEST(dm_test_ffa_runtime_nack, UTF_SCAN_FDT | UTF_CONSOLE);
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
From 6e707fe6a0120a3a6aa7954a250293162a441b21 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Thu, 15 Jan 2026 10:57:48 +0000
|
||||
Subject: [PATCH 49/53] sandbox: ffa: share synthetic partition metadata via
|
||||
macros
|
||||
|
||||
Reuse sandbox FF-A partition constants in emulator tests
|
||||
|
||||
Allow the sandbox FF-A emulator test to use execution-context and property
|
||||
constants defined in sandbox_arm_ffa.h
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 36 ++++++++++++++++------
|
||||
1 file changed, 26 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c
|
||||
index 531ecb12f3a..33d38d37ddb 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, 2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
+ * Copyright 2022-2023, 2025-2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
||||
*
|
||||
* Authors:
|
||||
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
@@ -22,41 +22,57 @@ DECLARE_GLOBAL_DATA_PTR;
|
||||
/* The partitions (SPs) table */
|
||||
static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
|
||||
{
|
||||
- .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
|
||||
+ .info = {
|
||||
+ .id = SANDBOX_SP1_ID,
|
||||
+ .exec_ctxt = SANDBOX_SP1_EXEC_CTXT,
|
||||
+ .properties = SANDBOX_SP1_PROPERTIES,
|
||||
+ },
|
||||
.sp_uuid = {
|
||||
.a1 = SANDBOX_SERVICE1_UUID_A1,
|
||||
.a2 = SANDBOX_SERVICE1_UUID_A2,
|
||||
.a3 = SANDBOX_SERVICE1_UUID_A3,
|
||||
.a4 = SANDBOX_SERVICE1_UUID_A4,
|
||||
- }
|
||||
+ },
|
||||
},
|
||||
{
|
||||
- .info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
|
||||
+ .info = {
|
||||
+ .id = SANDBOX_SP2_ID,
|
||||
+ .exec_ctxt = SANDBOX_SP2_EXEC_CTXT,
|
||||
+ .properties = SANDBOX_SP2_PROPERTIES,
|
||||
+ },
|
||||
.sp_uuid = {
|
||||
.a1 = SANDBOX_SERVICE2_UUID_A1,
|
||||
.a2 = SANDBOX_SERVICE2_UUID_A2,
|
||||
.a3 = SANDBOX_SERVICE2_UUID_A3,
|
||||
.a4 = SANDBOX_SERVICE2_UUID_A4,
|
||||
- }
|
||||
+ },
|
||||
},
|
||||
{
|
||||
- .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
|
||||
+ .info = {
|
||||
+ .id = SANDBOX_SP3_ID,
|
||||
+ .exec_ctxt = SANDBOX_SP3_EXEC_CTXT,
|
||||
+ .properties = SANDBOX_SP3_PROPERTIES,
|
||||
+ },
|
||||
.sp_uuid = {
|
||||
.a1 = SANDBOX_SERVICE1_UUID_A1,
|
||||
.a2 = SANDBOX_SERVICE1_UUID_A2,
|
||||
.a3 = SANDBOX_SERVICE1_UUID_A3,
|
||||
.a4 = SANDBOX_SERVICE1_UUID_A4,
|
||||
- }
|
||||
+ },
|
||||
},
|
||||
{
|
||||
- .info = { .id = SANDBOX_SP4_ID, .exec_ctxt = 0x1487, .properties = 0x70325621 },
|
||||
+ .info = {
|
||||
+ .id = SANDBOX_SP4_ID,
|
||||
+ .exec_ctxt = SANDBOX_SP4_EXEC_CTXT,
|
||||
+ .properties = SANDBOX_SP4_PROPERTIES,
|
||||
+ },
|
||||
.sp_uuid = {
|
||||
.a1 = SANDBOX_SERVICE2_UUID_A1,
|
||||
.a2 = SANDBOX_SERVICE2_UUID_A2,
|
||||
.a3 = SANDBOX_SERVICE2_UUID_A3,
|
||||
.a4 = SANDBOX_SERVICE2_UUID_A4,
|
||||
- }
|
||||
- }
|
||||
+ },
|
||||
+ },
|
||||
|
||||
};
|
||||
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
From a4d871a16513e86290aaa2304f0195e533200937 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Wed, 25 Feb 2026 14:40:19 +0000
|
||||
Subject: [PATCH 50/53] doc: arm64: document FF-A runtime path for EFI
|
||||
variables
|
||||
|
||||
Document how EFI runtime variables use FF-A MM communication
|
||||
|
||||
Describe the FF-A runtime layer on arm64 and how EFI variable
|
||||
runtime services use the FF-A transport and shared MM buffer.
|
||||
Also clarify armffa command scope and link to the FF-A doc.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
doc/arch/arm64.ffa.rst | 92 +++++++++++++++++++++++++++++++++++++---
|
||||
doc/usage/cmd/armffa.rst | 11 +++++
|
||||
2 files changed, 96 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
|
||||
index d2c4fb49f79..53218cd9c96 100644
|
||||
--- a/doc/arch/arm64.ffa.rst
|
||||
+++ b/doc/arch/arm64.ffa.rst
|
||||
@@ -15,10 +15,10 @@ application in S-EL0, or a Trusted OS in S-EL1.
|
||||
The U-Boot FF-A support (the bus) implements the interfaces to communicate
|
||||
with partitions in the Secure world aka Secure partitions (SPs).
|
||||
|
||||
-The FF-A support specifically focuses on communicating with SPs that
|
||||
-isolate portions of EFI runtime services that must run in a protected
|
||||
-environment which is inaccessible by the Host OS or Hypervisor.
|
||||
-Examples of such services are set/get variables.
|
||||
+U-Boot's FF-A bus support exposes an optional transport that EFI runtime
|
||||
+services can use to communicate with Secure Partitions. Through this
|
||||
+interface, EFI services (such as variable access) can request or exchange
|
||||
+data with the Secure World using FF-A.
|
||||
|
||||
The FF-A support uses the SMC ABIs defined by the FF-A specification to:
|
||||
|
||||
@@ -26,13 +26,13 @@ The FF-A support uses the SMC ABIs defined by the FF-A specification to:
|
||||
- Access an SP's service through communication protocols
|
||||
e.g. EFI MM communication protocol
|
||||
|
||||
-At this stage of development only EFI boot-time services are supported.
|
||||
-Runtime support will be added in future developments.
|
||||
-
|
||||
The U-Boot FF-A support provides the following parts:
|
||||
|
||||
- A Uclass driver providing generic FF-A methods.
|
||||
- An Arm FF-A device driver providing Arm-specific methods and reusing the Uclass methods.
|
||||
+- An optional runtime FF-A transport (toggled via CONFIG_ARM_FFA_RT_MODE) that is
|
||||
+ resident after ExitBootServices() and enables EFI runtime variable services
|
||||
+ via FF-A helpers and a shared MM communication buffer.
|
||||
- A sandbox emulator for Arm FF-A, emulates the FF-A side of the Secure World and provides
|
||||
FF-A ABIs inspection methods.
|
||||
- An FF-A sandbox device driver for FF-A communication with the emulated Secure World.
|
||||
@@ -69,6 +69,12 @@ CONFIG_ARM_FFA_TRANSPORT
|
||||
When using an Arm 64-bit platform, the Arm FF-A driver will be used.
|
||||
When using sandbox, the sandbox FF-A emulator and FF-A sandbox driver will be used.
|
||||
|
||||
+CONFIG_ARM_FFA_RT_MODE
|
||||
+ Enables the FF-A runtime transport. This option depends on
|
||||
+ CONFIG_ARM_FFA_TRANSPORT and CONFIG_EFI_LOADER, and is enabled by default.
|
||||
+ When enabled, a minimal set of FF-A operations remains available after
|
||||
+ ExitBootServices().
|
||||
+
|
||||
FF-A ABIs under the hood
|
||||
------------------------
|
||||
|
||||
@@ -158,6 +164,77 @@ they want to use (32-bit vs 64-bit). Selecting the protocol means using
|
||||
the 32-bit or 64-bit version of FFA_MSG_SEND_DIRECT_{REQ, RESP}.
|
||||
The calling convention between U-Boot and the secure world stays the same: SMC32.
|
||||
|
||||
+FF-A runtime support for EFI variables
|
||||
+--------------------------------------
|
||||
+
|
||||
+U-Boot provides an FF-A runtime transport to keep a minimal set of FF-A operations
|
||||
+available after ExitBootServices(). This runtime transport is enabled with
|
||||
+CONFIG_ARM_FFA_RT_MODE. The runtime helpers and data are marked with
|
||||
+``__efi_runtime`` / ``__efi_runtime_data`` through the
|
||||
+``__ffa_runtime`` / ``__ffa_runtime_data`` aliases in
|
||||
+``include/arm_ffa_runtime.h``.
|
||||
+
|
||||
+Runtime context is enabled at ExitBootServices(), and the following prerequisites
|
||||
+are prepared during FF-A bus probe:
|
||||
+
|
||||
+- The U-Boot FF-A endpoint ID is discovered at boot time with FFA_ID_GET and
|
||||
+ stored in the runtime private data.
|
||||
+- An ExitBootServices() event is registered by the runtime transport to enable
|
||||
+ the runtime context with ffa_enable_runtime_context() when EFI transitions
|
||||
+ to runtime.
|
||||
+
|
||||
+At runtime, the driver model is no longer available. Runtime users should
|
||||
+use the runtime interface ffa_sync_send_receive_runtime(), which internally
|
||||
+verifies the runtime context before issuing FF-A calls.
|
||||
+
|
||||
+EFI variable services over FF-A
|
||||
+-------------------------------
|
||||
+
|
||||
+When CONFIG_EFI_MM_COMM_TEE and CONFIG_ARM_FFA_TRANSPORT are enabled, U-Boot
|
||||
+routes EFI variable services to an MM Secure Partition (SP) over FF-A.
|
||||
+The MM SP is discovered at boot time using FFA_PARTITION_INFO_GET and its
|
||||
+partition ID is cached in runtime data.
|
||||
+
|
||||
+The data path uses a shared MM communication buffer and a door-bell style
|
||||
+direct message:
|
||||
+
|
||||
+- The communication buffer is located at CONFIG_FFA_SHARED_MM_BUF_ADDR and
|
||||
+ sized by CONFIG_FFA_SHARED_MM_BUF_SIZE.
|
||||
+- CONFIG_FFA_SHARED_MM_BUF_OFFSET is sent in the FF-A direct message payload
|
||||
+ to indicate where the data begins.
|
||||
+- The buffer is filled by memcpy(), the cache is flushed before notifying the
|
||||
+ MM SP, and later the buffer is reused directly with only the shared-buffer
|
||||
+ range invalidated (invalidate_dcache_range()) to avoid whole-cache
|
||||
+ invalidation.
|
||||
+
|
||||
+After ExitBootServices(), EFI SetVariable()/GetVariable() call paths use the
|
||||
+runtime MM communication helpers:
|
||||
+
|
||||
+- get_comm_buf() switches to the static shared buffer
|
||||
+- mm_communicate_runtime() selects FF-A transport when the runtime context
|
||||
+ is enabled
|
||||
+- ffa_mm_communicate_runtime() issues FFA_MSG_SEND_DIRECT_{REQ,RESP} through
|
||||
+ ffa_sync_send_receive_runtime()
|
||||
+
|
||||
+Configuration notes
|
||||
+-------------------
|
||||
+
|
||||
+Enable FF-A transport and MM communication:
|
||||
+
|
||||
+- CONFIG_ARM_FFA_TRANSPORT
|
||||
+- CONFIG_ARM_FFA_RT_MODE
|
||||
+- CONFIG_EFI_MM_COMM_TEE
|
||||
+
|
||||
+CONFIG_ARM_FFA_RT_MODE is enabled by default. It turns on MM communication for
|
||||
+EFI runtime and may be disabled when EFI services over FF-A are not required
|
||||
+after ExitBootServices().
|
||||
+
|
||||
+Configure the shared MM communication buffer:
|
||||
+
|
||||
+- CONFIG_FFA_SHARED_MM_BUF_ADDR
|
||||
+- CONFIG_FFA_SHARED_MM_BUF_SIZE
|
||||
+- CONFIG_FFA_SHARED_MM_BUF_OFFSET
|
||||
+
|
||||
Requirements for user drivers
|
||||
-----------------------------
|
||||
|
||||
@@ -260,6 +337,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 4f41e3393fd..5dcc3047a45 100644
|
||||
--- a/doc/usage/cmd/armffa.rst
|
||||
+++ b/doc/usage/cmd/armffa.rst
|
||||
@@ -39,6 +39,17 @@ The command also allows to gather secure partitions information and ping these
|
||||
|
||||
The command is also helpful in testing the communication with secure partitions.
|
||||
|
||||
+Notes
|
||||
+-----
|
||||
+
|
||||
+armffa is a boot-time test command. It relies on the FF-A driver model device
|
||||
+(UCLASS_FFA) and is not intended for EFI runtime use after
|
||||
+ExitBootServices().
|
||||
+
|
||||
+armffa does not provide EFI variable operations. For more information about
|
||||
+using EFI runtime SetVariable() and GetVariable() over FF-A please see
|
||||
+:doc:`../../arch/arm64.ffa`.
|
||||
+
|
||||
Example
|
||||
-------
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
From d595e579413e8bcf1f65be25f3da340abb5d2c2b Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Wed, 1 Apr 2026 13:37:35 +0100
|
||||
Subject: [PATCH 51/53] doc: bootefi: note two-phase runtime variables selftest
|
||||
|
||||
Explain how the runtime variable selftest runs in two phases
|
||||
|
||||
Document that the "variables at runtime" selftest runs in two
|
||||
phases when CONFIG_EFI_RT_VOLATILE_STORE is not enabled, and
|
||||
show how to select it with efi_selftest.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
doc/usage/cmd/bootefi.rst | 12 ++++++++++++
|
||||
1 file changed, 12 insertions(+)
|
||||
|
||||
diff --git a/doc/usage/cmd/bootefi.rst b/doc/usage/cmd/bootefi.rst
|
||||
index 7c5448586b7..91aebf1a4b5 100644
|
||||
--- a/doc/usage/cmd/bootefi.rst
|
||||
+++ b/doc/usage/cmd/bootefi.rst
|
||||
@@ -160,6 +160,16 @@ environment variable to match one of the listed identifiers
|
||||
Some of the tests execute the ExitBootServices() UEFI boot service and will not
|
||||
return to the command line but require a board reset.
|
||||
|
||||
+The test *variables at runtime* runs in two phases when
|
||||
+CONFIG_EFI_RT_VOLATILE_STORE is not enabled. Run it once to create a
|
||||
+runtime-accessible variable in non-volatile storage, reboot, then run it
|
||||
+again to validate, append, and delete that variable.
|
||||
+
|
||||
+::
|
||||
+
|
||||
+ => setenv efi_selftest 'variables at runtime'
|
||||
+ => bootefi selftest
|
||||
+
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
@@ -167,6 +177,8 @@ To use the *bootefi* command you must specify CONFIG_CMD_BOOTEFI=y.
|
||||
The *bootefi bootmgr* sub-command requries CMD_BOOTEFI_BOOTMGR=y.
|
||||
The *bootefi hello* sub-command requries CMD_BOOTEFI_HELLO=y.
|
||||
The *bootefi selftest* sub-command depends on CMD_BOOTEFI_SELFTEST=y.
|
||||
+The *variables at runtime* selftest runs in two phases when
|
||||
+CONFIG\_EFI\_RT\_VOLATILE\_STORE is not enabled.
|
||||
|
||||
See also
|
||||
--------
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
From 00b68d1c3dd2d182545bcacc668dbb2f637c94c1 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Fri, 10 Apr 2026 13:50:25 +0100
|
||||
Subject: [PATCH 52/53] efi_loader: align FF-A cache maintenance with runtime
|
||||
path
|
||||
|
||||
Match boot-time FF-A cache handling to runtime behavior
|
||||
|
||||
The boot-time FF-A MM communication path used invalidate_dcache_all()
|
||||
after copying the message into the shared buffer. This differs from the
|
||||
runtime path, which performs range-based maintenance to avoid global cache
|
||||
operations.
|
||||
|
||||
Update ffa_mm_communicate() to use the same pattern as the runtime helper:
|
||||
clean the shared buffer range before the SMC and invalidate the same range
|
||||
after the response. This keeps boot-time and runtime behavior consistent
|
||||
and avoids whole-cache invalidation.
|
||||
|
||||
Upstream-Status: Submitted [cover letter: https://lore.kernel.org/u-boot/20260424173151.371134-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
lib/efi_loader/efi_variable_tee.c | 33 ++++++++++++++++++++++++-------
|
||||
1 file changed, 26 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
|
||||
index 30687c21b8e..df509a435b1 100644
|
||||
--- a/lib/efi_loader/efi_variable_tee.c
|
||||
+++ b/lib/efi_loader/efi_variable_tee.c
|
||||
@@ -389,19 +389,38 @@ static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
|
||||
memcpy(virt_shared_buf, comm_buf, tx_data_size);
|
||||
|
||||
/*
|
||||
- * The secure world might have cache disabled for
|
||||
- * the device region used for shared buffer (which is the case for Optee).
|
||||
- * In this case, the secure world reads the data from DRAM.
|
||||
- * Let's flush the cache so the DRAM is updated with the latest data.
|
||||
+ * Shared buffer cache maintenance for FF-A / OP-TEE communication:
|
||||
+ *
|
||||
+ * NS -> S (request path):
|
||||
+ *
|
||||
+ * The non-secure side populates the shared buffer. If the buffer is cached
|
||||
+ * in NS, the updated bytes may reside in dirty D-cache lines and not yet be
|
||||
+ * visible in DDR. Since the secure world typically reads the shared buffer
|
||||
+ * directly from DDR (e.g. with caches disabled / non-coherent mapping), we
|
||||
+ * must clean the corresponding cache lines to the Point of Coherency (PoC)
|
||||
+ * before entering secure world.
|
||||
+ *
|
||||
+ * S -> NS (response path):
|
||||
+ *
|
||||
+ * The secure world may update the same shared buffer in DDR. After returning
|
||||
+ * to non-secure, any cached copies of that region in NS may be stale. We
|
||||
+ * therefore invalidate the shared buffer range after the FF-A call to drop
|
||||
+ * those lines and force subsequent reads to fetch the latest data from DDR.
|
||||
*/
|
||||
-#ifdef CONFIG_ARM64
|
||||
- invalidate_dcache_all();
|
||||
-#endif
|
||||
+ if (IS_ENABLED(CONFIG_ARM64))
|
||||
+ flush_dcache_range((unsigned long)virt_shared_buf,
|
||||
+ (unsigned long)virt_shared_buf +
|
||||
+ CONFIG_FFA_SHARED_MM_BUF_SIZE);
|
||||
|
||||
/* Announce there is data in the shared buffer */
|
||||
|
||||
ffa_ret = ffa_notify_mm_sp();
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_ARM64))
|
||||
+ invalidate_dcache_range((unsigned long)virt_shared_buf,
|
||||
+ (unsigned long)virt_shared_buf +
|
||||
+ CONFIG_FFA_SHARED_MM_BUF_SIZE);
|
||||
+
|
||||
switch (ffa_ret) {
|
||||
case 0: {
|
||||
ulong rx_data_size;
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
From 1be3bcbc0c7efc36b8fbac7ef0f8c8375dc6770d Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Sat, 18 Apr 2026 14:26:28 +0100
|
||||
Subject: [PATCH 53/53] efi_loader: fix AllocatePages overlap status
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Return EFI_NOT_FOUND for EFI_ALLOCATE_ADDRESS overlap
|
||||
|
||||
When efi_allocate_pages() is called with EFI_ALLOCATE_ADDRESS, UEFI
|
||||
expects EFI_NOT_FOUND if the requested address range is already
|
||||
allocated or unavailable. U-Boot currently returns
|
||||
EFI_OUT_OF_RESOURCES when efi_update_memory_map() detects an overlap
|
||||
after a successful lmb_alloc_mem(), which does not match
|
||||
EFI_ALLOCATE_ADDRESS semantics.
|
||||
|
||||
Return EFI_NOT_FOUND for EFI_ALLOCATE_ADDRESS requests that fail due
|
||||
to an overlapping EFI memory descriptor, while keeping
|
||||
EFI_OUT_OF_RESOURCES for other allocation types.
|
||||
|
||||
The UEFI specification [1] specifies that
|
||||
EFI_BOOT_SERVICES.AllocatePages must return EFI_NOT_FOUND when the
|
||||
requested address range is unavailable or already allocated;
|
||||
EFI_OUT_OF_RESOURCES applies to non‑address‑specific allocation
|
||||
failures.
|
||||
|
||||
[1] https://uefi.org/specs/UEFI/2.10_A/07_Services_Boot_Services.html
|
||||
|
||||
Upstream-Status: Submitted [https://lore.kernel.org/u-boot/20260427150530.3156000-1-harsimransingh.tungal@arm.com/]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
lib/efi_loader/efi_memory.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
|
||||
index b77c2f980cc..63cf1a7277f 100644
|
||||
--- a/lib/efi_loader/efi_memory.c
|
||||
+++ b/lib/efi_loader/efi_memory.c
|
||||
@@ -510,7 +510,9 @@ efi_status_t efi_allocate_pages(enum efi_allocate_type type,
|
||||
/* Map would overlap, bail out */
|
||||
lmb_free(addr, (u64)pages << EFI_PAGE_SHIFT, flags);
|
||||
unmap_sysmem((void *)(uintptr_t)efi_addr);
|
||||
- return EFI_OUT_OF_RESOURCES;
|
||||
+ if (type == EFI_ALLOCATE_ADDRESS)
|
||||
+ return EFI_NOT_FOUND;
|
||||
+ return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*memory = efi_addr;
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
From 0da9650a3ed86e63c6a9621d7a9195eb3a75a233 Mon Sep 17 00:00:00 2001
|
||||
From: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
Date: Fri, 17 Apr 2026 13:41:07 +0100
|
||||
Subject: [PATCH] corstone1000-a320: enable bootefi selftest
|
||||
|
||||
Turn on CONFIG_CMD_BOOTEFI_SELFTEST in the Corstone-1000 defconfig
|
||||
so the board can run the built-in UEFI self-test suite during
|
||||
development and validation.
|
||||
|
||||
Upstream-Status: Pending [Will be submitted upstream with the
|
||||
pending Cortex-A320 related U-Boot changes]
|
||||
Signed-off-by: Harsimran Singh Tungal <harsimransingh.tungal@arm.com>
|
||||
---
|
||||
configs/corstone1000-a320_defconfig | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/configs/corstone1000-a320_defconfig b/configs/corstone1000-a320_defconfig
|
||||
index d0ae1e745db..c4dcd1790cc 100644
|
||||
--- a/configs/corstone1000-a320_defconfig
|
||||
+++ b/configs/corstone1000-a320_defconfig
|
||||
@@ -41,6 +41,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_NVEDIT_EFI=y
|
||||
CONFIG_CMD_GPT=y
|
||||
@@ -76,6 +78,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_VIRTIO_MMIO=y
|
||||
Reference in New Issue
Block a user