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

Abdellatif El Khlifi abdellatif.elkhlifi at arm.com
Fri Mar 10 15:10:12 CET 2023


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 at arm.com>
Cc: Tom Rini <trini at konsulko.com>
Cc: Simon Glass <sjg at chromium.org>
Cc: Ilias Apalodimas <ilias.apalodimas at linaro.org>
Cc: Jens Wiklander <jens.wiklander at linaro.org>

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

v9: align FF-A sandbox driver with FF-A discovery through DM

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 +
 arch/sandbox/dts/sandbox.dtsi                 |   4 +
 arch/sandbox/dts/test.dts                     |   4 +
 configs/sandbox64_defconfig                   |   2 +
 configs/sandbox_defconfig                     |   2 +
 doc/arch/arm64.ffa.rst                        |   4 +
 doc/arch/sandbox/sandbox.rst                  |   1 +
 drivers/firmware/arm-ffa/Kconfig              |  11 +-
 drivers/firmware/arm-ffa/Makefile             |   1 +
 drivers/firmware/arm-ffa/core.c               |  36 +-
 drivers/firmware/arm-ffa/sandbox.c            | 610 ++++++++++++++++++
 .../firmware/arm-ffa/sandbox_arm_ffa_priv.h   | 129 ++++
 include/arm_ffa.h                             |   5 +-
 include/sandbox_arm_ffa.h                     | 124 ++++
 14 files changed, 928 insertions(+), 6 deletions(-)
 create mode 100644 drivers/firmware/arm-ffa/sandbox.c
 create mode 100644 drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h
 create mode 100644 include/sandbox_arm_ffa.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 18e9c2ce99..2b9d33e964 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -274,6 +274,7 @@ F:	doc/arch/arm64.ffa.rst
 F:	doc/usage/cmd/armffa.rst
 F:	drivers/firmware/arm-ffa/
 F:	include/arm_ffa.h
+F:	include/sandbox_arm_ffa.h
 
 ARM FREESCALE IMX
 M:	Stefano Babic <sbabic at denx.de>
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 30a305c4d2..059c273277 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -445,6 +445,10 @@
 	thermal {
 		compatible = "sandbox,thermal";
 	};
+
+	sandbox_arm_ffa {
+		compatible = "sandbox,arm_ffa";
+	};
 };
 
 &cros_ec {
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index d72d7a567a..11dc6ed0d9 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1802,6 +1802,10 @@
 		compatible = "u-boot,fwu-mdata-gpt";
 		fwu-mdata-store = <&mmc0>;
 	};
+
+	sandbox_arm_ffa {
+		compatible = "sandbox,arm_ffa";
+	};
 };
 
 #include "sandbox_pmic.dtsi"
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index ccbc18aad0..35d4676cf7 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -259,3 +259,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
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index a0fbdad20a..8aab8dda31 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -336,3 +336,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/arm64.ffa.rst b/doc/arch/arm64.ffa.rst
index 8fad9ef3d0..555ee9a6ae 100644
--- a/doc/arch/arm64.ffa.rst
+++ b/doc/arch/arm64.ffa.rst
@@ -64,6 +64,10 @@ CONFIG_ARM_FFA_TRANSPORT
     Enables the FF-A bus driver. Turn this on if you want to use FF-A
     communication.
 
+CONFIG_SANDBOX_FFA
+    Enables FF-A Sandbox driver. This emulates the FF-A ABIs handling under
+    Sandbox and provides functional tests for FF-A.
+
 FF-A ABIs under the hood
 ---------------------------------------
 
diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst
index cd7f8a2cb0..c5df372e00 100644
--- a/doc/arch/sandbox/sandbox.rst
+++ b/doc/arch/sandbox/sandbox.rst
@@ -200,6 +200,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 2cfd7ef5fc..b5430eb6f4 100644
--- a/drivers/firmware/arm-ffa/Kconfig
+++ b/drivers/firmware/arm-ffa/Kconfig
@@ -2,9 +2,9 @@
 
 config ARM_FFA_TRANSPORT
 	bool "Enable Arm Firmware Framework for Armv8-A driver"
-	depends on DM && ARM64
-	select ARM_SMCCC
-	select ARM_SMCCC_FEATURES
+	depends on DM && (ARM64 || SANDBOX)
+	select ARM_SMCCC if !SANDBOX
+	select ARM_SMCCC_FEATURES if !SANDBOX
 	imply CMD_ARMFFA
 	select LIB_UUID
 	select DEVRES
