
Hi Abdellatif,
On Wed, 29 Mar 2023 at 05:12, Abdellatif El Khlifi < abdellatif.elkhlifi@arm.com> wrote:
Add functional test cases for the FF-A support
These tests rely on the FF-A sandbox emulator and FF-A sandbox driver which help in inspecting the FF-A communication.
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com Cc: Tom Rini trini@konsulko.com Cc: Simon Glass sjg@chromium.org Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Jens Wiklander jens.wiklander@linaro.org Cc: Heinrich Schuchardt xypron.glpk@gmx.de
Changelog:
v10:
- use the FF-A driver Uclass operations
- use uclass_first_device()
- replace CONFIG_SANDBOX_FFA with CONFIG_ARM_FFA_TRANSPORT
- address nits
v9: align FF-A sandbox tests with FF-A discovery through DM
v8:
- update partition_info_get() second argument to be an SP count
- pass NULL device pointer to the FF-A bus discovery and operations
v7: set the tests to use 64-bit direct messaging
v4: align sandbox tests with the new FF-A driver interfaces and new way of error handling
v1: introduce sandbox tests
MAINTAINERS | 1 + doc/arch/arm64.ffa.rst | 1 + test/dm/Makefile | 2 + test/dm/ffa.c | 357 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 361 insertions(+) create mode 100644 test/dm/ffa.c
diff --git a/MAINTAINERS b/MAINTAINERS index b8019517ba..8f698b3f20 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -276,6 +276,7 @@ F: doc/arch/arm64.ffa.rst F: doc/usage/cmd/armffa.rst F: drivers/firmware/arm-ffa/ F: include/arm_ffa.h +F: test/dm/ffa.c
ARM FREESCALE IMX M: Stefano Babic sbabic@denx.de diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst index 457a0e112e..5b1450f579 100644 --- a/doc/arch/arm64.ffa.rst +++ b/doc/arch/arm64.ffa.rst @@ -38,6 +38,7 @@ The U-Boot FF-A support provides the following parts: 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. +- Sandbox FF-A test cases.
FF-A and SMC specifications
diff --git a/test/dm/Makefile b/test/dm/Makefile index 7a79b6e1a2..45563bdfb4 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0+ # # Copyright (c) 2013 Google, Inc +# Copyright 2022-2023 Arm Limited and/or its affiliates <
open-source-office@arm.com>
obj-$(CONFIG_UT_DM) += test-dm.o
@@ -85,6 +86,7 @@ obj-$(CONFIG_POWER_DOMAIN) += power-domain.o obj-$(CONFIG_ACPI_PMC) += pmc.o obj-$(CONFIG_DM_PMIC) += pmic.o obj-$(CONFIG_DM_PWM) += pwm.o +obj-$(CONFIG_ARM_FFA_TRANSPORT) += ffa.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o diff --git a/test/dm/ffa.c b/test/dm/ffa.c new file mode 100644 index 0000000000..d493597521 --- /dev/null +++ b/test/dm/ffa.c @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Functional tests for UCLASS_FFA class
- 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 <console.h> +#include <dm.h> +#include <asm/sandbox_arm_ffa.h> +#include <asm/sandbox_arm_ffa_priv.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h>
+/* Macros */
+#define LOG_MSG_SZ (100) +#define LOG_CMD_SZ (LOG_MSG_SZ * 2)
+/* Functional tests for the UCLASS_FFA */
+static int dm_test_ffa_log(struct unit_test_state *uts, char *msg) +{
char cmd[LOG_CMD_SZ] = {0};
console_record_reset();
snprintf(cmd, LOG_CMD_SZ, "echo \"%s\"", msg);
run_command(cmd, 0);
ut_assert_console_end();
return 0;
+}
+static int check_fwk_version(struct ffa_priv *priv, struct
unit_test_state *uts)
+{
struct ffa_sandbox_data func_data;
u32 fwk_version = 0;
func_data.data0 = &fwk_version;
func_data.data0_size = sizeof(fwk_version);
ut_assertok(sandbox_ffa_query_core_state(FFA_VERSION,
&func_data));
if (priv->dscvry_info.fwk_version != fwk_version) {
char msg[LOG_MSG_SZ] = {0};
snprintf(msg, LOG_MSG_SZ,
"[%s]: Error: framework version: core = 0x%x ,
sandbox = 0x%x", __func__,
priv->dscvry_info.fwk_version,
fwk_version);
dm_test_ffa_log(uts, msg);
return CMD_RET_FAILURE;
This is not a command. You should use ut_assert(false) here, perhaps? Please fix throughout.
}
return 0;
+}
+static int check_endpoint_id(struct ffa_priv *priv, struct
unit_test_state *uts)
+{
if (priv->id) {
char msg[LOG_MSG_SZ] = {0};
snprintf(msg, LOG_MSG_SZ,
"[%s]: Error: endpoint id: core = 0x%x",
__func__, priv->id);
dm_test_ffa_log(uts, msg);
return CMD_RET_FAILURE;
}
return 0;
+}
+static int check_rxtxbuf(struct ffa_priv *priv, struct unit_test_state
*uts)
+{
if (!priv->pair.rxbuf || !priv->pair.txbuf) {
char msg[LOG_MSG_SZ] = {0};
snprintf(msg, LOG_MSG_SZ, "[%s]: Error: rxbuf = %p txbuf
= %p", __func__,
priv->pair.rxbuf,
priv->pair.txbuf);
dm_test_ffa_log(uts, msg);
return CMD_RET_FAILURE;
}
return 0;
+}
+static int check_features(struct ffa_priv *priv, struct unit_test_state
*uts)
+{
char msg[LOG_MSG_SZ] = {0};
if (priv->pair.rxtx_min_pages != RXTX_4K &&
priv->pair.rxtx_min_pages != RXTX_16K &&
priv->pair.rxtx_min_pages != RXTX_64K) {
snprintf(msg,
LOG_MSG_SZ,
"[%s]: Error: FFA_RXTX_MAP features = 0x%lx",
__func__,
priv->pair.rxtx_min_pages);
dm_test_ffa_log(uts, msg);
return CMD_RET_FAILURE;
It's not clear to me why you are printing these messages? If should be enough to use ut_assert() as it shows you where the error happened, in a backtrace. Perhaps I am missing something?
}
return 0;
+}
+static int check_rxbuf_mapped_flag(u32 queried_func_id,
u8 rxbuf_mapped,
struct unit_test_state *uts)
+{
char msg[LOG_MSG_SZ] = {0};
switch (queried_func_id) {
case FFA_RXTX_MAP:
if (rxbuf_mapped)
return 0;
break;
case FFA_RXTX_UNMAP:
if (!rxbuf_mapped)
return 0;
break;
default:
return CMD_RET_FAILURE;
}
snprintf(msg, LOG_MSG_SZ, "[%s]: Error: %s mapping issue",
__func__,
(queried_func_id == FFA_RXTX_MAP ? "FFA_RXTX_MAP" :
"FFA_RXTX_UNMAP"));
dm_test_ffa_log(uts, msg);
return CMD_RET_FAILURE;
+}
+static int check_rxbuf_release_flag(u8 rxbuf_owned, struct
unit_test_state *uts)
+{
if (rxbuf_owned) {
char msg[LOG_MSG_SZ];
snprintf(msg, LOG_MSG_SZ, "[%s]: Error: RX buffer not
released", __func__);
dm_test_ffa_log(uts, msg);
return CMD_RET_FAILURE;
}
return 0;
+}
+static int test_ffa_msg_send_direct_req(u16 part_id, struct
unit_test_state *uts)
+{
struct ffa_send_direct_data msg;
u8 cnt;
struct udevice *dev;
uclass_first_device(UCLASS_FFA, &dev);
ut_assertnonnull(dev);
ut_assertok(ffa_sync_send_receive(dev, part_id, &msg, 1));
for (cnt = 0; cnt < sizeof(struct ffa_send_direct_data) /
sizeof(u64); cnt++)
ut_asserteq_64(-1UL, ((u64 *)&msg)[cnt]);
return 0;
+}
+static int test_partitions_and_comms(const char *service_uuid,
struct unit_test_state *uts)
+{
u32 count;
struct ffa_partition_info *parts_info;
u32 info_idx, exp_info_idx;
int ret;
struct udevice *dev;
struct ffa_sandbox_data func_data;
struct ffa_partitions *partitions;
uclass_first_device(UCLASS_FFA, &dev);
ut_assertnonnull(dev);
ut_assertok(uclass_first_device_err(...
/* Get from the driver the count of the SPs matching the UUID */
ret = ffa_partition_info_get(dev, service_uuid, &count, NULL);
/* Make sure partitions are detected */
ut_assertok(ret);
ut_asserteq(SANDBOX_SP_COUNT_PER_VALID_SERVICE, count);
/* Pre-allocate a buffer to be filled by the driver with
ffa_partition_info structs */
parts_info = calloc(count, sizeof(struct ffa_partition_info));
ut_assertnonnull(parts_info);
Use a local var
/* Ask the driver to fill the buffer with the SPs info */
ret = ffa_partition_info_get(dev, service_uuid, &count,
parts_info);
if (ret != 0) {
free(parts_info);
ut_assertok(ret);
}
/* SPs found , verify the partitions information */
func_data.data0 = &partitions;
func_data.data0_size = sizeof(struct ffa_partitions *);
ut_assertok(sandbox_ffa_query_core_state(FFA_PARTITION_INFO_GET,
&func_data));
ret = CMD_RET_FAILURE;
for (info_idx = 0; info_idx < count ; info_idx++) {
for (exp_info_idx = 0;
exp_info_idx < partitions->count;
exp_info_idx++) {
if (parts_info[info_idx].id ==
partitions->descs[exp_info_idx].info.id) {
ret = memcmp(&parts_info[info_idx],
&partitions->descs[exp_info_idx]
.info,
sizeof(struct
ffa_partition_info));
ut_asserteq_mem(). Please take a look at the functions available.
if (ret)
free(parts_info);
ut_assertok(ret);
/* Send and receive data from the current
partition */
test_ffa_msg_send_direct_req(parts_info[info_idx].id, uts);
}
ret = 0;
}
}
free(parts_info);
/* Verify expected partitions found in the emulated secure world
*/
ut_assertok(ret);
return 0;
+}
+static int dm_test_ffa_ack(struct unit_test_state *uts) +{
struct ffa_priv *priv;
struct ffa_sandbox_data func_data;
u8 rxbuf_flag = 0;
const char *svc1_uuid = SANDBOX_SERVICE1_UUID;
const char *svc2_uuid = SANDBOX_SERVICE2_UUID;
int ret;
struct udevice *dev;
/* Test probing the sandbox FF-A bus */
uclass_first_device(UCLASS_FFA, &dev);
ut_assertnonnull(dev);
/* Get a pointer to the sandbox FF-A bus private data */
priv = dev_get_priv(dev);
I think you want dev_get_uclass_priv() here, based on my othe rcomment
/* Make sure the private data pointer is retrieved */
ut_assertnonnull(priv);
/* Test FFA_VERSION */
[..]
Regards, Simon