Add SPM test for OP_TEE
Add test for testing the SPM component. We added a linux arm host
application and 3 SPs. The SPs share the same code but are only build
with different UUIDs.
The test performs the following tests:
-Test the communication between the Normal World and a SP and SP to SP
communication.
-Test memory sharing between Normal World and SP and SP to SP.
The tests can be ran by running the coresponding xtests
xtest 90
Signed-off-by: Jelle Sels <jelle.sels@arm.com>
Change-Id: Iebb7d4242bc3def233cf00675aaae5a5d9c3b578
diff --git a/components/service/spm_test/optee_sp_user_defines.h b/components/service/spm_test/optee_sp_user_defines.h
new file mode 100644
index 0000000..da484c0
--- /dev/null
+++ b/components/service/spm_test/optee_sp_user_defines.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SP_HEADER_DEFINES_H
+#define SP_HEADER_DEFINES_H
+
+/* To get UUID definition */
+#define OPTEE_SP_FLAGS 0
+
+/* Provisioned stack size */
+#define OPTEE_SP_STACK_SIZE (64 * 1024)
+
+/* Provisioned heap size */
+#define OPTEE_SP_HEAP_SIZE (32 * 1024)
+
+#endif /* SP_HEADER_DEFINES_H */
diff --git a/components/service/spm_test/sp.c b/components/service/spm_test/sp.c
new file mode 100644
index 0000000..8deaa36
--- /dev/null
+++ b/components/service/spm_test/sp.c
@@ -0,0 +1,812 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ffa_api.h>
+#include <ffa_internal_api.h>
+#include <ffa_memory_descriptors.h>
+#include <sp_api.h>
+#include <sp_discovery.h>
+#include <sp_memory_management.h>
+#include <sp_rxtx.h>
+#include <string.h>
+#include <trace.h>
+
+#define SP_TEST_OK 0xaa
+
+static volatile uint8_t tx_buffer[4096] __aligned(4096);
+static volatile uint8_t rx_buffer[4096] __aligned(4096);
+static volatile uint8_t my_buf[4096] __aligned(4096);
+static volatile uint8_t *shared_buffer;
+static size_t shared_buffer_size;
+
+
+
+enum errors {
+ ERR_OK,
+ ERR_VERSION,
+ ERR_ID_GET,
+ ERR_FEATURES,
+ ERR_SP_COMMUNICATION,
+ ERR_RXTX_MAP,
+ ERR_PARTITION,
+ ERR_RXTX_UNMAP,
+ ERR_MEM_INCORRECT_ACCESS,
+ ERR_MEM_RETRIEVE,
+ ERR_MEM_RELINQUISH,
+ ERR_SP_SHARE,
+ ERR_SP_SHARE_EXC,
+ ERR_TEST_NOT_FOUND
+};
+
+enum sp_tests {
+ EP_TEST_SP,
+ EP_TEST_SP_COMMUNICATION,
+ EP_TEST_SP_INCREASE,
+ EP_TRY_R_ACCESS,
+ EP_TRY_W_ACCESS,
+ EP_RETRIEVE,
+ EP_RELINQUISH,
+ EP_SP_MEM_SHARING,
+ EP_SP_MEM_SHARING_MULTI,
+ EP_SP_MEM_SHARING_EXC,
+ EP_SP_MEM_INCORRECT_ACCESS,
+ EP_SP_NOP
+};
+
+const char* sp_test_str[]= {
+ "EP_TEST_SP",
+ "EP_TEST_SP_COMMUNICATION",
+ "EP_TEST_SP_INCREASE",
+ "EP_TRY_R_ACCESS",
+ "EP_TRY_W_ACCESS",
+ "EP_RETRIEVE",
+ "EP_RELINQUISH",
+ "EP_SP_MEM_SHARING",
+ "EP_SP_MEM_SHARING_MULTI",
+ "EP_SP_MEM_SHARING_EXC",
+ "EP_SP_MEM_INCORRECT_ACCESS",
+ "EP_SP_NOP"
+};
+
+static bool test_ffa_version(void)
+{
+ sp_result result = SP_RESULT_OK;
+ uint16_t major = 0;
+ uint16_t minor = 0;
+
+ IMSG("Testing ffa_version()\n");
+
+ result = sp_discovery_ffa_version_get(&major, &minor);
+ if (result == SP_RESULT_OK) {
+ IMSG("ffa_version(): %"PRIu32".%"PRIu32"\n", major, minor);
+
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_version(): not supported\n");
+ } else {
+ EMSG("ffa_version(): unknown error %"PRId32"\n", result);
+ }
+
+ return false;
+}
+
+static bool test_ffa_id_get(uint16_t *id)
+{
+ sp_result result = SP_RESULT_OK;
+
+ IMSG("Testing ffa_id_get()\n");
+
+ result = sp_discovery_own_id_get(id);
+ if (result == SP_RESULT_OK) {
+ IMSG("ffa_id_get(): 0x%"PRIx16"\n", *id);
+
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_id_get(): not supported\n");
+ } else {
+ EMSG("ffa_id_get(): unknown error %"PRId32"\n", result);
+ }
+
+ return false;
+}
+
+static bool test_ffa_features(void)
+{
+ ffa_result result = FFA_OK;
+ struct ffa_interface_properties properties = {0};
+
+ IMSG("Testing ffa_features(FFA_RXTX_MAP)\n");
+
+ result = ffa_features(FFA_RXTX_MAP_32, &properties);
+ if (result == FFA_OK) {
+ static const char * const sizes[] = {
+ "4kB", "64kB", "16kB", "reserved"};
+ uint32_t buffer_size = properties.interface_properties[0] &
+ 0x3U;
+
+ IMSG("ffa_features(): minimum buffer size=%s\n",
+ sizes[buffer_size]);
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_features(): not supported\n");
+ } else {
+ EMSG("ffa_features(): unknown error %"PRId32"\n", result);
+ }
+ return false;
+}
+
+static bool test_ffa_rxtx_map(void)
+{
+ sp_result result = SP_RESULT_OK;
+
+ IMSG("Testing ffa_rxtx_map(%p %p, 1)\n", tx_buffer, rx_buffer);
+
+ result = sp_rxtx_buffer_map((void*)tx_buffer,(void*)rx_buffer,
+ sizeof(rx_buffer));
+ if (result == FFA_OK) {
+ IMSG("ffa_rxtx_map(): success\n");
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_rxtx_map(): not supported\n");
+ } else {
+ EMSG("ffa_rxtx_map(): unknown error %"PRId32"\n", result);
+ }
+
+ return false;
+}
+
+static bool test_ffa_partition_info_get(void)
+{
+ sp_result result = SP_RESULT_OK;
+ struct sp_partition_info partitions[10] = {0};
+ uint32_t i = 0;
+ uint32_t count = 10;
+
+ IMSG("Testing ffa_partition_info_get(nil)\n");
+
+ result = sp_discovery_partition_info_get_all(partitions, &count);
+ if (result == SP_RESULT_OK) {
+
+ IMSG("ffa_partition_info_get(): count=%"PRIu32"\n", count);
+
+ for (i = 0; i < count; i++) {
+ IMSG("partition #%u: ID=%u, execution_count=%u \
+ direct request = %c, send direcy request = %c, \
+ indirect request = %c\n",
+ i, partitions[i].partition_id,
+ partitions[i].execution_context_count,
+ partitions[i].supports_direct_requests ? '1': '0',
+ partitions[i].can_send_direct_requests ? '1': '0',
+ partitions[i].supports_indirect_requests ? '1':
+ '0'
+ );
+ }
+
+ IMSG("Testing ffa_rx_release()\n");
+
+ result = ffa_rx_release();
+ if (result == FFA_OK) {
+ IMSG("ffa_rx_release(): success\n");
+ return true;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_rx_release(): not supported\n");
+ return false;
+ }
+ EMSG("ffa_rx_release(): unknown error %"PRId32"\n", result);
+ return false;
+ } else if (result == FFA_NOT_SUPPORTED) {
+ IMSG("ffa_partition_info_get(): not supported\n");
+ return false;
+ }
+ EMSG("ffa_partition_info_get(): unknown error %"PRId32"\n", result);
+ return false;
+}
+
+static bool test_ffa_rxtx_unmap()
+{
+ sp_result result = SP_RESULT_OK;
+
+ result = sp_rxtx_buffer_unmap();
+ if (result == SP_RESULT_OK) {
+ IMSG("sp_rxtx_buffer_unmap(): success\n");
+ return true;
+ }
+ EMSG("sp_rxtx_buffer_unmap(): unknown error %"PRId32"\n", result);
+ return false;
+}
+
+static void return_error(uint32_t error, struct ffa_direct_msg *msg)
+{
+ ffa_msg_send_direct_resp(msg->destination_id, msg->source_id, 0xff,
+ error, 0, 0, 0, msg);
+}
+
+static void return_ok(struct ffa_direct_msg *msg)
+{
+
+ ffa_msg_send_direct_resp(msg->destination_id,
+ msg->source_id, SP_TEST_OK, 0, 0, 0, 0, msg);
+}
+
+static bool test_read_access(void)
+{
+ return (shared_buffer[0] != 5);
+
+}
+
+static void test_write_access(void)
+{
+ shared_buffer[0] = 0xff;
+}
+
+static void test_increase(struct ffa_direct_msg *msg)
+{
+ msg->args[1]++;
+ msg->args[2]++;
+ msg->args[3]++;
+ msg->args[4]++;
+ ffa_msg_send_direct_resp(msg->destination_id,msg->source_id, SP_TEST_OK,
+ msg->args[1], msg->args[2], msg->args[3],
+ msg->args[4], msg);
+
+}
+
+static void test_communication(struct ffa_direct_msg *msg)
+{
+ struct ffa_direct_msg sp_msg = {0};
+ uint16_t dst = (uint16_t)msg->args[1];
+ ffa_result res = FFA_OK;
+
+ sp_msg.args[1] = 0x55;
+ sp_msg.args[2] = 0xAA;
+ sp_msg.args[3] = 0xBB;
+ sp_msg.args[4] = 0xCC;
+ res = ffa_msg_send_direct_req(msg->destination_id, dst, EP_TEST_SP_INCREASE,
+ 0x55, 0xAA, 0xBB, 0xCC, &sp_msg);
+
+ if (res != FFA_OK) {
+ EMSG("error % in %s:%d"PRId32, res, __FILE__, __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (sp_msg.args[1] == 0x56 && sp_msg.args[2] == 0xAB &&
+ sp_msg.args[3] == 0xBC &&sp_msg.args[4] == 0xCD) {
+ return_ok(msg);
+ } else {
+ DMSG("Failed SP communication %x %x %x %x",sp_msg.args[1],
+ sp_msg.args[2], sp_msg.args[3], sp_msg.args[4]);
+
+ return_error(ERR_SP_COMMUNICATION, msg);
+ }
+}
+
+static void test_internal_sp(struct ffa_direct_msg *msg)
+{
+ enum errors err = ERR_OK;
+ uint16_t id = 0;
+
+ if (test_ffa_version()) {
+ if (!test_ffa_id_get(&id))
+ err = ERR_ID_GET;
+
+ if (!err && !test_ffa_features())
+ err = ERR_VERSION;
+
+ if (!err && !test_ffa_rxtx_unmap(id))
+ err = ERR_RXTX_UNMAP;
+
+ if (!err && !test_ffa_rxtx_map())
+ err = ERR_RXTX_MAP;
+
+ if (!err && !test_ffa_partition_info_get())
+ err = ERR_PARTITION;
+
+ } else {
+ err = ERR_VERSION;
+ }
+
+ if (err != ERR_OK) {
+ DMSG("Failed at SP test %x", err);
+ return_error((uint32_t)err, msg);
+ }
+
+ return_ok(msg);
+}
+
+static void set_rxtx_buf(struct ffa_mem_transaction_buffer *t_buf,
+ struct ffa_mem_transaction_buffer *r_buf)
+{
+ if (t_buf) {
+ t_buf->buffer = (void*)tx_buffer;
+ t_buf->length = 4096;
+ t_buf->used = false;
+ }
+ if (r_buf) {
+ r_buf->buffer = (void*)rx_buffer;
+ r_buf->length = 4096;
+ r_buf->used = false;
+ }
+}
+
+static void test_mem_retrieve(struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor descriptor = {0};
+ struct sp_memory_region regions[1] = {0};
+ struct sp_memory_access_descriptor acc_desc = {0};
+ uint64_t handle = 0;
+ uint32_t out_region_count = 1;
+ uint16_t own_id = 0;
+
+ ffa_id_get(&own_id);
+
+ handle = (uint64_t)msg->args[1] | (((uint64_t)msg->args[2]) << 32);
+ descriptor.tag = 0;
+ descriptor.sender_id = msg->args[3] & 0xffff;
+ acc_desc.receiver_id = own_id;
+ acc_desc.data_access = sp_data_access_read_write;
+ res = sp_memory_retrieve(&descriptor, &acc_desc, regions, 1,
+ &out_region_count, handle);
+
+ if (res) {
+ DMSG("Failed retrieving me share");
+ return_error((uint32_t)ERR_MEM_RETRIEVE, msg);
+ return;
+ }
+
+ shared_buffer = regions[0].address;
+ shared_buffer_size = regions[0].page_count * 4096;
+
+ return_ok(msg);
+}
+
+static void test_mem_relinquish(struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor descriptor = {0};
+ uint64_t handle = 0;
+ uint16_t endpoint_id = 0;
+ struct sp_memory_transaction_flags flags = {
+ .zero_memory = false,
+ .operation_time_slicing = false,
+ };
+
+ if (msg->args[3] == 1)
+ flags.zero_memory = true;
+
+ ffa_id_get(&endpoint_id);
+ handle = (uint64_t)msg->args[1] | (((uint64_t)msg->args[2]) << 32);
+ descriptor.tag = 0;
+
+ res = sp_memory_relinquish(handle, &endpoint_id, 1, &flags);
+ if (res) {
+ DMSG("Failed to relinquish share");
+ return_error((uint32_t)ERR_MEM_RELINQUISH, msg);
+ }
+
+ return_ok(msg);
+}
+
+static void test_mem_sharing(uint16_t service_ep_id, struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id;
+ struct sp_memory_access_descriptor acc_desc = { };
+
+ my_buf[0] = 0xa;
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_not_executable;
+ acc_desc.receiver_id = service_ep_id;
+
+ res = sp_memory_share(&desc, &acc_desc, 1, ®ion, 1, &handle);
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, service_ep_id,
+ EP_RETRIEVE, handle & 0xffffffff,
+ handle >> 32, own_id, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, service_ep_id,
+ EP_TRY_W_ACCESS, 0,
+ 0, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, service_ep_id,
+ EP_RELINQUISH, handle & 0xffffffff,
+ handle >> 32, 0, 0, msg);
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_mem_reclaim(handle, 0);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+
+ return_ok(msg);
+}
+
+static void test_mem_multi_sharing(struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id = 0;
+ struct sp_memory_access_descriptor acc_desc[2] = { };
+ uint32_t err = 0;
+ uint16_t endpoint2 = msg->args[1];
+ uint16_t endpoint3 = msg->args[2];
+
+ my_buf[0] = 0xa;
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc[0].data_access = sp_data_access_read_write;
+ acc_desc[0].instruction_access = sp_instruction_access_not_executable;
+ acc_desc[0].receiver_id = endpoint2;
+
+ acc_desc[1].data_access = sp_data_access_read_write;
+ acc_desc[1].instruction_access = sp_instruction_access_not_executable;
+ acc_desc[1].receiver_id = endpoint3;
+
+ res = sp_memory_share(&desc, acc_desc, 2, ®ion, 1, &handle);
+ if (res != FFA_OK) {
+ EMSG("ffa_memory_share(): error %"PRId32, res);
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+ /* test SP2*/
+ res = ffa_msg_send_direct_req(own_id, endpoint2,
+ EP_RETRIEVE, handle & 0xffffffff,
+ handle >> 32, own_id, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, endpoint2,
+ EP_TRY_W_ACCESS, 0,
+ 0, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (my_buf[0] != 0xff) {
+ EMSG("SP2 didn't change the value of the buffer");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, endpoint2,
+ EP_RELINQUISH, handle & 0xffffffff,
+ handle >> 32, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+ my_buf[0] = 0xa;
+ /* test SP3*/
+ res = ffa_msg_send_direct_req(own_id, endpoint3,
+ EP_RETRIEVE, handle & 0xffffffff,
+ handle >> 32, own_id, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, endpoint3,
+ EP_TRY_W_ACCESS, 0,
+ 0, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (my_buf[0] != 0xff) {
+ EMSG("SP3 didn't change the value of the buffer");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ if (ffa_mem_reclaim(handle, 0) == FFA_OK) {
+ EMSG("SP3 didn't relinquish memory yet!");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ res = ffa_msg_send_direct_req(own_id, endpoint3,
+ EP_RELINQUISH, handle & 0xffffffff,
+ handle >> 32, 0, 0, msg);
+
+ if (res != FFA_OK) {
+ EMSG("test_mem_multi_sharing(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ if (ffa_mem_reclaim(handle, 0) != FFA_OK) {
+ EMSG("All memory should have been relinquished!");
+ err = (uint32_t)ERR_SP_SHARE;
+ goto err;
+ }
+
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_ok(msg);
+ return;
+err:
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_error(err, msg);
+}
+
+static void test_mem_sharing_inccorrect_access(uint16_t service_ep_id,
+ struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id = 0;
+ struct sp_memory_access_descriptor acc_desc = { };
+
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_executable;
+ acc_desc.receiver_id = service_ep_id;
+
+ res = sp_memory_share(&desc, &acc_desc, 1, ®ion, 1, &handle);
+ if (res == FFA_OK) {
+ EMSG("ffa_memory_share(): error %"PRId32, res);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_ok(msg);
+}
+
+static void test_mem_sharing_exc(uint16_t service_ep_id,
+ struct ffa_direct_msg *msg)
+{
+ ffa_result res = FFA_OK;
+ struct sp_memory_descriptor desc = { 0 };
+ struct sp_memory_region region = { 0 };
+ uint64_t handle = 0;
+ uint64_t handle2 = 0;
+ struct ffa_mem_transaction_buffer t_buf = {0};
+ uint16_t own_id = 0;
+ uint16_t src_id = msg->source_id = 0;
+ struct sp_memory_access_descriptor acc_desc = { };
+ uint32_t err = 0;
+
+ set_rxtx_buf(&t_buf, NULL);
+ ffa_id_get(&own_id);
+
+ region.address = (void*) my_buf;
+ region.page_count = 1;
+ desc.sender_id = own_id;
+ desc.memory_type = sp_memory_type_normal_memory;
+ desc.mem_region_attr.normal_memory.cacheability =
+ sp_cacheability_write_back;
+
+ desc.mem_region_attr.normal_memory.shareability =
+ sp_shareability_inner_shareable;
+
+ acc_desc.data_access = sp_data_access_read_write;
+ acc_desc.instruction_access = sp_instruction_access_not_executable;
+ acc_desc.receiver_id = service_ep_id;
+
+ res = sp_memory_share(&desc, &acc_desc, 1, ®ion, 1, &handle);
+ if (res != FFA_OK) {
+ EMSG("test_mem_sharing_exc(): error %"PRId32, res);
+ err = (uint32_t)ERR_SP_SHARE_EXC;
+ goto err;
+ }
+
+ /*
+ * Try it again, it should fail as we don't have acclusive access
+ * anymore
+ */
+ res = sp_memory_share(&desc, &acc_desc, 1, ®ion, 1, &handle2);
+ if (res == FFA_OK) {
+ EMSG("test_mem_sharing_exc(): error %"PRId32, res);
+ err = (uint32_t)ERR_SP_SHARE_EXC;
+ goto err;
+ }
+
+ res = ffa_mem_reclaim(handle, 0);
+
+ if (res != FFA_OK) {
+ EMSG("ffa_memory_share(): error % in %s:%d"PRId32, res,
+ __FILE__,
+ __LINE__);
+ return_error((uint32_t)ERR_SP_SHARE, msg);
+ return;
+ }
+
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_ok(msg);
+ return;
+err:
+ msg->destination_id = own_id;
+ msg->source_id = src_id;
+ return_error(err, msg);
+}
+
+void __noreturn sp_main(struct ffa_init_info *init_info) {
+ struct ffa_direct_msg msg = {0};
+ uint16_t own_id = 0;
+
+ /* Boot phase */
+ if (sp_discovery_own_id_get(&own_id) != SP_RESULT_OK) {
+ EMSG("Couldn't get own_id!!");
+ }
+
+ test_ffa_rxtx_map();
+ /* End of boot phase */
+ ffa_msg_wait(&msg);
+
+ while (1) {
+ enum sp_tests test_case = (enum sp_tests)msg.args[0];
+
+ DMSG("SP:%x Starting test %s", own_id, sp_test_str[test_case]);
+ switch (test_case) {
+ case EP_TEST_SP:
+ test_internal_sp(&msg);
+ break;
+ case EP_TEST_SP_COMMUNICATION:
+ test_communication(&msg);
+ break;
+ case EP_TEST_SP_INCREASE:
+ test_increase(&msg);
+ break;
+ case EP_TRY_R_ACCESS:
+ test_read_access();
+ return_ok(&msg);
+ break;
+ case EP_TRY_W_ACCESS:
+ test_write_access();
+ return_ok(&msg);
+ break;
+ case EP_RETRIEVE:
+ test_mem_retrieve(&msg);
+ break;
+ case EP_RELINQUISH:
+ test_mem_relinquish(&msg);
+ break;
+ case EP_SP_MEM_SHARING:
+ test_mem_sharing((uint16_t)msg.args[1], &msg);
+ break;
+ case EP_SP_MEM_SHARING_MULTI:
+ test_mem_multi_sharing(&msg);
+ break;
+ case EP_SP_MEM_SHARING_EXC:
+ test_mem_sharing_exc((uint16_t)msg.args[1], &msg);
+ break;
+ case EP_SP_MEM_INCORRECT_ACCESS:
+ test_mem_sharing_inccorrect_access(
+ (uint16_t)msg.args[1], &msg);
+ break;
+ case EP_SP_NOP:
+ return_ok(&msg);
+ break;
+
+ default:
+ return_error((uint32_t)ERR_TEST_NOT_FOUND, &msg);
+ break;
+ }
+ }
+}
+
+void sp_interrupt_handler(uint32_t interrupt_id)
+{
+ (void)interrupt_id;
+ DMSG("Got interrupt %x", interrupt_id);
+}
diff --git a/components/service/spm_test/spm_test.cmake b/components/service/spm_test/spm_test.cmake
new file mode 100644
index 0000000..484892a
--- /dev/null
+++ b/components/service/spm_test/spm_test.cmake
@@ -0,0 +1,102 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+#-------------------------------------------------------------------------------
+# The CMakeLists.txt for building the spm-test sp deployment for opteesp
+#
+# Used for building the SPs used in the spm test. The SP can be build twice
+# , to be able to test inter SPs communication. This is done by passing the
+# -DSP_NUMBER=1 parameter.
+#-------------------------------------------------------------------------------
+target_include_directories(spm-test${SP_NUMBER} PRIVATE "${TOP_LEVEL_INCLUDE_DIRS}")
+
+include(${TS_ROOT}/tools/cmake/common/TargetCompileDefinitions.cmake)
+set_target_uuids(
+ SP_UUID ${SP_UUID_CANON}
+ SP_NAME "spm-test${SP_NUMBER}"
+)
+set(SP_HEAP_SIZE "32 * 1024" CACHE STRING "SP heap size in bytes")
+set(TRACE_PREFIX "SPM-TEST${SP_NUMBER}" CACHE STRING "Trace prefix")
+
+#-------------------------------------------------------------------------------
+# Extend with components that are common across all deployments of
+# spm-test
+#
+#-------------------------------------------------------------------------------
+target_include_directories(spm-test${SP_NUMBER} PRIVATE
+ ${TS_ROOT}
+ ${TS_ROOT}/components
+)
+
+#-------------------------------------------------------------------------------
+# Set target platform to provide drivers needed by the deployment
+#
+#-------------------------------------------------------------------------------
+add_platform(TARGET spm-test${SP_NUMBER})
+
+#################################################################
+
+target_compile_definitions(spm-test${SP_NUMBER} PRIVATE
+ ARM64=1
+)
+
+target_include_directories(spm-test${SP_NUMBER} PRIVATE
+ ${TS_ROOT}/components/service/spm_test
+)
+
+#-------------------------------------------------------------------------------
+# Deployment specific source files
+#-------------------------------------------------------------------------------
+target_sources(spm-test${SP_NUMBER} PRIVATE
+ ${TS_ROOT}/components/service/spm_test/sp.c
+)
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
+ target_compile_options(spm-test${SP_NUMBER} PRIVATE
+ -fdiagnostics-show-option
+ -gdwarf-2
+ -mstrict-align
+ -O0
+ $<$<COMPILE_LANGUAGE:C>:-std=c99>
+ $<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>
+ )
+
+ # Options for GCC that control linking
+ target_link_options(spm-test${SP_NUMBER} PRIVATE
+ -zmax-page-size=4096
+ )
+ # Options directly for LD, these are not understood by GCC
+ target_link_options(spm-test${SP_NUMBER} PRIVATE
+ -Wl,--as-needed
+ -Wl,--sort-section=alignment
+ # -Wl,--dynamic-list ${CMAKE_CURRENT_LIST_DIR}/dyn_list
+ )
+endif()
+
+compiler_generate_stripped_elf(TARGET spm-test${SP_NUMBER} NAME "${SP_UUID_CANON}.stripped.elf" RES STRIPPED_ELF)
+
+######################################## install
+if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+ set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "location to install build output to." FORCE)
+endif()
+
+set_target_properties(spm-test${SP_NUMBER} PROPERTIES OUTPUT_NAME "spm-test${SP_NUMBER}-${SP_UUID_CANON}.elf" )
+
+install(TARGETS spm-test${SP_NUMBER}
+ PUBLIC_HEADER DESTINATION ${TS_ENV}/include
+ RUNTIME DESTINATION ${TS_ENV}/bin
+ )
+install(FILES ${STRIPPED_ELF} DESTINATION ${TS_ENV}/bin)
+
+
+include(${TS_ROOT}/tools/cmake/common/ExportSp.cmake)
+export_sp(
+ SP_UUID_CANON ${SP_UUID_CANON}
+ SP_UUID_LE ${SP_UUID_LE}
+ SP_NAME "spm-test${SP_NUMBER}"
+ MK_IN ${TS_ROOT}/environments/opteesp/sp.mk.in
+ DTS_IN ${TS_ROOT}/deployments/spm-test${SP_NUMBER}/opteesp/default_spm_test${SP_NUMBER}.dts.in
+ JSON_IN ${TS_ROOT}/environments/opteesp/sp_pkg.json.in
+)
diff --git a/deployments/spm-test1/opteesp/CMakeLists.txt b/deployments/spm-test1/opteesp/CMakeLists.txt
new file mode 100644
index 0000000..7a2d614
--- /dev/null
+++ b/deployments/spm-test1/opteesp/CMakeLists.txt
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test1)
+
+set(SP_UUID_CANON "5c9edbc3-7b3a-4367-9f83-7c191ae86a37")
+set(SP_NUMBER 1)
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "environments/opteesp"
+)
+
diff --git a/deployments/spm-test1/opteesp/default_spm_test1.dts.in b/deployments/spm-test1/opteesp/default_spm_test1.dts.in
new file mode 100644
index 0000000..88311ec
--- /dev/null
+++ b/deployments/spm-test1/opteesp/default_spm_test1.dts.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP1";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ legacy-elf-format = <1>;
+ run-time-model = <1>; /* Run to completion */
+};
diff --git a/deployments/spm-test2/opteesp/CMakeLists.txt b/deployments/spm-test2/opteesp/CMakeLists.txt
new file mode 100644
index 0000000..a3c3408
--- /dev/null
+++ b/deployments/spm-test2/opteesp/CMakeLists.txt
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test2)
+
+set(SP_UUID_CANON "7817164c-c40c-4d1a-867a-9bb2278cf41a")
+set(SP_NUMBER 2)
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "environments/opteesp"
+)
diff --git a/deployments/spm-test2/opteesp/default_spm_test2.dts.in b/deployments/spm-test2/opteesp/default_spm_test2.dts.in
new file mode 100644
index 0000000..94073bd
--- /dev/null
+++ b/deployments/spm-test2/opteesp/default_spm_test2.dts.in
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP2";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ legacy-elf-format = <1>;
+ run-time-model = <1>; /* Run to completion */
+};
diff --git a/deployments/spm-test3/opteesp/CMakeLists.txt b/deployments/spm-test3/opteesp/CMakeLists.txt
new file mode 100644
index 0000000..f756bb7
--- /dev/null
+++ b/deployments/spm-test3/opteesp/CMakeLists.txt
@@ -0,0 +1,31 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
+set(TS_PLATFORM "arm/fvp/fvp_base_revc-2xaemv8a" CACHE STRING "Target platform location.")
+include(../../deployment.cmake REQUIRED)
+include(${TS_ROOT}/environments/opteesp/env.cmake)
+
+project(trusted-services LANGUAGES C ASM)
+add_executable(spm-test3)
+
+set(SP_UUID_CANON "23eb0100-e32a-4497-9052-2f11e584afa6")
+set(SP_NUMBER 3)
+include(${TS_ROOT}/components/service/spm_test/spm_test.cmake)
+#-------------------------------------------------------------------------------
+# Components that are spm-test specific to deployment in the opteesp
+# environment.
+#-------------------------------------------------------------------------------
+add_components(TARGET "spm-test${SP_NUMBER}"
+ BASE_DIR ${TS_ROOT}
+ COMPONENTS
+ "components/common/fdt"
+ "components/common/trace"
+ "components/common/utils"
+ "components/config/loader/sp"
+ "components/messaging/ffa/libsp"
+ "environments/opteesp"
+)
diff --git a/deployments/spm-test3/opteesp/default_spm_test3.dts.in b/deployments/spm-test3/opteesp/default_spm_test3.dts.in
new file mode 100644
index 0000000..58b2251
--- /dev/null
+++ b/deployments/spm-test3/opteesp/default_spm_test3.dts.in
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+@DTS_TAG@
+
+@DTS_NODE@ {
+ compatible = "arm,ffa-manifest-1.0";
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+
+ /* Properties */
+ description = "SPMC test SP3";
+ uuid = <@EXPORT_SP_UUID_DT@>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <3>; /* Direct messaging only */
+ legacy-elf-format = <1>;
+};