xtest: SPMC Add basic test
Add a first FF-A test. It will test the basic functionality of the FF-A
messages.
The tests are added to a new test suite(ffa_spmc) and can be run with the:
xtest -t ffa_spmc command
The corresponding SPs can be found in the trusted-services repo.
Currently the TS debugfs driver is needed to communicate with the SPs. It
can be loaded by running the
/mnt/host/out/linux-arm-ffa-user/load_module.sh script which is created
as part of the linux-arm-ffa-user target.
Signed-off-by: Jelle Sels <jelle.sels@arm.com>
Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
diff --git a/host/xtest/CMakeLists.txt b/host/xtest/CMakeLists.txt
index 040043a..320d336 100644
--- a/host/xtest/CMakeLists.txt
+++ b/host/xtest/CMakeLists.txt
@@ -62,6 +62,9 @@
xtest_test.c
xtest_uuid_helpers.c
)
+if(CFG_SECURE_PARTITION AND CFG_SPMC_TESTS)
+ list (APPEND SRC ffa_spmc_1000.c)
+endif()
if (WITH_GP_TESTS)
add_compile_options(-DWITH_GP_TESTS=1)
diff --git a/host/xtest/Makefile b/host/xtest/Makefile
index a898c57..af45f5e 100644
--- a/host/xtest/Makefile
+++ b/host/xtest/Makefile
@@ -83,6 +83,10 @@
xtest_test.c \
xtest_uuid_helpers.c
+ifeq ($(CFG_SECURE_PARTITION)-$(CFG_SPMC_TESTS),y-y)
+srcs += ffa_spmc_1000.c
+endif
+
ifeq ($(CFG_SECSTOR_TA_MGMT_PTA),y)
srcs += install_ta.c
endif
diff --git a/host/xtest/ffa_spmc_1000.c b/host/xtest/ffa_spmc_1000.c
new file mode 100644
index 0000000..acbd8ea
--- /dev/null
+++ b/host/xtest/ffa_spmc_1000.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ */
+#include <fcntl.h>
+#include <ffa.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include "include/uapi/linux/arm_ffa_user.h"
+#include "xtest_helpers.h"
+#include "xtest_test.h"
+
+#define FFA_DRIVER_FS_PATH "/sys/kernel/debug/arm_ffa_user"
+#define SPMC_TEST_OK 0xaa
+
+enum sp_tests {
+ EP_TEST_SP,
+ EP_TEST_SP_COMMUNICATION,
+};
+
+static int ffa_fd = -1;
+
+static const char test_endpoint1_uuid[] =
+ "5c9edbc3-7b3a-4367-9f83-7c191ae86a37";
+static const char test_endpoint2_uuid[] =
+ "7817164c-c40c-4d1a-867a-9bb2278cf41a";
+static const char test_endpoint3_uuid[] =
+ "23eb0100-e32a-4497-9052-2f11e584afa6";
+
+static struct ffa_ioctl_ep_desc test_endpoint1 = {
+ .uuid_ptr = (uint64_t) test_endpoint1_uuid,
+};
+
+static struct ffa_ioctl_ep_desc test_endpoint2 = {
+ .uuid_ptr = (uint64_t) test_endpoint2_uuid,
+};
+
+static struct ffa_ioctl_ep_desc test_endpoint3 = {
+ .uuid_ptr = (uint64_t) test_endpoint3_uuid,
+};
+
+static void close_debugfs(void)
+{
+ int err = 0;
+
+ if (ffa_fd >= 0) {
+ err = close(ffa_fd);
+ if (err < 0)
+ Do_ADBG_Log("Error: Could not close the FF-A driver");
+ }
+ ffa_fd = -1;
+}
+
+static bool init_sp_xtest(ADBG_Case_t *c)
+{
+ if (ffa_fd < 0) {
+ ffa_fd = open(FFA_DRIVER_FS_PATH, O_RDWR);
+ if (ffa_fd < 0) {
+ Do_ADBG_Log("Error: Could not open the FF-A driver");
+ return false;
+ }
+ }
+ return true;
+}
+
+static int start_sp_test(uint16_t endpoint, enum sp_tests test,
+ struct ffa_ioctl_msg_args *args)
+{
+ args->dst_id = endpoint;
+ args->args[0] = (uint32_t)test;
+ return ioctl(ffa_fd, FFA_IOC_MSG_SEND, args);
+}
+
+static uint16_t get_endpoint_id(uint64_t endp)
+{
+ struct ffa_ioctl_ep_desc sid = { .uuid_ptr = endp };
+
+ /* Get ID of destination SP based on UUID */
+ if(ioctl(ffa_fd, FFA_IOC_GET_PART_ID, &sid))
+ return 0xffff;
+
+ return sid.id;
+}
+
+static void xtest_ffa_spmc_test_1001(ADBG_Case_t *c)
+{
+ struct ffa_ioctl_msg_args args = { 0 };
+ uint16_t endpoint1_id = 0;
+ uint16_t endpoint2_id = 0;
+ int rc = 0;
+
+ Do_ADBG_BeginSubCase(c, "SP1 comms check");
+ if (!init_sp_xtest(c)) {
+ Do_ADBG_Log("Failed to initialise test, skipping SP test");
+ goto out;
+ }
+
+ endpoint1_id = get_endpoint_id(test_endpoint1.uuid_ptr);
+ if (endpoint1_id == 0xffff) {
+ Do_ADBG_Log("Could not contact xtest_1 sp, skipping SP test");
+ Do_ADBG_Log("Add xtest_1 sp to the image to enable tests");
+ goto out;
+ }
+
+ memset(&args, 0, sizeof(args));
+ rc = start_sp_test(endpoint1_id, EP_TEST_SP, &args);
+ if (!ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0))
+ goto out;
+
+ if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK))
+ goto out;
+ Do_ADBG_EndSubCase(c, "SP1 comms check");
+
+ Do_ADBG_BeginSubCase(c, "Sp2 comms check");
+ endpoint2_id = get_endpoint_id(test_endpoint2.uuid_ptr);
+ if (endpoint2_id == 0xffff) {
+ Do_ADBG_Log("Could not contact xtest_2 sp, skipping SP test");
+ Do_ADBG_Log("Add xtest_2 sp to the image to enable tests");
+ goto out;
+ }
+
+ memset(&args, 0, sizeof(args));
+ rc = start_sp_test(endpoint2_id, EP_TEST_SP, &args);
+ if (!ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0))
+ goto out;
+
+ if (!ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK))
+ goto out;
+ Do_ADBG_EndSubCase(c, "Sp2 comms check");
+
+ /* Test SP to SP messaging. */
+ Do_ADBG_BeginSubCase(c, "SP to SP messaging check");
+ memset(&args, 0, sizeof(args));
+ args.args[1] = endpoint2_id;
+
+ rc = start_sp_test(endpoint1_id, EP_TEST_SP_COMMUNICATION, &args);
+ ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
+
+ memset(&args, 0, sizeof(args));
+ args.args[1] = endpoint1_id;
+
+ rc = start_sp_test(endpoint2_id, EP_TEST_SP_COMMUNICATION, &args);
+ ADBG_EXPECT_COMPARE_SIGNED(c, rc, ==, 0);
+ ADBG_EXPECT_COMPARE_UNSIGNED(c, args.args[0], ==, SPMC_TEST_OK);
+
+
+out:
+ Do_ADBG_EndSubCase(c, NULL);
+ close_debugfs();
+}
+
+ADBG_CASE_DEFINE(ffa_spmc, 1001, xtest_ffa_spmc_test_1001,
+ "Test FF-A communication");
diff --git a/host/xtest/include/uapi/linux/arm_ffa_user.h b/host/xtest/include/uapi/linux/arm_ffa_user.h
new file mode 100644
index 0000000..9ef0be3
--- /dev/null
+++ b/host/xtest/include/uapi/linux/arm_ffa_user.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020-2022, Arm Limited
+ */
+
+#ifndef __ARM_FFA_USER_H
+#define __ARM_FFA_USER_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define FFA_IOC_MAGIC 0xf0
+#define FFA_IOC_BASE 0
+
+/**
+ * struct ffa_ioctl_ep_desc - Query endpoint ID
+ * @uuid_ptr: [in] Pointer to queried UUID. Format must be an RFC 4122 string,
+ * i.e. "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee".
+ * @id: [out] 16-bit ID of endpoint.
+ */
+struct ffa_ioctl_ep_desc {
+ __u64 uuid_ptr;
+ __u16 id;
+};
+#define FFA_IOC_GET_PART_ID _IOWR(FFA_IOC_MAGIC, FFA_IOC_BASE + 0, \
+ struct ffa_ioctl_ep_desc)
+
+/**
+ * struct ffa_ioctl_msg_args - Send direct message request
+ * @args: [in/out] Arguments of FFA_MSG_SEND_DIRECT_REQ (w3-w7). If the
+ * response is FFA_MSG_SEND_DIRECT_RESP, the received arguments are
+ * returned in this field.
+ * @dst_id: [in] 16-bit ID of destination endpoint.
+ */
+struct ffa_ioctl_msg_args {
+ __u32 args[5];
+ __u16 dst_id;
+};
+#define FFA_IOC_MSG_SEND _IOWR(FFA_IOC_MAGIC, FFA_IOC_BASE + 1, \
+ struct ffa_ioctl_msg_args)
+
+/**
+ * struct ffa_ioctl_shm_desc - Share/reclaim memory region
+ * @handle: [in/out] Handle assigned by the SPM. Output when used with
+ * FFA_IOC_SHM_INIT, input when used with FFA_IOC_SHM_DEINIT.
+ * @size: [in/out] In: the required size of region in bytes. Out: the
+ * actual region size allocated by the kernel. Unused on reclaim.
+ * @dst_id: [in] 16-bit ID of destination endpoint. Unused on reclaim.
+ */
+struct ffa_ioctl_shm_desc {
+ __u64 handle;
+ __u64 size;
+ __u16 dst_id;
+};
+#define FFA_IOC_SHM_INIT _IOWR(FFA_IOC_MAGIC, FFA_IOC_BASE + 2, \
+ struct ffa_ioctl_shm_desc)
+
+#define FFA_IOC_SHM_DEINIT _IOW(FFA_IOC_MAGIC, FFA_IOC_BASE + 3, \
+ struct ffa_ioctl_shm_desc)
+
+/**
+ * struct ffa_ioctl_buf_desc - Read/write shared memory region
+ * @handle: [in] Handle of the memory region.
+ * @buf_ptr: [in] Pointer to user space buffer. Data is copied from/to this
+ * buffer to/from the memory region shared with the given endpoint.
+ * @buf_len: [in] Length of read/write in bytes.
+ */
+struct ffa_ioctl_buf_desc {
+ __u64 handle;
+ __u64 buf_ptr;
+ __u64 buf_len;
+};
+#define FFA_IOC_SHM_READ _IOW(FFA_IOC_MAGIC, FFA_IOC_BASE + 4, \
+ struct ffa_ioctl_buf_desc)
+
+#define FFA_IOC_SHM_WRITE _IOW(FFA_IOC_MAGIC, FFA_IOC_BASE + 5, \
+ struct ffa_ioctl_buf_desc)
+
+#endif /* __ARM_FFA_USER_H */
diff --git a/host/xtest/xtest_main.c b/host/xtest/xtest_main.c
index 00cf667..0815d5d 100644
--- a/host/xtest/xtest_main.c
+++ b/host/xtest/xtest_main.c
@@ -2,6 +2,7 @@
/*
* Copyright (c) 2016, Linaro Limited
* Copyright (c) 2014, STMicroelectronics International N.V.
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
*/
#include <err.h>
@@ -35,6 +36,9 @@
#ifdef CFG_PKCS11_TA
ADBG_SUITE_DEFINE(pkcs11);
#endif
+#ifdef CFG_SPMC_TESTS
+ADBG_SUITE_DEFINE(ffa_spmc);
+#endif
ADBG_SUITE_DEFINE(regression);
char *xtest_tee_name = NULL;
@@ -53,7 +57,13 @@
#define PKCS11_SUITE ""
#endif
-static char gsuitename[] = "regression" GP_SUITE PKCS11_SUITE;
+#ifdef CFG_SPMC_TESTS
+#define FFA_SPMC_SUITE "+ffa_spmc"
+#else
+#define FFA_SPMC_SUITE ""
+#endif
+
+static char gsuitename[] = "regression" GP_SUITE PKCS11_SUITE FFA_SPMC_SUITE;
void usage(char *program);
@@ -72,6 +82,9 @@
#ifdef CFG_PKCS11_TA
printf(" pkcs11");
#endif
+#ifdef CFG_SPMC_TESTS
+ printf(" ffa_spmc");
+#endif
printf("\n");
printf("\t To run several suites, use multiple names\n");
printf("\t separated by a '+')\n");
diff --git a/host/xtest/xtest_test.h b/host/xtest/xtest_test.h
index bb083f7..215024b 100644
--- a/host/xtest/xtest_test.h
+++ b/host/xtest/xtest_test.h
@@ -20,6 +20,9 @@
#ifdef CFG_PKCS11_TA
ADBG_SUITE_DECLARE(pkcs11);
#endif
+#ifdef CFG_SPMC_TESTS
+ADBG_SUITE_DECLARE(ffa_spmc);
+#endif
ADBG_SUITE_DECLARE(regression);
/* TEEC_Result */