diff --git a/MAINTAINERS b/MAINTAINERS index d1cfe38476f..0b5605e462d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -269,12 +269,13 @@ F: configs/cortina_presidio-asic-pnand_defconfig ARM FF-A M: Abdellatif El Khlifi S: Maintained +F: arch/sandbox/include/asm/sandbox_arm_ffa.h +F: arch/sandbox/include/asm/sandbox_arm_ffa_priv.h F: cmd/armffa.c 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 diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index f0ee0b3481a..8aaf911a41a 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -451,6 +451,15 @@ thermal { compatible = "sandbox,thermal"; }; + + arm-ffa-emul { + compatible = "sandbox,arm-ffa-emul"; + + sandbox-arm-ffa { + compatible = "sandbox,arm-ffa"; + }; + }; + }; &cros_ec { diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index b5509eee8cf..f351d5cb84b 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1831,6 +1831,14 @@ extcon { compatible = "sandbox,extcon"; }; + + arm-ffa-emul { + compatible = "sandbox,arm-ffa-emul"; + + sandbox-arm-ffa { + compatible = "sandbox,arm-ffa"; + }; + }; }; #include "sandbox_pmic.dtsi" diff --git a/arch/sandbox/include/asm/sandbox_arm_ffa.h b/arch/sandbox/include/asm/sandbox_arm_ffa.h new file mode 100644 index 00000000000..be2790f4960 --- /dev/null +++ b/arch/sandbox/include/asm/sandbox_arm_ffa.h @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2022-2023 Arm Limited and/or its affiliates + * + * Authors: + * Abdellatif El Khlifi + */ + +#ifndef __SANDBOX_ARM_FFA_H +#define __SANDBOX_ARM_FFA_H + +#include + +/* + * This header provides public sandbox FF-A emulator declarations + * and declarations needed by FF-A sandbox clients + */ + +/* UUIDs strings of the emulated services */ +#define SANDBOX_SERVICE1_UUID "ed32d533-4209-99e6-2d72-cdd998a79cc0" +#define SANDBOX_SERVICE2_UUID "ed32d544-4209-99e6-2d72-cdd998a79cc0" + +/* IDs of the emulated secure partitions (SPs) */ +#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 - query ABI state data structure + * @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 + * + * Used to pass various types of data with different sizes between + * the test cases and the sandbox emulator. + * The data is for querying FF-A ABIs state. + */ +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 FF-A emulator public functions */ + +/** + * sandbox_query_ffa_emul_state() - Inspect the FF-A ABIs + * @queried_func_id: The FF-A function to be queried + * @func_data: Pointer to the FF-A function arguments container structure + * + * Query the status of FF-A ABI specified in the input argument. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int sandbox_query_ffa_emul_state(u32 queried_func_id, + struct ffa_sandbox_data *func_data); + +#endif diff --git a/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h b/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h new file mode 100644 index 00000000000..b0881822d78 --- /dev/null +++ b/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2022-2023 Arm Limited and/or its affiliates + * + * Authors: + * Abdellatif El Khlifi + */ + +#ifndef __SANDBOX_ARM_FFA_PRV_H +#define __SANDBOX_ARM_FFA_PRV_H + +#include + +/* This header is exclusively used by the Sandbox FF-A driver and emulator */ + +/* 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 emulated FF-A secure partitions (SPs) */ +#define SANDBOX_PARTITIONS_CNT (4) + +/* Binary data of the emulated services UUIDs */ + +/* 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) + * @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 + * + * Hosts 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_emul - emulator data + * + * @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 + * @test_ffa_data: The data of the FF-A bus under test + * + * Hosts all the emulated secure world data. + */ +struct sandbox_ffa_emul { + u32 fwk_version; + u16 id; + struct ffa_partitions partitions; + struct ffa_rxtxpair pair; + struct ffa_rxtxpair_info pair_info; +}; + +/** + * ffa_emul_find() - Finds the FF-A emulator + * @dev: the sandbox FF-A device (sandbox-arm-ffa) + * @emulp: the FF-A emulator device (sandbox-ffa-emul) + * Return: + * 0 on success. Otherwise, failure + */ +int ffa_emul_find(struct udevice *dev, struct udevice **emulp); + +#endif diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 9bd81c1d03c..2b37aa3464c 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -261,3 +261,4 @@ CONFIG_FWU_MULTI_BANK_UPDATE=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +CONFIG_ARM_FFA_TRANSPORT=y diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 19cc6701e62..4300f952b07 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -347,3 +347,4 @@ CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +CONFIG_ARM_FFA_TRANSPORT=y diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst index aefd5274470..b7c754fa3d9 100644 --- a/doc/arch/arm64.ffa.rst +++ b/doc/arch/arm64.ffa.rst @@ -33,6 +33,10 @@ The U-Boot FF-A support provides the following parts: - A Uclass driver providing generic FF-A methods. - An Arm FF-A device driver providing Arm-specific methods and reusing the Uclass methods. +- A sandbox emulator for Arm FF-A, emulates the FF-A side of the Secure World and provides + FF-A ABIs inspection methods. +- An FF-A sandbox device driver for FF-A communication with the emulated Secure World. + The driver leverages the FF-A Uclass to establish FF-A communication. FF-A and SMC specifications ------------------------------------------- @@ -62,6 +66,7 @@ CONFIG_ARM_FFA_TRANSPORT Enables the FF-A support. Turn this on if you want to use FF-A communication. When using an Arm 64-bit platform, the Arm FF-A driver will be used. + When using sandbox, the sandbox FF-A emulator and FF-A sandbox driver will be used. FF-A ABIs under the hood --------------------------------------- @@ -98,10 +103,8 @@ architecture features including FF-A bus. Class Index Probed Driver Name ----------------------------------------------------------- - ... firmware 0 [ + ] psci |-- psci ffa 0 [ ] arm_ffa | `-- arm_ffa - ... The PSCI driver is bound to the PSCI device and when probed it tries to discover the architecture features by calling a callback the features drivers provide. @@ -205,6 +208,18 @@ The following features are provided: - FF-A bus can be compiled and used without EFI +Relationship between the sandbox emulator and the FF-A device +--------------------------------------------------------------- + +:: + + => dm tree + + Class Index Probed Driver Name + ----------------------------------------------------------- + ffa_emul 0 [ + ] sandbox_ffa_emul `-- arm-ffa-emul + ffa 0 [ ] sandbox_arm_ffa `-- sandbox-arm-ffa + The armffa command ----------------------------------- diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst index 77ca6bc4cc7..a3631de7493 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 a7d53928598..d75f8b53fd8 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 @@ -33,5 +33,10 @@ config ARM_FFA_TRANSPORT Generic FF-A methods are implemented in the Uclass (arm-ffa-uclass.c). Arm specific methods are implemented in the Arm driver (arm-ffa.c). - For more details about the FF-A support, please refer to doc/arch/arm64.ffa.rst + FF-A sandbox is provided to run FF-A under sandbox and allows to test the FF-A Uclass. + Sandbox support includes an emulator for Arm FF-A which emulates the FF-A side of + the Secure World and provides FF-A ABIs inspection methods (ffa-emul-uclass.c). + An FF-A sandbox driver is also provided for FF-A communication with the emulated + Secure World (sandbox_ffa.c). + For more details about the FF-A support, please refer to doc/arch/arm64.ffa.rst diff --git a/drivers/firmware/arm-ffa/Makefile b/drivers/firmware/arm-ffa/Makefile index 11b17662853..318123a7f42 100644 --- a/drivers/firmware/arm-ffa/Makefile +++ b/drivers/firmware/arm-ffa/Makefile @@ -5,4 +5,12 @@ # Authors: # Abdellatif El Khlifi -obj-y += arm-ffa-uclass.o arm-ffa.o +# build the generic FF-A methods +obj-y += arm-ffa-uclass.o +ifeq ($(CONFIG_SANDBOX),y) +# build the FF-A sandbox emulator and driver +obj-y += ffa-emul-uclass.o sandbox_ffa.o +else +# build the Arm64 FF-A driver +obj-y += arm-ffa.o +endif diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c new file mode 100644 index 00000000000..5562bbaac3a --- /dev/null +++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c @@ -0,0 +1,720 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022-2023 Arm Limited and/or its affiliates + * + * Authors: + * Abdellatif El Khlifi + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 }, + .sp_uuid = { + .a1 = SANDBOX_SERVICE2_UUID_A1, + .a2 = SANDBOX_SERVICE2_UUID_A2, + .a3 = SANDBOX_SERVICE2_UUID_A3, + .a4 = SANDBOX_SERVICE2_UUID_A4, + } + }, + { + .info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 }, + .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, + } + } + +}; + +/* The emulator functions */ + +/** + * sandbox_ffa_version() - Emulated FFA_VERSION handler function + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_VERSION FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ + +static int sandbox_ffa_version(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res) +{ + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + 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(ulong)); + + return 0; +} + +/** + * sandbox_ffa_id_get() - Emulated FFA_ID_GET handler function + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_ID_GET FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_id_get(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res) +{ + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + 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(ulong)); + + return 0; +} + +/** + * sandbox_ffa_features() - Emulated FFA_FEATURES handler function + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_FEATURES FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_features(ffa_value_t *pargs, ffa_value_t *res) +{ + res->a1 = 0; + + 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(ulong)); + return 0; + } + + res->a0 = FFA_SMC_32(FFA_ERROR); + res->a2 = -NOT_SUPPORTED; + /* x3-x7 MBZ */ + memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong)); + log_err("FF-A interface %lx not implemented\n", pargs->a1); + + return ffa_to_std_errmap[NOT_SUPPORTED]; +} + +/** + * sandbox_ffa_partition_info_get() - Emulated FFA_PARTITION_INFO_GET handler + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_PARTITION_INFO_GET FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_partition_info_get(struct udevice *emul, ffa_value_t *pargs, + ffa_value_t *res) +{ + struct ffa_partition_info *rxbuf_desc_info = NULL; + u32 descs_cnt; + u32 descs_size_bytes; + int ret; + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + res->a0 = FFA_SMC_32(FFA_ERROR); + + if (!priv->pair.rxbuf) { + res->a2 = -DENIED; + ret = ffa_to_std_errmap[DENIED]; + goto cleanup; + } + + if (priv->pair_info.rxbuf_owned) { + res->a2 = -BUSY; + ret = ffa_to_std_errmap[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 descs buffer size */ + if ((priv->pair_info.rxtx_buf_size * SZ_4K) < descs_size_bytes) { + res->a2 = -NO_MEMORY; + ret = ffa_to_std_errmap[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; + ret = 0; + + goto cleanup; + } + + /* A UUID specified. Return the info of all SPs 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 = (ulong) + (rxbuf_desc_info - (struct ffa_partition_info *) + priv->pair.rxbuf); + ret = 0; + + /* Transfer ownership to the consumer: the non secure world */ + priv->pair_info.rxbuf_owned = 1; + } else { + /* Unrecognized UUID */ + res->a2 = -INVALID_PARAMETERS; + ret = ffa_to_std_errmap[INVALID_PARAMETERS]; + } + +cleanup: + + log_err("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(ulong)); + + return ret; +} + +/** + * sandbox_ffa_rxtx_map() - Emulated FFA_RXTX_MAP handler + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_RXTX_MAP FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_rxtx_map(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res) +{ + int ret; + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + res->a0 = FFA_SMC_32(FFA_ERROR); + + if (priv->pair.txbuf && priv->pair.rxbuf) { + res->a2 = -DENIED; + ret = ffa_to_std_errmap[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; + ret = 0; + goto feedback; + } + + if (!pargs->a1 || !pargs->a2) { + res->a2 = -INVALID_PARAMETERS; + ret = ffa_to_std_errmap[INVALID_PARAMETERS]; + } else { + res->a2 = -NO_MEMORY; + ret = ffa_to_std_errmap[NO_MEMORY]; + } + + log_err("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(ulong)); + + return ret; +} + +/** + * sandbox_ffa_rxtx_unmap() - Emulated FFA_RXTX_UNMAP handler + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_RXTX_UNMAP FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_rxtx_unmap(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res) +{ + int ret; + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + res->a0 = FFA_SMC_32(FFA_ERROR); + res->a2 = -INVALID_PARAMETERS; + ret = ffa_to_std_errmap[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; + ret = 0; + goto feedback; + } + + log_err("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(ulong)); + + return ret; +} + +/** + * sandbox_ffa_rx_release() - Emulated FFA_RX_RELEASE handler + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_RX_RELEASE FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_rx_release(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res) +{ + int ret; + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + if (!priv->pair_info.rxbuf_owned) { + res->a0 = FFA_SMC_32(FFA_ERROR); + res->a2 = -DENIED; + ret = ffa_to_std_errmap[DENIED]; + } else { + priv->pair_info.rxbuf_owned = 0; + res->a0 = FFA_SMC_32(FFA_SUCCESS); + res->a2 = 0; + ret = 0; + } + + res->a1 = 0; + + /* x3-x7 MBZ */ + memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong)); + + return ret; +} + +/** + * sandbox_ffa_sp_valid() - Check SP validity + * @emul: The sandbox FF-A emulator device + * @part_id: partition ID to check + * + * Search the input ID in the descriptors table. + * + * Return: + * + * 1 on success (Partition found). Otherwise, failure + */ +static int sandbox_ffa_sp_valid(struct udevice *emul, u16 part_id) +{ + u32 descs_cnt; + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + 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 + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A ABIs. + * 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 + */ +static int sandbox_ffa_msg_send_direct_req(struct udevice *emul, + ffa_value_t *pargs, ffa_value_t *res) +{ + u16 part_id; + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + part_id = GET_DST_SP_ID(pargs->a1); + + if (GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != priv->id || + !sandbox_ffa_sp_valid(emul, part_id) || pargs->a2) { + res->a0 = FFA_SMC_32(FFA_ERROR); + res->a1 = 0; + res->a2 = -INVALID_PARAMETERS; + + /* x3-x7 MBZ */ + memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong)); + + return ffa_to_std_errmap[INVALID_PARAMETERS]; + } + + 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 = -1UL; + res->a4 = -1UL; + res->a5 = -1UL; + res->a6 = -1UL; + res->a7 = -1UL; + + return 0; +} + +/** + * sandbox_ffa_get_rxbuf_flags() - Read the mapping/ownership flags + * @emul: The sandbox FF-A emulator device + * @queried_func_id: The FF-A function to be queried + * @func_data: Pointer to the FF-A function arguments container structure + * + * Query 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 *emul, u32 queried_func_id, + struct ffa_sandbox_data *func_data) +{ + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + 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("The querried FF-A interface flag (%d) undefined\n", + queried_func_id); + return -EINVAL; + } +} + +/** + * sandbox_ffa_get_fwk_version() - Return the FFA framework version + * @emul: The sandbox FF-A emulator device + * @func_data: Pointer to the FF-A function arguments container structure + * + * Return the FFA framework version read from the FF-A emulator data. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_get_fwk_version(struct udevice *emul, struct ffa_sandbox_data *func_data) +{ + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + if (!func_data) + return -EINVAL; + + if (!func_data->data0 || + func_data->data0_size != sizeof(priv->fwk_version)) + return -EINVAL; + + *((u32 *)func_data->data0) = priv->fwk_version; + + return 0; +} + +/** + * sandbox_ffa_get_parts() - Return the address of partitions data + * @emul: The sandbox FF-A emulator device + * @func_data: Pointer to the FF-A function arguments container structure + * + * Return the address of partitions data read from the FF-A emulator data. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_get_parts(struct udevice *emul, struct ffa_sandbox_data *func_data) +{ + struct sandbox_ffa_emul *priv = dev_get_priv(emul); + + if (!func_data) + return -EINVAL; + + if (!func_data->data0 || + func_data->data0_size != sizeof(struct ffa_partitions *)) + return -EINVAL; + + *((struct ffa_partitions **)func_data->data0) = &priv->partitions; + + return 0; +} + +/** + * sandbox_query_ffa_emul_state() - Inspect the FF-A ABIs + * @queried_func_id: The FF-A function to be queried + * @func_data: Pointer to the FF-A function arguments container structure + * + * Query the status of FF-A ABI specified in the input argument. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int sandbox_query_ffa_emul_state(u32 queried_func_id, + struct ffa_sandbox_data *func_data) +{ + struct udevice *emul; + int ret; + + ret = uclass_first_device_err(UCLASS_FFA_EMUL, &emul); + if (ret) { + log_err("Cannot find FF-A emulator during querying state\n"); + return ret; + } + + switch (queried_func_id) { + case FFA_RXTX_MAP: + case FFA_RXTX_UNMAP: + case FFA_RX_RELEASE: + return sandbox_ffa_get_rxbuf_flags(emul, queried_func_id, func_data); + case FFA_VERSION: + return sandbox_ffa_get_fwk_version(emul, func_data); + case FFA_PARTITION_INFO_GET: + return sandbox_ffa_get_parts(emul, func_data); + default: + log_err("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 + * + * Emulate the FF-A ABIs SMC call. + * 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 *emul; + + ret = uclass_first_device_err(UCLASS_FFA_EMUL, &emul); + if (ret) { + log_err("Cannot find FF-A emulator during SMC emulation\n"); + return; + } + + switch (args->a0) { + case FFA_SMC_32(FFA_VERSION): + ret = sandbox_ffa_version(emul, args, res); + break; + case FFA_SMC_32(FFA_PARTITION_INFO_GET): + ret = sandbox_ffa_partition_info_get(emul, args, res); + break; + case FFA_SMC_32(FFA_RXTX_UNMAP): + ret = sandbox_ffa_rxtx_unmap(emul, args, res); + break; + case FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ): + ret = sandbox_ffa_msg_send_direct_req(emul, args, res); + break; + case FFA_SMC_32(FFA_ID_GET): + ret = sandbox_ffa_id_get(emul, 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(emul, args, res); + break; + case FFA_SMC_32(FFA_RX_RELEASE): + ret = sandbox_ffa_rx_release(emul, args, res); + break; + default: + log_err("Undefined FF-A interface (%lx)\n", + args->a0); + } + + if (ret != 0) + log_err("FF-A ABI internal failure (%d)\n", ret); +} + +/** + * invoke_ffa_fn() - SMC wrapper + * @args: FF-A ABI arguments to be copied to Xn registers + * @res: FF-A ABI return data to be copied from Xn registers + * + * Calls the emulated SMC call. + */ +void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res) +{ + sandbox_arm_ffa_smccc_smc(&args, res); +} + +/** + * ffa_emul_find() - Find the FF-A emulator + * @dev: the sandbox FF-A device (sandbox-arm-ffa) + * @emulp: the FF-A emulator device (sandbox-ffa-emul) + * + * Search for the FF-A emulator and returns its device pointer. + * + * Return: + * 0 on success. Otherwise, failure + */ +int ffa_emul_find(struct udevice *dev, struct udevice **emulp) +{ + int ret; + + ret = uclass_first_device_err(UCLASS_FFA_EMUL, emulp); + if (ret) { + log_err("Cannot find FF-A emulator\n"); + return ret; + } + + log_info("FF-A emulator ready to use\n"); + + return 0; +} + +UCLASS_DRIVER(ffa_emul) = { + .name = "ffa_emul", + .id = UCLASS_FFA_EMUL, + .post_bind = dm_scan_fdt_dev, +}; + +static const struct udevice_id sandbox_ffa_emul_ids[] = { + { .compatible = "sandbox,arm-ffa-emul" }, + { } +}; + +/* Declaring the sandbox FF-A emulator under UCLASS_FFA_EMUL */ +U_BOOT_DRIVER(sandbox_ffa_emul) = { + .name = "sandbox_ffa_emul", + .id = UCLASS_FFA_EMUL, + .of_match = sandbox_ffa_emul_ids, + .priv_auto = sizeof(struct sandbox_ffa_emul), +}; diff --git a/drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h b/drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h deleted file mode 100644 index 4338f9c9b17..00000000000 --- a/drivers/firmware/arm-ffa/sandbox_arm_ffa_priv.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright 2022-2023 Arm Limited and/or its affiliates - * - * Authors: - * Abdellatif El Khlifi - */ - -#ifndef __SANDBOX_ARM_FFA_PRV_H -#define __SANDBOX_ARM_FFA_PRV_H - -/* Future sandbox support private declarations */ - -#endif diff --git a/drivers/firmware/arm-ffa/sandbox_ffa.c b/drivers/firmware/arm-ffa/sandbox_ffa.c new file mode 100644 index 00000000000..ef9491ccead --- /dev/null +++ b/drivers/firmware/arm-ffa/sandbox_ffa.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022-2023 Arm Limited and/or its affiliates + * + * Authors: + * Abdellatif El Khlifi + */ +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/** + * sandbox_ffa_discover() - perform sandbox FF-A discovery + * @dev: The sandbox FF-A bus device + * Try to discover the FF-A framework. Discovery is performed by + * querying the FF-A framework version from secure world using the FFA_VERSION ABI. + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_discover(struct udevice *dev) +{ + int ret; + struct udevice *emul; + + log_info("Emulated FF-A framework discovery\n"); + + ret = ffa_emul_find(dev, &emul); + if (ret) { + log_err("Cannot find FF-A emulator\n"); + return ret; + } + + ret = ffa_get_version_hdlr(dev); + if (ret) + return ret; + + return 0; +} + +/** + * sandbox_ffa_probe() - The sandbox FF-A driver probe function + * @dev: the sandbox-arm-ffa device + * Save the emulator device in uc_priv. + * Return: + * + * 0 on success. + */ +static int sandbox_ffa_probe(struct udevice *dev) +{ + int ret; + struct ffa_priv *uc_priv = dev_get_uclass_priv(dev); + + ret = uclass_first_device_err(UCLASS_FFA_EMUL, &uc_priv->emul); + if (ret) { + log_err("Cannot find FF-A emulator\n"); + return ret; + } + + return 0; +} + +/** + * sandbox_ffa_bind() - The sandbox FF-A driver bind function + * @dev: the sandbox-arm-ffa device + * Try to discover the emulated FF-A bus. + * Return: + * + * 0 on success. + */ +static int sandbox_ffa_bind(struct udevice *dev) +{ + int ret; + + ret = sandbox_ffa_discover(dev); + if (ret) + return ret; + + return 0; +} + +/* Sandbox Arm FF-A emulator operations */ + +static const struct ffa_bus_ops sandbox_ffa_ops = { + .partition_info_get = ffa_get_partitions_info_hdlr, + .sync_send_receive = ffa_msg_send_direct_req_hdlr, + .rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr, +}; + +static const struct udevice_id sandbox_ffa_id[] = { + { "sandbox,arm-ffa", 0 }, + { }, +}; + +/* Declaring the sandbox FF-A driver under UCLASS_FFA */ +U_BOOT_DRIVER(sandbox_arm_ffa) = { + .name = "sandbox_arm_ffa", + .of_match = sandbox_ffa_id, + .id = UCLASS_FFA, + .bind = sandbox_ffa_bind, + .probe = sandbox_ffa_probe, + .ops = &sandbox_ffa_ops, +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 3c6af2e3d2f..0432c95c9ed 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -63,6 +63,7 @@ enum uclass_id { UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_EXTCON, /* External Connector Class */ UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */ + UCLASS_FFA_EMUL, /* sandbox FF-A device emulator */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FPGA, /* FPGA device */ UCLASS_FUZZING_ENGINE, /* Fuzzing engine */