arm_ffa: introduce sandbox FF-A support

Emulate Secure World's FF-A ABIs and allow testing U-Boot FF-A support

Features of the sandbox FF-A support:

- Introduce an FF-A emulator
- Introduce an FF-A device driver for FF-A comms with emulated Secure World
- Provides test methods allowing to read the status of the inspected ABIs

The sandbox FF-A emulator supports only 64-bit direct messaging.

Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
Cc: Tom Rini <trini@konsulko.com>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Cc: Jens Wiklander <jens.wiklander@linaro.org>
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Abdellatif El Khlifi 2023-08-04 14:33:41 +01:00 committed by Tom Rini
parent 39d383bdac
commit a09852d862
15 changed files with 1081 additions and 22 deletions

View file

@ -269,10 +269,11 @@ F: configs/cortina_presidio-asic-pnand_defconfig
ARM FF-A ARM FF-A
M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
S: Maintained S: Maintained
F: arch/sandbox/include/asm/sandbox_arm_ffa.h
F: arch/sandbox/include/asm/sandbox_arm_ffa_priv.h
F: doc/arch/arm64.ffa.rst F: doc/arch/arm64.ffa.rst
F: drivers/firmware/arm-ffa/ F: drivers/firmware/arm-ffa/
F: include/arm_ffa.h F: include/arm_ffa.h
F: include/sandbox_arm_ffa.h
ARM FREESCALE IMX ARM FREESCALE IMX
M: Stefano Babic <sbabic@denx.de> M: Stefano Babic <sbabic@denx.de>

View file

@ -451,6 +451,15 @@
thermal { thermal {
compatible = "sandbox,thermal"; compatible = "sandbox,thermal";
}; };
arm-ffa-emul {
compatible = "sandbox,arm-ffa-emul";
sandbox-arm-ffa {
compatible = "sandbox,arm-ffa";
};
};
}; };
&cros_ec { &cros_ec {

View file

@ -1831,6 +1831,14 @@
extcon { extcon {
compatible = "sandbox,extcon"; compatible = "sandbox,extcon";
}; };
arm-ffa-emul {
compatible = "sandbox,arm-ffa-emul";
sandbox-arm-ffa {
compatible = "sandbox,arm-ffa";
};
};
}; };
#include "sandbox_pmic.dtsi" #include "sandbox_pmic.dtsi"

View file

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __SANDBOX_ARM_FFA_H
#define __SANDBOX_ARM_FFA_H
#include <arm_ffa.h>
/*
* 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

View file

@ -0,0 +1,121 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __SANDBOX_ARM_FFA_PRV_H
#define __SANDBOX_ARM_FFA_PRV_H
#include <arm_ffa_priv.h>
/* 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

View file

@ -260,3 +260,4 @@ CONFIG_FWU_MULTI_BANK_UPDATE=y
CONFIG_UNIT_TEST=y CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y CONFIG_UT_TIME=y
CONFIG_UT_DM=y CONFIG_UT_DM=y
CONFIG_ARM_FFA_TRANSPORT=y

View file

@ -345,3 +345,4 @@ CONFIG_TEST_FDTDEC=y
CONFIG_UNIT_TEST=y CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y CONFIG_UT_TIME=y
CONFIG_UT_DM=y CONFIG_UT_DM=y
CONFIG_ARM_FFA_TRANSPORT=y

View file

@ -33,6 +33,10 @@ The U-Boot FF-A support provides the following parts:
- A Uclass driver providing generic FF-A methods. - A Uclass driver providing generic FF-A methods.
- An Arm FF-A device driver providing Arm-specific methods and reusing the Uclass 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 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 Enables the FF-A support. Turn this on if you want to use FF-A
communication. communication.
When using an Arm 64-bit platform, the Arm FF-A driver will be used. 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 FF-A ABIs under the hood
--------------------------------------- ---------------------------------------
@ -98,10 +103,8 @@ architecture features including FF-A bus.
Class Index Probed Driver Name Class Index Probed Driver Name
----------------------------------------------------------- -----------------------------------------------------------
...
firmware 0 [ + ] psci |-- psci firmware 0 [ + ] psci |-- psci
ffa 0 [ ] arm_ffa | `-- arm_ffa ffa 0 [ ] arm_ffa | `-- arm_ffa
...
The PSCI driver is bound to the PSCI device and when probed it tries to discover 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. the architecture features by calling a callback the features drivers provide.
@ -203,6 +206,18 @@ The following features are provided:
- FF-A bus can be compiled and used without EFI - 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
Example of boot logs with FF-A enabled Example of boot logs with FF-A enabled
-------------------------------------- --------------------------------------

View file

@ -200,6 +200,7 @@ Supported Drivers
U-Boot sandbox supports these emulations: U-Boot sandbox supports these emulations:
- Arm FF-A
- Block devices - Block devices
- Chrome OS EC - Chrome OS EC
- GPIO - GPIO

View file

@ -2,9 +2,9 @@
config ARM_FFA_TRANSPORT config ARM_FFA_TRANSPORT
bool "Enable Arm Firmware Framework for Armv8-A driver" bool "Enable Arm Firmware Framework for Armv8-A driver"
depends on DM && ARM64 depends on DM && (ARM64 || SANDBOX)
select ARM_SMCCC select ARM_SMCCC if !SANDBOX
select ARM_SMCCC_FEATURES select ARM_SMCCC_FEATURES if !SANDBOX
select LIB_UUID select LIB_UUID
select DEVRES select DEVRES
help help
@ -32,5 +32,10 @@ config ARM_FFA_TRANSPORT
Generic FF-A methods are implemented in the Uclass (arm-ffa-uclass.c). 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). 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

View file

@ -5,4 +5,12 @@
# Authors: # Authors:
# Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> # Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
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

View file

@ -0,0 +1,720 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <dm.h>
#include <mapmem.h>
#include <string.h>
#include <asm/global_data.h>
#include <asm/sandbox_arm_ffa.h>
#include <asm/sandbox_arm_ffa_priv.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/root.h>
#include <linux/errno.h>
#include <linux/sizes.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_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),
};

View file

@ -1,14 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __SANDBOX_ARM_FFA_PRV_H
#define __SANDBOX_ARM_FFA_PRV_H
/* Future sandbox support private declarations */
#endif

View file

@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <arm_ffa.h>
#include <dm.h>
#include <log.h>
#include <asm/global_data.h>
#include <asm/sandbox_arm_ffa_priv.h>
#include <dm/device-internal.h>
#include <linux/errno.h>
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,
};

View file

@ -63,6 +63,7 @@ enum uclass_id {
UCLASS_ETH_PHY, /* Ethernet PHY device */ UCLASS_ETH_PHY, /* Ethernet PHY device */
UCLASS_EXTCON, /* External Connector Class */ UCLASS_EXTCON, /* External Connector Class */
UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */ UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */
UCLASS_FFA_EMUL, /* sandbox FF-A device emulator */
UCLASS_FIRMWARE, /* Firmware */ UCLASS_FIRMWARE, /* Firmware */
UCLASS_FPGA, /* FPGA device */ UCLASS_FPGA, /* FPGA device */
UCLASS_FUZZING_ENGINE, /* Fuzzing engine */ UCLASS_FUZZING_ENGINE, /* Fuzzing engine */