[PATCH v8 06/10] arm_ffa: introduce the FF-A Sandbox driver

Abdellatif El Khlifi
2022-11-22T13:20:31Z

Provide a Sandbox driver to emulate the FF-A ABIs

The emulated ABIs are those supported by the FF-A core driver
and according to FF-A specification v1.0.

The Sandbox driver provides operations allowing the test
application to read the status of all the inspected ABIs
and perform functional tests based on that.

sandbox driver supports only 64-bit direct messaging.

Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Cc: Tom Rini <trini@konsulko.com>
Cc: Simon Glass <sjg@chromium.org>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Jens Wiklander <jens.wiklander@linaro.org>

---

Changelog:
===============

v8: update ffa_bus_prvdata_get() to return a pointer rather than
a pointer address

v7: state that sandbox driver supports only 64-bit direct messaging

v4: align sandbox driver with the new FF-A driver interfaces
and new way of error handling

v1: introduce the sandbox driver

MAINTAINERS | 1 +
configs/sandbox64_defconfig | 2 +
configs/sandbox_defconfig | 2 +
doc/arch/sandbox/sandbox.rst | 1 +
drivers/firmware/arm-ffa/Kconfig | 9 +-
drivers/firmware/arm-ffa/Makefile | 1 +
drivers/firmware/arm-ffa/arm_ffa_prv.h | 15 +-
drivers/firmware/arm-ffa/core.c | 22 +-
drivers/firmware/arm-ffa/sandbox.c | 659 ++++++++++++++++++
.../firmware/arm-ffa/sandbox_arm_ffa_prv.h | 144 ++++
include/arm_ffa.h | 2 +-
include/sandbox_arm_ffa.h | 91 +++
lib/efi_loader/efi_boottime.c | 2 +-
13 files changed, 938 insertions(+), 13 deletions(-)
create mode 100644 drivers/firmware/arm-ffa/sandbox.c
create mode 100644 drivers/firmware/arm-ffa/sandbox_arm_ffa_prv.h
create mode 100644 include/sandbox_arm_ffa.h

diff --git a/MAINTAINERS b/MAINTAINERS
index aa4e87d9f8..9197344df4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -270,6 +270,7 @@ F: cmd/armffa.c
F: doc/arch/arm64.ffa.rst
F: drivers/firmware/arm-ffa/
F: include/arm_ffa.h
+F: include/sandbox_arm_ffa.h

ARM FREESCALE IMX
M: Stefano Babic <sbabic@denx.de>
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index cff166b1c1..141ffd1f85 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -258,3 +258,5 @@ CONFIG_FWU_MULTI_BANK_UPDATE=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
CONFIG_UT_DM=y
+CONFIG_ARM_FFA_TRANSPORT=y
+CONFIG_SANDBOX_FFA=y
\ No newline at end of file
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 07fe0c3a7a..a146a6bf1b 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -333,3 +333,5 @@ CONFIG_TEST_FDTDEC=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
CONFIG_UT_DM=y
+CONFIG_ARM_FFA_TRANSPORT=y
+CONFIG_SANDBOX_FFA=y
\ No newline at end of file
diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst
index 34c4e06d9b..a42409a7b4 100644
--- a/doc/arch/sandbox/sandbox.rst
+++ b/doc/arch/sandbox/sandbox.rst
@@ -203,6 +203,7 @@ Supported Drivers

U-Boot sandbox supports these emulations:

+- Arm FF-A
- Block devices
- Chrome OS EC
- GPIO
diff --git a/drivers/firmware/arm-ffa/Kconfig b/drivers/firmware/arm-ffa/Kconfig
index be4df89d23..b86f16d778 100644
--- a/drivers/firmware/arm-ffa/Kconfig
+++ b/drivers/firmware/arm-ffa/Kconfig
@@ -2,8 +2,8 @@

config ARM_FFA_TRANSPORT
bool "Enable Arm Firmware Framework for Armv8-A driver"
- depends on DM && ARM64
- select ARM_SMCCC
+ depends on DM && (ARM64 || SANDBOX)
+ select ARM_SMCCC if !SANDBOX
select CMD_ARMFFA
select LIB_UUID
select DEVRES
@@ -29,3 +29,8 @@ config ARM_FFA_TRANSPORT

For more details about the FF-A driver, please refer to doc/arch/arm64.ffa.rst

+config SANDBOX_FFA
+ bool "FF-A Sandbox driver"
+ depends on ARM_FFA_TRANSPORT && SANDBOX
+ help
+ This emulates the FF-A handling under Sandbox and allows to test the FF-A driver
diff --git a/drivers/firmware/arm-ffa/Makefile b/drivers/firmware/arm-ffa/Makefile
index 043a8915be..0d21d6b47a 100644
--- a/drivers/firmware/arm-ffa/Makefile
+++ b/drivers/firmware/arm-ffa/Makefile
@@ -4,3 +4,4 @@
# Abdellatif El Khlifi, Arm Limited, abdellatif.elkhlifi@arm.com.