@@ -32,3 +32,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 c8d83b4bc9..d22c1ba609 100644
--- a/drivers/firmware/arm-ffa/Makefile
+++ b/drivers/firmware/arm-ffa/Makefile
@@ -6,3 +6,4 @@
 #   Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
 
 obj-y += arm-ffa-uclass.o core.o
+obj-$(CONFIG_SANDBOX_FFA) += sandbox.o
diff --git a/drivers/firmware/arm-ffa/core.c b/drivers/firmware/arm-ffa/core.c
index 2210f5343c..0d2e6ff0d4 100644
--- a/drivers/firmware/arm-ffa/core.c
+++ b/drivers/firmware/arm-ffa/core.c
@@ -1042,6 +1042,7 @@ bool ffa_try_discovery(void)
 	return true;
 }
 
+#if !CONFIG_IS_ENABLED(SANDBOX_FFA)
 /**
  * __arm_ffa_fn_smc() - SMC wrapper
  * @args: FF-A ABI arguments to be copied to Xn registers
@@ -1069,6 +1070,7 @@ void __arm_ffa_fn_smc(ffa_value_t args, ffa_value_t *res)
  * The FF-A driver supports the SMCCCv1.2 extended input/output registers.
  * So, the legacy SMC invocation is not used.
  *
+ * In Sandbox mode sandbox_arm_ffa is used to test arm_ffa driver.
  * Return:
  *
  * 0 on success. Otherwise, failure
@@ -1088,6 +1090,30 @@ ARM_SMCCC_FEATURE_DRIVER(arm_ffa) = {
 	.driver_name = FFA_DRV_NAME,
 	.is_supported = ffa_bus_is_supported,
 };
+#else
+/* SANDBOX_FFA */
+
+/**
+ * ffa_bind() - The driver bind function
+ * @dev:	the arm_ffa device
+ * When using sandbox tries to discover the emulated FF-A bus.
+ * Return:
+ *
+ * 0 on success.
+ */
+static int ffa_bind(struct udevice *dev)
+{
+	bool ret;
+
+	log_info("[FFA] binding the device\n");
+
+	ret = ffa_try_discovery();
+	if (ret)
+		return 0;
+	else
+		return -ENODEV;
+}
+#endif
 
 /**
  * ffa_set_smc_conduit() - Set the SMC conduit
@@ -1101,7 +1127,12 @@ ARM_SMCCC_FEATURE_DRIVER(arm_ffa) = {
  */
 static int ffa_set_smc_conduit(void)
 {
-	dscvry_info.invoke_ffa_fn = __arm_ffa_fn_smc;
+#if CONFIG_IS_ENABLED(SANDBOX_FFA)
+		dscvry_info.invoke_ffa_fn = sandbox_arm_ffa_smccc_smc;
+		log_info("[FFA] Using SMC emulation\n");
+#else
+		dscvry_info.invoke_ffa_fn = __arm_ffa_fn_smc;
+#endif
 
 	log_info("[FFA] Conduit is SMC\n");
 
@@ -1246,4 +1277,7 @@ U_BOOT_DRIVER(arm_ffa) = {
 	.remove	= ffa_remove,
 	.unbind	= ffa_unbind,
 	.ops		= &ffa_ops,
+#if CONFIG_IS_ENABLED(SANDBOX_FFA)
+	.bind		= ffa_bind,
+#endif
 };
diff --git a/drivers/firmware/arm-ffa/sandbox.c b/drivers/firmware/arm-ffa/sandbox.c
new file mode 100644
index 0000000000..84c2fc929f
--- /dev/null
+++ b/drivers/firmware/arm-ffa/sandbox.c
@@ -0,0 +1,610 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office at arm.com>
+ *
+ * Authors:
+ *   Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <string.h>
+#include <asm/global_data.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+#include <linux/errno.h>
+#include <linux/sizes.h>
+#include "sandbox_arm_ffa_priv.h"
+
+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 },
+		.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_version() - Emulated FFA_VERSION handler function
+ * @dev:	the sandbox FF-A device
+ * @{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)
+{
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	priv->fwk_version = FFA_VERSION_1_0;
+	res->a0 = priv->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
+ * @dev:	the sandbox FF-A device
+ * @{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)
+{
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	res->a0 = FFA_SMC_32(FFA_SUCCESS);
+	res->a1 = 0;
+
+	priv->id = NS_PHYS_ENDPOINT_ID;
+	res->a2 = priv->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
+ * @dev:	the sandbox FF-A device
+ * @{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));
+		log_err("[FFA] [Sandbox] FF-A interface 0x%lx not implemented\n", pargs->a1);
+	}
+
+	res->a1 = 0;
+
+	return 0;
+}
+
+/**
+ * sandbox_ffa_partition_info_get() - Emulated FFA_PARTITION_INFO_GET handler function
+ * @dev:	the sandbox FF-A device
+ * @{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;
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	res->a0 = FFA_SMC_32(FFA_ERROR);
+
+	if (!priv->pair.rxbuf) {
+		res->a2 = FFA_ERR_STAT_DENIED;
+		goto cleanup;
+	}
+
+	if (priv->pair_info.rxbuf_owned) {
+		res->a2 = FFA_ERR_STAT_BUSY;
+		goto cleanup;
+	}
+
+	if (!priv->partitions.descs) {
+		priv->partitions.descs = sandbox_partitions;
+		priv->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 ((priv->pair_info.rxtx_buf_size * SZ_4K) < descs_size_bytes) {
+		res->a2 = FFA_ERR_STAT_NO_MEMORY;
+		goto cleanup;
+	}
+
+	rxbuf_desc_info = priv->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++) =
+				priv->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 */
+		priv->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 == priv->partitions.descs[descs_cnt].sp_uuid.a1 &&
+		    pargs->a2 == priv->partitions.descs[descs_cnt].sp_uuid.a2 &&
+		    pargs->a3 == priv->partitions.descs[descs_cnt].sp_uuid.a3 &&
+		    pargs->a4 == priv->partitions.descs[descs_cnt].sp_uuid.a4) {
+			*(rxbuf_desc_info++) =
+				priv->partitions.descs[descs_cnt].info;
+		}
+
+	if (rxbuf_desc_info != priv->pair.rxbuf) {
+		res->a0 = FFA_SMC_32(FFA_SUCCESS);
+		/* Store the partitions count */
+		res->a2 = (unsigned long)
+			(rxbuf_desc_info - (struct ffa_partition_info *)priv->pair.rxbuf);
+
+		/* Transfer ownership to the consumer: the non secure world */
+		priv->pair_info.rxbuf_owned = 1;
+	} else {
+		/* Unrecognized UUID */
+		res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS;
+	}
+
+cleanup:
+
+	log_err("[FFA] [Sandbox] FFA_PARTITION_INFO_GET (%ld)\n", 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
+ * @dev:	the sandbox FF-A device
+ * @{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)
+{
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	res->a0 = FFA_SMC_32(FFA_ERROR);
+
+	if (priv->pair.txbuf && priv->pair.rxbuf) {
+		res->a2 = FFA_ERR_STAT_DENIED;
+		goto feedback;
+	}
+
+	if (pargs->a3 >= RXTX_BUFFERS_MIN_PAGES && pargs->a1 && pargs->a2) {
+		priv->pair.txbuf = map_sysmem(pargs->a1, 0);
+		priv->pair.rxbuf = map_sysmem(pargs->a2, 0);
+		priv->pair_info.rxtx_buf_size = pargs->a3;
+		priv->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;
+
+	log_err("[FFA] [Sandbox] error in FFA_RXTX_MAP arguments (%d)\n", (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
+ * @dev:	the sandbox FF-A device
+ * @{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)
+{
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	res->a0 = FFA_SMC_32(FFA_ERROR);
+	res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS;
+
+	if (GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != priv->id)
+		goto feedback;
+
+	if (priv->pair.txbuf && priv->pair.rxbuf) {
+		priv->pair.txbuf = 0;
+		priv->pair.rxbuf = 0;
+		priv->pair_info.rxtx_buf_size = 0;
+		priv->pair_info.rxbuf_mapped = 0;
+		res->a0 = FFA_SMC_32(FFA_SUCCESS);
+		res->a2 = 0;
+		goto feedback;
+	}
+
+	log_err("[FFA] [Sandbox] No buffer pair registered on behalf of the caller\n");
+
+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
+ * @dev:	the sandbox FF-A device
+ * @{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)
+{
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	if (!priv->pair_info.rxbuf_owned) {
+		res->a0 = FFA_SMC_32(FFA_ERROR);
+		res->a2 = FFA_ERR_STAT_DENIED;
+	} else {
+		priv->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
+ * @dev:	the sandbox_arm_ffa device
+ * @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(struct udevice *dev, u16 part_id)
+{
+	u32 descs_cnt;
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++)
+		if (priv->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
+ * @dev:	the sandbox FF-A device
+ * @{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;
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	part_id = GET_DST_SP_ID(pargs->a1);
+
+	if ((GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != priv->id) ||
+	    !sandbox_ffa_sp_valid(dev, 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(priv->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_rxbuf_flags() - Reading the mapping/ownership flags
+ * @dev:	the sandbox_arm_ffa device
+ * @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(struct udevice *dev, u32 queried_func_id,
+				       struct ffa_sandbox_data *func_data)
+{
+	struct sandbox_ffa_priv *priv = dev_get_priv(dev);
+
+	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) = priv->pair_info.rxbuf_mapped;
+		return 0;
+	case FFA_RX_RELEASE:
+		*((u8 *)func_data->data0) = priv->pair_info.rxbuf_owned;
+		return 0;
+	default:
+		log_err("[FFA] [Sandbox] The querried  FF-A interface flag (%d) undefined\n",
+			queried_func_id);
+		return -EINVAL;
+	}
+}
+
+/**
+ * sandbox_ffa_query_core_state() - The driver dispatcher function
+ * @dev:	the sandbox_arm_ffa device
+ * @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(struct udevice *dev, u32 queried_func_id,
+				 struct ffa_sandbox_data *func_data)
+{
+	switch (queried_func_id) {
+	case FFA_RXTX_MAP:
+	case FFA_RXTX_UNMAP:
+	case FFA_RX_RELEASE:
+		return sandbox_ffa_get_rxbuf_flags(dev, queried_func_id, func_data);
+	default:
+		log_err("[FFA] [Sandbox] Undefined FF-A interface (%d)\n", 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;
+	struct udevice *dev = NULL;
+
+	uclass_get_device_by_name(UCLASS_FFA, "sandbox_arm_ffa", &dev);
+	if (!dev) {
+		log_err("[FFA] [Sandbox] Cannot find FF-A sandbox device\n");
+		return;
+	}
+
+	switch (args.a0) {
+	case FFA_SMC_32(FFA_VERSION):
+		ret = sandbox_ffa_version(dev, &args, res);
+		break;
+	case FFA_SMC_32(FFA_PARTITION_INFO_GET):
+		ret = sandbox_ffa_partition_info_get(dev, &args, res);
+		break;
+	case FFA_SMC_32(FFA_RXTX_UNMAP):
+		ret = sandbox_ffa_rxtx_unmap(dev, &args, res);
+		break;
+	case FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ):
+		ret = sandbox_ffa_msg_send_direct_req(dev, &args, res);
+		break;
+	case FFA_SMC_32(FFA_ID_GET):
+		ret = sandbox_ffa_id_get(dev, &args, res);
+		break;
+	case FFA_SMC_32(FFA_FEATURES):
+		ret = sandbox_ffa_features(dev, &args, res);
+		break;
+	case FFA_SMC_64(FFA_RXTX_MAP):
+		ret = sandbox_ffa_rxtx_map(dev, &args, res);
+		break;
+	case FFA_SMC_32(FFA_RX_RELEASE):
+		ret = sandbox_ffa_rx_release(dev, &args, res);
+		break;
+	default:
+		log_err("[FFA] [Sandbox] Undefined FF-A interface (0x%lx)\n", args.a0);
+	}
+
+	if (ret != 0)
+		log_err("[FFA] [Sandbox] FF-A ABI internal failure (%d)\n", ret);
+}
+
+/**
+ * sandbox_ffa_probe() - The driver probe function
+ * @dev:	the sandbox_arm_ffa device
+ *
+ * Binds the FF-A bus driver and sets the sandbox device as the FF-A bus device parent
+ *
+ * Return:
+ *
+ * 0 on success. Otherwise, failure
+ */
+static int sandbox_ffa_probe(struct udevice *dev)
+{
+	struct udevice *child_dev = NULL;
+	int ret;
+
+	ret = device_bind_driver(dev, FFA_DRV_NAME, FFA_DRV_NAME, &child_dev);
+	if (ret) {
+		pr_err("%s was not bound: %d, aborting\n", FFA_DRV_NAME, ret);
+		return -ENODEV;
+	}
+
+	dev_set_parent_plat(child_dev, dev_get_plat(dev));
+
+	return 0;
+}
+
+static const struct udevice_id sandbox_ffa_id[] = {
+	{ "sandbox,arm_ffa", 0 },
+	{ },
+};
+
+/* Declaring the sandbox_arm_ffa driver under UCLASS_FFA */
+U_BOOT_DRIVER(sandbox_arm_ffa) = {
+	.name		= FFA_SANDBOX_DRV_NAME,
+	.of_match = sandbox_ffa_id,
+	.id		= UCLASS_FFA,
+	.probe		= sandbox_ffa_probe,
+	.priv_auto	= sizeof(struct sandbox_ffa_priv),
+};
diff --git a/drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h b/drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h
new file mode 100644
index 0000000000..c35d80de16
--- /dev/null
+++ b/drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office at arm.com>
+ *
+ * Authors:
+ *   Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
+ */
+
+#ifndef __SANDBOX_ARM_FFA_PRV_H
+#define __SANDBOX_ARM_FFA_PRV_H
+
+#include <sandbox_arm_ffa.h>
+#include "arm_ffa_priv.h"
+
+/* This header is exclusively used by the Sandbox FF-A driver and sandbox tests */
+
+/* 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
+
+/* 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)
+
+/* number of secure partitions emulated by the FF-A sandbox driver */
+#define SANDBOX_PARTITIONS_CNT (4)
+
+/* Binary data of services UUIDs emulated by the FF-A sandbox driver */
+
+/* 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_priv - 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_priv {
+	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(struct udevice *dev, \
+							      ffa_value_t *pargs, ffa_value_t *res)
+
+#endif
diff --git a/include/arm_ffa.h b/include/arm_ffa.h
index 69f3c51080..70a9eefae6 100644
--- a/include/arm_ffa.h
+++ b/include/arm_ffa.h
@@ -12,8 +12,9 @@
 #include <linux/printk.h>
 
 /*
- * This header is public. It can be used by clients to access
- * data structures and definitions they need
+ * This header is used to access FF-A data structures
+ * and definitions. The header is used by the FF-A core driver, clients,
+ * sandbox driver, sandbox tests, armffa command
  */
 
 /*
diff --git a/include/sandbox_arm_ffa.h b/include/sandbox_arm_ffa.h
new file mode 100644
index 0000000000..3d99b6b8fa
--- /dev/null
+++ b/include/sandbox_arm_ffa.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office at arm.com>
+ *
+ * Authors:
+ *   Abdellatif El Khlifi <abdellatif.elkhlifi at arm.com>
+ */
+
+#ifndef __SANDBOX_ARM_FFA_H
+#define __SANDBOX_ARM_FFA_H
+
+#include <arm_ffa.h>
+
+/*
+ * This header provides the sandbox driver declarations
+ * needed by FF-A driver, armffa command and sandbox tests
+ */
+
+/* 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))
+
+/**
+ * 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 strings of services emulated by the FF-A sandbox driver */
+#define SANDBOX_SERVICE1_UUID	"ed32d533-4209-99e6-2d72-cdd998a79cc0"
+#define SANDBOX_SERVICE2_UUID	"ed32d544-4209-99e6-2d72-cdd998a79cc0"
+
+/* IDs of secure partitions (SPs) emulated by the FF-A sandbox driver */
+#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"
+
+/* Number of valid services */
+#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() - The driver dispatcher function
+ * @dev:	the sandbox_arm_ffa device
+ * @queried_func_id:	The FF-A function to be queried
+ * @func_data:  Pointer to the FF-A function arguments container structure
+ * Return:
+ * 0 on success. Otherwise, failure
+ */
+int sandbox_ffa_query_core_state(struct udevice *dev, u32 queried_func_id,
+				 struct ffa_sandbox_data *func_data);
+
+/**
+ * sandbox_arm_ffa_smccc_smc() - FF-A SMC call emulation
+ * @args:	the SMC call arguments
+ * @res:	the SMC call returned data
+ * 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);
+
+#endif
-- 
2.25.1



More information about the U-Boot mailing list