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.

Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhl...@arm.com>
Cc: Tom Rini <tr...@konsulko.com>
Cc: Simon Glass <s...@chromium.org>
Cc: Ilias Apalodimas <ilias.apalodi...@linaro.org>
Cc: Jens Wiklander <jens.wiklan...@linaro.org>

---

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

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.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               |  24 +-
 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, 939 insertions(+), 14 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 663e2abccd..598ae76e16 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -255,6 +255,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 <sba...@denx.de>
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index b20b181ab1..cd5575ce61 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -250,3 +250,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/configs/sandbox_defconfig b/configs/sandbox_defconfig
index df6a28ef24..27eb2f7ab3 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -327,3 +327,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.rst b/doc/arch/sandbox.rst
index 068d4a3be4..5d7e1b2c48 100644
--- a/doc/arch/sandbox.rst
+++ b/doc/arch/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 624e834b1f..343f6499d0 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/README.ffa.drv
 
+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.elkhl...@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 7bc90f7f66..3e0d4c112c 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)
@@ -94,11 +104,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 324367d12b..2810e4a636 100644
--- a/drivers/firmware/arm-ffa/core.c
+++ b/drivers/firmware/arm-ffa/core.c
@@ -1096,6 +1096,7 @@ static int ffa_msg_send_direct_req(u16 dst_part_id, 
struct ffa_send_direct_data
        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
@@ -1109,6 +1110,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
@@ -1122,7 +1124,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");
@@ -1299,15 +1306,16 @@ struct ffa_prvdata **ffa_bus_prvdata_get(void)
 }
 
 /**
- * ffa_bus_discover - discover FF-A bus and probe the arm_ffa device
+ * ffa_bus_discover - discover FF-A bus and probe arm_ffa and sandbox_arm_ffa 
devices
  *
  * 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:
@@ -1318,9 +1326,15 @@ int ffa_bus_discover(void)
 {
        int ret = 0;
 
-       if (!ffa_priv_data)
+       if (!ffa_priv_data) {
                ret = ffa_device_get();
 
+#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..16e1fdc809
--- /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.elkhl...@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.
+ *
+ * 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.elkhl...@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 d146e7b328..6fa097d4ed 100644
--- a/include/arm_ffa.h
+++ b/include/arm_ffa.h
@@ -86,7 +86,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(void);
 
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.elkhl...@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 2054b33568..bea7ad7608 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())
                        debug("[efi_boottime][ERROR]: can not unmap FF-A RX/TX 
buffers\n");
-- 
2.17.1

Reply via email to