obj-y += arm-ffa-uclass.o core.o
+obj-$(CONFIG_SANDBOX_FFA) += sandbox.o
diff --git a/drivers/firmware/arm-ffa/arm_ffa_prv.h b/drivers/firmware/arm-ffa/arm_ffa_prv.h
index 4eea7dc036..bbc8b87069 100644
--- a/drivers/firmware/arm-ffa/arm_ffa_prv.h
+++ b/drivers/firmware/arm-ffa/arm_ffa_prv.h
@@ -19,6 +19,16 @@
/* FF-A core driver name */
#define FFA_DRV_NAME "arm_ffa"

+/* The FF-A SMC function definitions */
+
+#if CONFIG_IS_ENABLED(SANDBOX_FFA)
+#include "sandbox_arm_ffa.h"
+#else
+typedef struct arm_smccc_1_2_regs ffa_value_t;
+#endif
+
+typedef void (*invoke_ffa_fn_t)(ffa_value_t args, ffa_value_t *res);
+
/* FF-A driver version definitions */

#define MAJOR_VERSION_MASK GENMASK(30, 16)
@@ -103,11 +113,6 @@ struct ffa_abi_errmap {
#define FFA_ERRMAP_COUNT (FFA_LAST_ID - FFA_FIRST_ID + 1)
#define FFA_ID_TO_ERRMAP_ID(ffa_id) ((ffa_id) - FFA_FIRST_ID)

-/* The FF-A SMC function definitions */
-
-typedef struct arm_smccc_1_2_regs ffa_value_t;
-typedef void (*invoke_ffa_fn_t)(ffa_value_t args, ffa_value_t *res);
-
/*
* struct ffa_partition_uuid - 16 bytes UUID transmitted by FFA_PARTITION_INFO_GET
* @a1-4: 32-bit words access to the UUID data
diff --git a/drivers/firmware/arm-ffa/core.c b/drivers/firmware/arm-ffa/core.c
index 0b1f8e6a07..560603b28b 100644
--- a/drivers/firmware/arm-ffa/core.c
+++ b/drivers/firmware/arm-ffa/core.c
@@ -1072,6 +1072,7 @@ static int ffa_msg_send_direct_req(struct udevice *dev, u16 dst_part_id,
return ffa_to_std_errno(ffa_errno);
}

+#if !CONFIG_IS_ENABLED(SANDBOX_FFA)
/**
* __arm_ffa_fn_smc - SMC wrapper
* @args: FF-A ABI arguments to be copied to Xn registers
@@ -1085,6 +1086,7 @@ void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res)
{
arm_smccc_1_2_smc(&args, res);
}
+#endif

/**
* ffa_set_smc_conduit - Set the SMC conduit
@@ -1098,7 +1100,12 @@ void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res)
*/
static int ffa_set_smc_conduit(void)
{
- ffa_priv_data->invoke_ffa_fn = __arm_ffa_fn_smc;
+#if CONFIG_IS_ENABLED(SANDBOX_FFA)
+ ffa_priv_data->invoke_ffa_fn = sandbox_arm_ffa_smccc_smc;
+ ffa_info("Using SMC emulation");
+#else
+ ffa_priv_data->invoke_ffa_fn = __arm_ffa_fn_smc;
+#endif

if (!ffa_priv_data->invoke_ffa_fn) {
ffa_err("failure to set the invoke function");
@@ -1275,17 +1282,18 @@ struct ffa_prvdata *ffa_bus_prvdata_get(void)
}

/**
- * ffa_bus_discover - discover FF-A bus and probe arm_ffa device
+ * ffa_bus_discover - discover FF-A bus and probe arm_ffa and sandbox_arm_ffa devices
* @pdev: the address of a device pointer (to be filled when the arm_ffa bus device is created
* successfully)
*
* This function makes sure the FF-A bus is discoverable.
- * When probing succeeds FF-A discovery is done. The arm_ffa device is ready to use.
+ * When probing succeeds FF-A discovery is done. The arm_ffa and sandbox_arm_ffa devices
+ * are ready to use.
*
* When the bus was already discovered successfully the discovery will not run again.
*
* Arm FF-A transport is implemented through arm_ffa u-boot device managing the FF-A
- * communication.
+ * communication. In Sandbox mode sandbox_arm_ffa is used to test arm_ffa driver.
* All FF-A clients should use the arm_ffa device to use the FF-A transport.
*
* Return:
@@ -1299,6 +1307,12 @@ int ffa_bus_discover(struct udevice **pdev)
if (!ffa_priv_data) {
ret = ffa_device_get(pdev);

+#if CONFIG_IS_ENABLED(SANDBOX_FFA)
+ if (ret == 0)
+ ret = sandbox_ffa_device_get();
+#endif
+ }
+
return ret;
}

diff --git a/drivers/firmware/arm-ffa/sandbox.c b/drivers/firmware/arm-ffa/sandbox.c
new file mode 100644
index 0000000000..16f1ca926e
--- /dev/null
+++ b/drivers/firmware/arm-ffa/sandbox.c
@@ -0,0 +1,659 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2022 ARM Limited
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#include "sandbox_arm_ffa_prv.h"
+#include <asm/global_data.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/root.h>
+#include <linux/errno.h>
+#include <linux/sizes.h>
+#include <mapmem.h>
+#include <string.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * The device private data structure containing all the emulated secure world data
+ */
+static struct sandbox_ffa_prvdata sandbox_ffa_priv_data = {0};
+
+/* The partitions (SPs) table */
+static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
+ {
+ .info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
+ .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_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
+ .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_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
+ .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 },
+ .sp_uuid = {
+ .a1 = SANDBOX_SERVICE2_UUID_A1,
+ .a2 = SANDBOX_SERVICE2_UUID_A2,
+ .a3 = SANDBOX_SERVICE2_UUID_A3,
+ .a4 = SANDBOX_SERVICE2_UUID_A4,
+ }
+ }
+
+};
+
+/*
+ * Driver functions
+ */
+
+/**
+ * sandbox_ffa_get_device - probes the sandbox_arm_ffa device
+ *
+ * This function makes sure the sandbox_arm_ffa device is probed
+ * This function makes sure the sandbox_arm_ffa device is
+ * created, bound to this driver, probed and ready to use.
+ *
+ * sandbox_arm_ffa depends on arm_ffa device. This dependency is
+ * handled by ffa_bus_discover function. arm_ffa is probed first then
+ * sandbox_arm_ffa.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int sandbox_ffa_device_get(void)
+{
+ int ret;
+
+ if (sandbox_ffa_priv_data.dev)
+ return 0;
+
+ ret = device_bind(dm_root(),
+ DM_DRIVER_GET(sandbox_arm_ffa),
+ FFA_SANDBOX_DRV_NAME,
+ NULL,
+ ofnode_null(),
+ &sandbox_ffa_priv_data.dev);
+ if (ret) {
+ sandbox_ffa_priv_data.dev = NULL;
+ return ret;
+ }
+
+ ret = device_probe(sandbox_ffa_priv_data.dev);
+ if (ret) {
+ ffa_err("[Sandbox] can not probe the device");
+ device_unbind(sandbox_ffa_priv_data.dev);
+ sandbox_ffa_priv_data.dev = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_version - Emulated FFA_VERSION handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_VERSION FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_version)
+{
+ sandbox_ffa_priv_data.fwk_version = FFA_VERSION_1_0;
+ res->a0 = sandbox_ffa_priv_data.fwk_version;
+
+ /* x1-x7 MBZ */
+ memset(FFA_X1X7_MBZ_REG_START, 0, FFA_X1X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_id_get - Emulated FFA_ID_GET handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_ID_GET FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_id_get)
+{
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ res->a1 = 0;
+
+ sandbox_ffa_priv_data.id = NS_PHYS_ENDPOINT_ID;
+ res->a2 = sandbox_ffa_priv_data.id;
+
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_features - Emulated FFA_FEATURES handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_FEATURES FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_features)
+{
+ if (pargs->a1 == FFA_SMC_64(FFA_RXTX_MAP)) {
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ res->a2 = RXTX_BUFFERS_MIN_SIZE;
+ res->a3 = 0;
+ /* x4-x7 MBZ */
+ memset(FFA_X4X7_MBZ_REG_START,
+ 0, FFA_X4X7_MBZ_CNT * sizeof(unsigned long));
+ } else {
+ res->a0 = FFA_SMC_32(FFA_ERROR);
+ res->a2 = FFA_ERR_STAT_NOT_SUPPORTED;
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START,
+ 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+ ffa_err("[Sandbox] FF-A interface 0x%lx not implemented", pargs->a1);
+ }
+
+ res->a1 = 0;
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_partition_info_get - Emulated FFA_PARTITION_INFO_GET handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_PARTITION_INFO_GET FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_partition_info_get)
+{
+ struct ffa_partition_info *rxbuf_desc_info = NULL;
+ u32 descs_cnt;
+ u32 descs_size_bytes;
+
+ res->a0 = FFA_SMC_32(FFA_ERROR);
+
+ if (!sandbox_ffa_priv_data.pair.rxbuf) {
+ res->a2 = FFA_ERR_STAT_DENIED;
+ goto cleanup;
+ }
+
+ if (sandbox_ffa_priv_data.pair_info.rxbuf_owned) {
+ res->a2 = FFA_ERR_STAT_BUSY;
+ goto cleanup;
+ }
+
+ if (!sandbox_ffa_priv_data.partitions.descs) {
+ sandbox_ffa_priv_data.partitions.descs = sandbox_partitions;
+ sandbox_ffa_priv_data.partitions.count = SANDBOX_PARTITIONS_CNT;
+ }
+
+ descs_size_bytes = SANDBOX_PARTITIONS_CNT * sizeof(struct ffa_partition_desc);
+
+ /* Abort if the RX buffer size is smaller than the descriptors buffer size */
+ if ((sandbox_ffa_priv_data.pair_info.rxtx_buf_size * SZ_4K) < descs_size_bytes) {
+ res->a2 = FFA_ERR_STAT_NO_MEMORY;
+ goto cleanup;
+ }
+
+ rxbuf_desc_info = (struct ffa_partition_info *)sandbox_ffa_priv_data.pair.rxbuf;
+
+ /* No UUID specified. Return the information of all partitions */
+ if (!pargs->a1 && !pargs->a2 && !pargs->a3 && !pargs->a4) {
+ for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++)
+ *(rxbuf_desc_info++) =
+ sandbox_ffa_priv_data.partitions.descs[descs_cnt].info;
+
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ res->a2 = SANDBOX_PARTITIONS_CNT;
+ /* transfer ownership to the consumer: the non secure world */
+ sandbox_ffa_priv_data.pair_info.rxbuf_owned = 1;
+
+ goto cleanup;
+ }
+
+ /*
+ * A UUID is specified. Return the information of all partitions matching
+ * the UUID
+ */
+
+ for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++)
+ if (pargs->a1 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].sp_uuid.a1 &&
+ pargs->a2 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].sp_uuid.a2 &&
+ pargs->a3 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].sp_uuid.a3 &&
+ pargs->a4 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].sp_uuid.a4) {
+ *(rxbuf_desc_info++) =
+ sandbox_ffa_priv_data.partitions.descs[descs_cnt].info;
+ }
+
+ if (rxbuf_desc_info != ((struct ffa_partition_info *)sandbox_ffa_priv_data.pair.rxbuf)) {
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ /* store the partitions count */
+ res->a2 = (unsigned long)
+ (rxbuf_desc_info - (struct ffa_partition_info *)
+ sandbox_ffa_priv_data.pair.rxbuf);
+
+ /* transfer ownership to the consumer: the non secure world */
+ sandbox_ffa_priv_data.pair_info.rxbuf_owned = 1;
+ } else {
+ /* Unrecognized UUID */
+ res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS;
+ }
+
+cleanup:
+
+ ffa_err("[Sandbox] FFA_PARTITION_INFO_GET (%ld)", res->a2);
+
+ res->a1 = 0;
+
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_rxtx_map - Emulated FFA_RXTX_MAP handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_RXTX_MAP FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_rxtx_map)
+{
+ res->a0 = FFA_SMC_32(FFA_ERROR);
+
+ if (sandbox_ffa_priv_data.pair.txbuf && sandbox_ffa_priv_data.pair.rxbuf) {
+ res->a2 = FFA_ERR_STAT_DENIED;
+ goto feedback;
+ }
+
+ if (pargs->a3 >= RXTX_BUFFERS_MIN_PAGES && pargs->a1 && pargs->a2) {
+ sandbox_ffa_priv_data.pair.txbuf = pargs->a1;
+ sandbox_ffa_priv_data.pair.rxbuf = pargs->a2;
+ sandbox_ffa_priv_data.pair_info.rxtx_buf_size = pargs->a3;
+ sandbox_ffa_priv_data.pair_info.rxbuf_mapped = 1;
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ res->a2 = 0;
+ goto feedback;
+ }
+
+ if (!pargs->a1 || !pargs->a2)
+ res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS;
+ else
+ res->a2 = FFA_ERR_STAT_NO_MEMORY;
+
+ ffa_err("[Sandbox] error in FFA_RXTX_MAP arguments (%d)", (int)res->a2);
+
+feedback:
+
+ res->a1 = 0;
+
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START,
+ 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_rxtx_unmap - Emulated FFA_RXTX_UNMAP handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_RXTX_UNMAP FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_rxtx_unmap)
+{
+ res->a0 = FFA_SMC_32(FFA_ERROR);
+ res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS;
+
+ if (GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != sandbox_ffa_priv_data.id)
+ goto feedback;
+
+ if (sandbox_ffa_priv_data.pair.txbuf && sandbox_ffa_priv_data.pair.rxbuf) {
+ sandbox_ffa_priv_data.pair.txbuf = 0;
+ sandbox_ffa_priv_data.pair.rxbuf = 0;
+ sandbox_ffa_priv_data.pair_info.rxtx_buf_size = 0;
+ sandbox_ffa_priv_data.pair_info.rxbuf_mapped = 0;
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ res->a2 = 0;
+ goto feedback;
+ }
+
+ ffa_err("[Sandbox] No buffer pair registered on behalf of the caller");
+
+feedback:
+
+ res->a1 = 0;
+
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START,
+ 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_rx_release - Emulated FFA_RX_RELEASE handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_RX_RELEASE FF-A function.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_rx_release)
+{
+ if (!sandbox_ffa_priv_data.pair_info.rxbuf_owned) {
+ res->a0 = FFA_SMC_32(FFA_ERROR);
+ res->a2 = FFA_ERR_STAT_DENIED;
+ } else {
+ sandbox_ffa_priv_data.pair_info.rxbuf_owned = 0;
+ res->a0 = FFA_SMC_32(FFA_SUCCESS);
+ res->a2 = 0;
+ }
+
+ res->a1 = 0;
+
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START,
+ 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_sp_valid - Checks SP validity
+ * @part_id: partition ID to check
+ *
+ * This is the function searches the input ID in the descriptors table.
+ *
+ * Return:
+ *
+ * 1 on success (Partition found). Otherwise, failure
+ */
+static int sandbox_ffa_sp_valid(u16 part_id)
+{
+ u32 descs_cnt;
+
+ for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++)
+ if (sandbox_ffa_priv_data.partitions.descs[descs_cnt].info.id == part_id)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_msg_send_direct_req - Emulated FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
+ * @{a0-a7} , res: The SMC call arguments and return structure.
+ *
+ * This is the function that emulates FFA_MSG_SEND_DIRECT_{REQ,RESP}
+ * FF-A functions. Only SMC 64-bit is supported in Sandbox.
+ *
+ * Emulating interrupts is not supported. So, FFA_RUN and FFA_INTERRUPT are not supported.
+ * In case of success FFA_MSG_SEND_DIRECT_RESP is returned with default pattern data (0xff).
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+SANDBOX_SMC_FFA_ABI(ffa_msg_send_direct_req)
+{
+ u16 part_id;
+
+ part_id = GET_DST_SP_ID(pargs->a1);
+
+ if ((GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != sandbox_ffa_priv_data.id) ||
+ !sandbox_ffa_sp_valid(part_id) ||
+ pargs->a2) {
+ res->a0 = FFA_SMC_32(FFA_ERROR);
+ res->a1 = 0;
+ res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS;
+
+ /* x3-x7 MBZ */
+ memset(FFA_X3_MBZ_REG_START,
+ 0, FFA_X3X7_MBZ_CNT * sizeof(unsigned long));
+
+ return 0;
+ }
+
+ res->a0 = FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP);
+
+ res->a1 = PREP_SRC_SP_ID(part_id) |
+ PREP_NS_PHYS_ENDPOINT_ID(sandbox_ffa_priv_data.id);
+
+ res->a2 = 0;
+
+ /*
+ * return 0xff bytes as a response
+ */
+ res->a3 = 0xffffffffffffffff;
+ res->a4 = 0xffffffffffffffff;
+ res->a5 = 0xffffffffffffffff;
+ res->a6 = 0xffffffffffffffff;
+ res->a7 = 0xffffffffffffffff;
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_get_prv_data - Returns the pointer to FF-A core pivate data
+ * @func_data: Pointer to the FF-A function arguments container structure
+ *
+ * This is the handler that returns the address of the FF-A core pivate data.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+static int sandbox_ffa_get_prv_data(struct ffa_sandbox_data *func_data)
+{
+ if (!func_data)
+ return -EINVAL;
+
+ if (!func_data->data0 || func_data->data0_size != sizeof(struct ffa_prvdata *))
+ return -EINVAL;
+
+ if (!func_data->data1 || func_data->data1_size != sizeof(struct sandbox_ffa_prvdata *))
+ return -EINVAL;
+
+ *((struct ffa_prvdata **)func_data->data0) = ffa_bus_prvdata_get();
+ *((struct sandbox_ffa_prvdata **)func_data->data1) = &sandbox_ffa_priv_data;
+
+ return 0;
+}
+
+/**
+ * sandbox_ffa_get_rxbuf_flags - Reading the mapping/ownership flags
+ * @queried_func_id: The FF-A function to be queried
+ * @func_data: Pointer to the FF-A function arguments container structure
+ *
+ * This is the handler that queries the status flags of the following emulated ABIs:
+ * FFA_RXTX_MAP, FFA_RXTX_UNMAP, FFA_RX_RELEASE
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+static int sandbox_ffa_get_rxbuf_flags(u32 queried_func_id, struct ffa_sandbox_data *func_data)
+{
+ if (!func_data)
+ return -EINVAL;
+
+ if (!func_data->data0 || func_data->data0_size != sizeof(u8))
+ return -EINVAL;
+
+ switch (queried_func_id) {
+ case FFA_RXTX_MAP:
+ case FFA_RXTX_UNMAP:
+ *((u8 *)func_data->data0) = sandbox_ffa_priv_data.pair_info.rxbuf_mapped;
+ return 0;
+ case FFA_RX_RELEASE:
+ *((u8 *)func_data->data0) = sandbox_ffa_priv_data.pair_info.rxbuf_owned;
+ return 0;
+ default:
+ ffa_err("[Sandbox] The querried FF-A interface flag (%d) undefined",
+ queried_func_id);
+ return -EINVAL;
+ }
+}
+
+/**
+ * sandbox_ffa_query_core_state - The driver dispatcher function
+ * @queried_func_id: The FF-A function to be queried
+ * @func_data: Pointer to the FF-A function arguments container structure
+ *
+ * Queries the status of FF-A ABI specified in the input argument.
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+int sandbox_ffa_query_core_state(u32 queried_func_id, struct ffa_sandbox_data *func_data)
+{
+ switch (queried_func_id) {
+ case FFA_VERSION:
+ case FFA_ID_GET:
+ case FFA_FEATURES:
+ return sandbox_ffa_get_prv_data(func_data);
+ case FFA_RXTX_MAP:
+ case FFA_RXTX_UNMAP:
+ case FFA_RX_RELEASE:
+ return sandbox_ffa_get_rxbuf_flags(queried_func_id, func_data);
+ default:
+ ffa_err("[Sandbox] The querried FF-A interface (%d) undefined", queried_func_id);
+ return -EINVAL;
+ }
+}
+
+/**
+ * sandbox_arm_ffa_smccc_smc - FF-A SMC call emulation
+ * @args: the SMC call arguments
+ * @res: the SMC call returned data
+ *
+ * Sandbox driver emulates the FF-A ABIs SMC call using this function.
+ * The emulated FF-A ABI is identified and invoked.
+ * FF-A emulation is based on the FF-A specification 1.0
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure.
+ * FF-A protocol error codes are returned using the registers arguments as described
+ * by the specification
+ */
+void sandbox_arm_ffa_smccc_smc(ffa_value_t args, ffa_value_t *res)
+{
+ int ret = 0;
+
+ switch (args.a0) {
+ case FFA_SMC_32(FFA_VERSION):
+ ret = sandbox_ffa_version(&args, res);
+ break;
+ case FFA_SMC_32(FFA_PARTITION_INFO_GET):
+ ret = sandbox_ffa_partition_info_get(&args, res);
+ break;
+ case FFA_SMC_32(FFA_RXTX_UNMAP):
+ ret = sandbox_ffa_rxtx_unmap(&args, res);
+ break;
+ case FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ):
+ ret = sandbox_ffa_msg_send_direct_req(&args, res);
+ break;
+ case FFA_SMC_32(FFA_ID_GET):
+ ret = sandbox_ffa_id_get(&args, res);
+ break;
+ case FFA_SMC_32(FFA_FEATURES):
+ ret = sandbox_ffa_features(&args, res);
+ break;
+ case FFA_SMC_64(FFA_RXTX_MAP):
+ ret = sandbox_ffa_rxtx_map(&args, res);
+ break;
+ case FFA_SMC_32(FFA_RX_RELEASE):
+ ret = sandbox_ffa_rx_release(&args, res);
+ break;
+ default:
+ ffa_err("[Sandbox] Undefined FF-A interface (0x%lx)", args.a0);
+ }
+
+ if (ret != 0)
+ ffa_err("[Sandbox] FF-A ABI internal failure (%d)", ret);
+}
+
+/**
+ * sandbox_ffa_probe - The driver probe function
+ * @dev: the sandbox_arm_ffa device
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+static int sandbox_ffa_probe(struct udevice *dev)
+{
+ return 0;
+}
+
+/**
+ * sandbox_ffa_remove - The driver remove function
+ * @dev: the sandbox_arm_ffa device
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+static int sandbox_ffa_remove(struct udevice *dev)
+{
+ ffa_info("[Sandbox] removing the device");
+ memset(&sandbox_ffa_priv_data, 0, sizeof(sandbox_ffa_priv_data));
+ return 0;
+}
+
+/**
+ * Declaring the sandbox_arm_ffa driver under UCLASS_FFA
+ */
+U_BOOT_DRIVER(sandbox_arm_ffa) = {
+ .name = FFA_SANDBOX_DRV_NAME,
+ .id = UCLASS_FFA,
+ .probe = sandbox_ffa_probe,
+ .remove = sandbox_ffa_remove,
+};
diff --git a/drivers/firmware/arm-ffa/sandbox_arm_ffa_prv.h b/drivers/firmware/arm-ffa/sandbox_arm_ffa_prv.h
new file mode 100644
index 0000000000..4db57f5092
--- /dev/null
+++ b/drivers/firmware/arm-ffa/sandbox_arm_ffa_prv.h
@@ -0,0 +1,144 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2022 ARM Limited
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#ifndef __SANDBOX_ARM_FFA_PRV_H
+#define __SANDBOX_ARM_FFA_PRV_H
+
+#include "arm_ffa_prv.h"
+#include <sandbox_arm_ffa.h>
+
+/*
+ * This header is private. It is exclusively used by the Sandbox FF-A driver
+ */
+
+/* FF-A core driver name */
+#define FFA_SANDBOX_DRV_NAME "sandbox_arm_ffa"
+
+/* FF-A ABIs internal error codes (as defined by the spec) */
+
+#define FFA_ERR_STAT_NOT_SUPPORTED -1
+#define FFA_ERR_STAT_INVALID_PARAMETERS -2
+#define FFA_ERR_STAT_NO_MEMORY -3
+#define FFA_ERR_STAT_BUSY -4
+#define FFA_ERR_STAT_DENIED -6
+
+/* Providing Arm SMCCC declarations to sandbox */
+
+#define ARM_SMCCC_FAST_CALL 1UL
+#define ARM_SMCCC_OWNER_STANDARD 4
+#define ARM_SMCCC_SMC_32 0
+#define ARM_SMCCC_SMC_64 1
+#define ARM_SMCCC_TYPE_SHIFT 31
+#define ARM_SMCCC_CALL_CONV_SHIFT 30
+#define ARM_SMCCC_OWNER_MASK 0x3F
+#define ARM_SMCCC_OWNER_SHIFT 24
+#define ARM_SMCCC_FUNC_MASK 0xFFFF
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+ (((type) << ARM_SMCCC_TYPE_SHIFT) | \
+ ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+ (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+ ((func_num) & ARM_SMCCC_FUNC_MASK))
+
+/* Non-secure physical FF-A instance */
+#define NS_PHYS_ENDPOINT_ID (0)
+
+#define GET_NS_PHYS_ENDPOINT_ID_MASK GENMASK(31, 16)
+#define GET_NS_PHYS_ENDPOINT_ID(x) \
+ ((u16)(FIELD_GET(GET_NS_PHYS_ENDPOINT_ID_MASK, (x))))
+
+/* Helper macro for reading the destination partition ID */
+#define GET_DST_SP_ID_MASK GENMASK(15, 0)
+#define GET_DST_SP_ID(x) \
+ ((u16)(FIELD_GET(GET_DST_SP_ID_MASK, (x))))
+
+/* Helper macro for setting the source partition ID */
+#define PREP_SRC_SP_ID_MASK GENMASK(31, 16)
+#define PREP_SRC_SP_ID(x) \
+ (FIELD_PREP(PREP_SRC_SP_ID_MASK, (x)))
+
+/* Helper macro for setting the destination endpoint ID */
+#define PREP_NS_PHYS_ENDPOINT_ID_MASK GENMASK(15, 0)
+#define PREP_NS_PHYS_ENDPOINT_ID(x) \
+ (FIELD_PREP(PREP_NS_PHYS_ENDPOINT_ID_MASK, (x)))
+
+/* RX/TX buffers minimum size */
+#define RXTX_BUFFERS_MIN_SIZE (RXTX_4K)
+#define RXTX_BUFFERS_MIN_PAGES (1)
+
+/* MBZ registers info */
+
+/* x1-x7 MBZ */
+#define FFA_X1X7_MBZ_CNT (7)
+#define FFA_X1X7_MBZ_REG_START (&res->a1)
+
+/* x4-x7 MBZ */
+#define FFA_X4X7_MBZ_CNT (4)
+#define FFA_X4X7_MBZ_REG_START (&res->a4)
+
+/* x3-x7 MBZ */
+#define FFA_X3X7_MBZ_CNT (5)
+#define FFA_X3_MBZ_REG_START (&res->a3)
+
+/* secure partitions count */
+#define SANDBOX_PARTITIONS_CNT (4)
+
+/* service 1 UUID binary data (little-endian format) */
+#define SANDBOX_SERVICE1_UUID_A1 0xed32d533
+#define SANDBOX_SERVICE1_UUID_A2 0x99e64209
+#define SANDBOX_SERVICE1_UUID_A3 0x9cc02d72
+#define SANDBOX_SERVICE1_UUID_A4 0xcdd998a7
+
+/* service 2 UUID binary data (little-endian format) */
+#define SANDBOX_SERVICE2_UUID_A1 0xed32d544
+#define SANDBOX_SERVICE2_UUID_A2 0x99e64209
+#define SANDBOX_SERVICE2_UUID_A3 0x9cc02d72
+#define SANDBOX_SERVICE2_UUID_A4 0xcdd998a7
+
+/**
+ * struct ffa_rxtxpair_info - structure hosting the RX/TX buffers flags
+ * @rxbuf_owned: RX buffer ownership flag (the owner is non secure world: the consumer)
+ * @rxbuf_mapped: RX buffer mapping flag
+ * @txbuf_owned TX buffer ownership flag
+ * @txbuf_mapped: TX buffer mapping flag
+ * @rxtx_buf_size: RX/TX buffers size as set by the FF-A core driver
+ *
+ * Data structure hosting the ownership/mapping flags of the RX/TX buffers
+ * When a buffer is owned/mapped its corresponding flag is set to 1 otherwise 0.
+ */
+struct ffa_rxtxpair_info {
+ u8 rxbuf_owned;
+ u8 rxbuf_mapped;
+ u8 txbuf_owned;
+ u8 txbuf_mapped;
+ u32 rxtx_buf_size;
+};
+
+/**
+ * struct sandbox_ffa_prvdata - the driver private data structure
+ *
+ * @dev: The arm_ffa device under u-boot driver model
+ * @fwk_version: FF-A framework version
+ * @id: u-boot endpoint ID
+ * @partitions: The partitions descriptors structure
+ * @pair: The RX/TX buffers pair
+ * @pair_info: The RX/TX buffers pair flags and size
+ * @conduit: The selected conduit
+ *
+ * The driver data structure hosting all the emulated secure world data.
+ */
+struct sandbox_ffa_prvdata {
+ struct udevice *dev;
+ u32 fwk_version;
+ u16 id;
+ struct ffa_partitions partitions;
+ struct ffa_rxtxpair pair;
+ struct ffa_rxtxpair_info pair_info;
+};
+
+#define SANDBOX_SMC_FFA_ABI(ffabi) static int sandbox_##ffabi(ffa_value_t *pargs, ffa_value_t *res)
+
+#endif
diff --git a/include/arm_ffa.h b/include/arm_ffa.h
index 74b16174c2..b88904fe50 100644
--- a/include/arm_ffa.h
+++ b/include/arm_ffa.h
@@ -90,7 +90,7 @@ struct ffa_bus_ops {
const struct ffa_bus_ops *ffa_bus_ops_get(void);

/**
- * ffa_bus_discover - discover FF-A bus and probes the arm_ffa device
+ * ffa_bus_discover - discover FF-A bus and probes the arm_ffa and sandbox_arm_ffa devices
*/
int ffa_bus_discover(struct udevice **pdev);

diff --git a/include/sandbox_arm_ffa.h b/include/sandbox_arm_ffa.h
new file mode 100644
index 0000000000..d5df16f282
--- /dev/null
+++ b/include/sandbox_arm_ffa.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2022 ARM Limited
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
+ */
+
+#ifndef __SANDBOX_ARM_FFA_H
+#define __SANDBOX_ARM_FFA_H
+
+#include <arm_ffa.h>
+
+/**
+ * struct sandbox_smccc_1_2_regs - Arguments for or Results from emulated SMC call
+ * @a0-a17 argument values from registers 0 to 17
+ */
+struct sandbox_smccc_1_2_regs {
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+ unsigned long a4;
+ unsigned long a5;
+ unsigned long a6;
+ unsigned long a7;
+ unsigned long a8;
+ unsigned long a9;
+ unsigned long a10;
+ unsigned long a11;
+ unsigned long a12;
+ unsigned long a13;
+ unsigned long a14;
+ unsigned long a15;
+ unsigned long a16;
+ unsigned long a17;
+};
+
+typedef struct sandbox_smccc_1_2_regs ffa_value_t;
+
+/* UUIDs of services supported by the sandbox driver */
+#define SANDBOX_SERVICE1_UUID "ed32d533-4209-99e6-2d72-cdd998a79cc0"
+#define SANDBOX_SERVICE2_UUID "ed32d544-4209-99e6-2d72-cdd998a79cc0"
+#define SANDBOX_SP1_ID 0x1245
+#define SANDBOX_SP2_ID 0x9836
+#define SANDBOX_SP3_ID 0x6452
+#define SANDBOX_SP4_ID 0x7814
+
+/* invalid service UUID (no matching SP) */
+#define SANDBOX_SERVICE3_UUID "55d532ed-0942-e699-722d-c09ca798d9cd"
+
+/* invalid service UUID (invalid UUID string format) */
+#define SANDBOX_SERVICE4_UUID "32ed-0942-e699-722d-c09ca798d9cd"
+
+#define SANDBOX_SP_COUNT_PER_VALID_SERVICE 2
+
+/**
+ * struct ffa_sandbox_data - generic data structure used to exchange
+ * data between test cases and the sandbox driver
+ * @data0_size: size of the first argument
+ * @data0: pointer to the first argument
+ * @data1_size>: size of the second argument
+ * @data1: pointer to the second argument
+ *
+ * Using this structure sandbox test cases can pass various types of data with different sizes.
+ */
+struct ffa_sandbox_data {
+ u32 data0_size; /* size of the first argument */
+ void *data0; /* pointer to the first argument */
+ u32 data1_size; /* size of the second argument */
+ void *data1; /* pointer to the second argument */
+};
+
+/**
+ * The sandbox driver public functions
+ */
+
+/**
+ * sandbox_ffa_query_core_state - Queries the status of FF-A ABIs
+ */
+int sandbox_ffa_query_core_state(u32 queried_func_id, struct ffa_sandbox_data *func_data);
+
+/**
+ * sandbox_ffa_get_device - create, bind and probe the sandbox_arm_ffa device
+ */
+int sandbox_ffa_device_get(void);
+
+/**
+ * sandbox_arm_ffa_smccc_smc - FF-A SMC call emulation
+ */
+void sandbox_arm_ffa_smccc_smc(ffa_value_t args, ffa_value_t *res);
+
+#endif
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 8949aca250..9cf089f162 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2185,7 +2185,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
}

-#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT) && !CONFIG_IS_ENABLED(SANDBOX_FFA)
/* unmap FF-A RX/TX buffers */
if (ffa_bus_ops_get()->rxtx_unmap(NULL))
log_err("Can't unmap FF-A RX/TX buffers\n");
--
2.17.1