aboutsummaryrefslogtreecommitdiff
path: root/tftf
diff options
context:
space:
mode:
Diffstat (limited to 'tftf')
-rw-r--r--tftf/tests/runtime_services/secure_service/ffa_helpers.c255
-rw-r--r--tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c187
-rw-r--r--tftf/tests/tests-spm.mk1
-rw-r--r--tftf/tests/tests-spm.xml10
4 files changed, 446 insertions, 7 deletions
diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
index bda47c989..8ee4ebc76 100644
--- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c
+++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c
@@ -6,14 +6,10 @@
#include <debug.h>
#include <smccc.h>
+#include <ffa_endpoints.h>
#include <ffa_helpers.h>
#include <ffa_svc.h>
-#define OPTEE_FFA_GET_API_VERSION (0)
-#define OPTEE_FFA_GET_OS_VERSION (1)
-#define OPTEE_FFA_GET_OS_VERSION_MAJOR (3)
-#define OPTEE_FFA_GET_OS_VERSION_MINOR (8)
-
/*-----------------------------------------------------------------------------
* FFA_RUN
*
@@ -86,7 +82,7 @@ smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id,
message, 0, 0, 0, 0);
}
-static smc_ret_values __ffa_msg_send_direct_req64_5(uint32_t source_id,
+smc_ret_values ffa_msg_send_direct_req64_5args(uint32_t source_id,
uint32_t dest_id,
uint64_t arg0,
uint64_t arg1,
@@ -108,7 +104,7 @@ static smc_ret_values __ffa_msg_send_direct_req64_5(uint32_t source_id,
smc_ret_values ffa_msg_send_direct_req64(uint32_t source_id, uint32_t dest_id,
uint64_t message)
{
- return __ffa_msg_send_direct_req64_5(source_id, dest_id,
+ return ffa_msg_send_direct_req64_5args(source_id, dest_id,
message, 0, 0, 0, 0);
}
@@ -155,6 +151,165 @@ bool check_spmc_execution_level(void)
return (is_optee_spmc_criteria == 2U);
}
+/**
+ * Initialises the header of the given `ffa_memory_region`, not including the
+ * composite memory region offset.
+ */
+static void ffa_memory_region_init_header(
+ struct ffa_memory_region *memory_region, ffa_vm_id_t sender,
+ ffa_memory_attributes_t attributes, ffa_memory_region_flags_t flags,
+ ffa_memory_handle_t handle, uint32_t tag, ffa_vm_id_t receiver,
+ ffa_memory_access_permissions_t permissions)
+{
+ memory_region->sender = sender;
+ memory_region->attributes = attributes;
+ memory_region->reserved_0 = 0;
+ memory_region->flags = flags;
+ memory_region->handle = handle;
+ memory_region->tag = tag;
+ memory_region->reserved_1 = 0;
+ memory_region->receiver_count = 1;
+ memory_region->receivers[0].receiver_permissions.receiver = receiver;
+ memory_region->receivers[0].receiver_permissions.permissions =
+ permissions;
+ memory_region->receivers[0].receiver_permissions.flags = 0;
+ memory_region->receivers[0].reserved_0 = 0;
+}
+
+/**
+ * Initialises the given `ffa_memory_region` and copies as many as possible of
+ * the given constituents to it.
+ *
+ * Returns the number of constituents remaining which wouldn't fit, and (via
+ * return parameters) the size in bytes of the first fragment of data copied to
+ * `memory_region` (attributes, constituents and memory region header size), and
+ * the total size of the memory sharing message including all constituents.
+ */
+uint32_t ffa_memory_region_init(
+ struct ffa_memory_region *memory_region, size_t memory_region_max_size,
+ ffa_vm_id_t sender, ffa_vm_id_t receiver,
+ const struct ffa_memory_region_constituent constituents[],
+ uint32_t constituent_count, uint32_t tag,
+ ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
+ enum ffa_instruction_access instruction_access,
+ enum ffa_memory_type type, enum ffa_memory_cacheability cacheability,
+ enum ffa_memory_shareability shareability, uint32_t *total_length,
+ uint32_t *fragment_length)
+{
+ ffa_memory_access_permissions_t permissions = 0;
+ ffa_memory_attributes_t attributes = 0;
+ struct ffa_composite_memory_region *composite_memory_region;
+ uint32_t fragment_max_constituents;
+ uint32_t count_to_copy;
+ uint32_t i;
+ uint32_t constituents_offset;
+
+ /* Set memory region's permissions. */
+ ffa_set_data_access_attr(&permissions, data_access);
+ ffa_set_instruction_access_attr(&permissions, instruction_access);
+
+ /* Set memory region's page attributes. */
+ ffa_set_memory_type_attr(&attributes, type);
+ ffa_set_memory_cacheability_attr(&attributes, cacheability);
+ ffa_set_memory_shareability_attr(&attributes, shareability);
+
+ ffa_memory_region_init_header(memory_region, sender, attributes, flags,
+ 0, tag, receiver, permissions);
+ /*
+ * Note that `sizeof(struct_ffa_memory_region)` and `sizeof(struct
+ * ffa_memory_access)` must both be multiples of 16 (as verified by the
+ * asserts in `ffa_memory.c`, so it is guaranteed that the offset we
+ * calculate here is aligned to a 64-bit boundary and so 64-bit values
+ * can be copied without alignment faults.
+ */
+ memory_region->receivers[0].composite_memory_region_offset =
+ sizeof(struct ffa_memory_region) +
+ memory_region->receiver_count *
+ sizeof(struct ffa_memory_access);
+
+ composite_memory_region =
+ ffa_memory_region_get_composite(memory_region, 0);
+ composite_memory_region->page_count = 0;
+ composite_memory_region->constituent_count = constituent_count;
+ composite_memory_region->reserved_0 = 0;
+
+ constituents_offset =
+ memory_region->receivers[0].composite_memory_region_offset +
+ sizeof(struct ffa_composite_memory_region);
+ fragment_max_constituents =
+ (memory_region_max_size - constituents_offset) /
+ sizeof(struct ffa_memory_region_constituent);
+
+ count_to_copy = constituent_count;
+ if (count_to_copy > fragment_max_constituents) {
+ count_to_copy = fragment_max_constituents;
+ }
+
+ for (i = 0; i < constituent_count; ++i) {
+ if (i < count_to_copy) {
+ composite_memory_region->constituents[i] =
+ constituents[i];
+ }
+ composite_memory_region->page_count +=
+ constituents[i].page_count;
+ }
+
+ if (total_length != NULL) {
+ *total_length =
+ constituents_offset +
+ composite_memory_region->constituent_count *
+ sizeof(struct ffa_memory_region_constituent);
+ }
+ if (fragment_length != NULL) {
+ *fragment_length =
+ constituents_offset +
+ count_to_copy *
+ sizeof(struct ffa_memory_region_constituent);
+ }
+
+ return composite_memory_region->constituent_count - count_to_copy;
+}
+
+/**
+ * Initialises the given `ffa_memory_region` to be used for an
+ * `FFA_MEM_RETRIEVE_REQ` by the receiver of a memory transaction.
+ *
+ * Returns the size of the message written.
+ */
+uint32_t ffa_memory_retrieve_request_init(
+ struct ffa_memory_region *memory_region, ffa_memory_handle_t handle,
+ ffa_vm_id_t sender, ffa_vm_id_t receiver, uint32_t tag,
+ ffa_memory_region_flags_t flags, enum ffa_data_access data_access,
+ enum ffa_instruction_access instruction_access,
+ enum ffa_memory_type type, enum ffa_memory_cacheability cacheability,
+ enum ffa_memory_shareability shareability)
+{
+ ffa_memory_access_permissions_t permissions = 0;
+ ffa_memory_attributes_t attributes = 0;
+
+ /* Set memory region's permissions. */
+ ffa_set_data_access_attr(&permissions, data_access);
+ ffa_set_instruction_access_attr(&permissions, instruction_access);
+
+ /* Set memory region's page attributes. */
+ ffa_set_memory_type_attr(&attributes, type);
+ ffa_set_memory_cacheability_attr(&attributes, cacheability);
+ ffa_set_memory_shareability_attr(&attributes, shareability);
+
+ ffa_memory_region_init_header(memory_region, sender, attributes, flags,
+ handle, tag, receiver, permissions);
+ /*
+ * Offset 0 in this case means that the hypervisor should allocate the
+ * address ranges. This is the only configuration supported by Hafnium,
+ * as it enforces 1:1 mappings in the stage 2 page tables.
+ */
+ memory_region->receivers[0].composite_memory_region_offset = 0;
+ memory_region->receivers[0].reserved_0 = 0;
+
+ return sizeof(struct ffa_memory_region) +
+ memory_region->receiver_count * sizeof(struct ffa_memory_access);
+}
+
/*
* FFA Version ABI helper.
* Version fields:
@@ -260,3 +415,89 @@ smc_ret_values ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
return tftf_smc(&args);
}
+
+/* Donate memory to another partition */
+smc_ret_values ffa_mem_donate(uint32_t descriptor_length,
+ uint32_t fragment_length)
+{
+ smc_args args = {
+ .fid = FFA_MEM_DONATE_SMC32,
+ .arg1 = descriptor_length,
+ .arg2 = fragment_length,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ
+ };
+
+ return tftf_smc(&args);
+}
+
+/* Lend memory to another partition */
+smc_ret_values ffa_mem_lend(uint32_t descriptor_length,
+ uint32_t fragment_length)
+{
+ smc_args args = {
+ .fid = FFA_MEM_LEND_SMC32,
+ .arg1 = descriptor_length,
+ .arg2 = fragment_length,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ
+ };
+
+ return tftf_smc(&args);
+}
+
+/* Share memory with another partition */
+smc_ret_values ffa_mem_share(uint32_t descriptor_length,
+ uint32_t fragment_length)
+{
+ smc_args args = {
+ .fid = FFA_MEM_SHARE_SMC32,
+ .arg1 = descriptor_length,
+ .arg2 = fragment_length,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ
+ };
+
+ return tftf_smc(&args);
+}
+
+/* Retrieve memory shared by another partition */
+smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length,
+ uint32_t fragment_length)
+{
+ smc_args args = {
+ .fid = FFA_MEM_RETRIEVE_REQ_SMC32,
+ .arg1 = descriptor_length,
+ .arg2 = fragment_length,
+ .arg3 = FFA_PARAM_MBZ,
+ .arg4 = FFA_PARAM_MBZ,
+ .arg5 = FFA_PARAM_MBZ,
+ .arg6 = FFA_PARAM_MBZ,
+ .arg7 = FFA_PARAM_MBZ
+ };
+
+ return tftf_smc(&args);
+}
+
+/* Relinquish access to memory region */
+smc_ret_values ffa_mem_relinquish(void)
+{
+ smc_args args = {
+ .fid = FFA_MEM_RELINQUISH,
+ };
+
+ return tftf_smc(&args);
+}
+
+/* Reclaim exclusive access to owned memory region */
+smc_ret_values ffa_mem_reclaim(uint64_t handle, uint32_t flags)
+{
+ smc_args args = {
+ .fid = FFA_MEM_RECLAIM,
+ .arg1 = (uint32_t) handle,
+ .arg2 = (uint32_t) (handle >> 32),
+ .arg3 = flags
+ };
+
+ return tftf_smc(&args);
+}
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
new file mode 100644
index 000000000..0ae8a8d30
--- /dev/null
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cactus_test_cmds.h>
+#include <debug.h>
+#include <ffa_endpoints.h>
+#include <ffa_helpers.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <xlat_tables_defs.h>
+
+#define MAILBOX_SIZE PAGE_SIZE
+
+#define SENDER HYP_ID
+#define RECEIVER SP_ID(1)
+
+/* Memory section to be sent over mem management ABIs */
+static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE];
+
+static __aligned(PAGE_SIZE) uint8_t send_page[PAGE_SIZE];
+static __aligned(PAGE_SIZE) uint8_t recv_page[PAGE_SIZE];
+
+/* Within the same test the RXTX Buffers only need to be shared once */
+static bool rxtx_mapped;
+
+static struct mailbox_buffers mb = {
+ .recv = (void *)recv_page,
+ .send = (void *)send_page,
+ };
+
+static test_result_t test_memory_send_sp(uint32_t mem_func)
+{
+ smc_ret_values ret;
+ uint32_t remaining_constituent_count;
+ uint32_t total_length;
+ uint32_t fragment_length;
+ uint32_t sent_length;
+ ffa_memory_handle_t handle;
+ uint32_t *ptr;
+
+ /**********************************************************************
+ * Verify that FFA is there and that it has the correct version.
+ **********************************************************************/
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0);
+
+ /**********************************************************************
+ * If OPTEE is SPMC skip this test.
+ **********************************************************************/
+ if (check_spmc_execution_level()) {
+ VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ if (!rxtx_mapped) {
+ ret = ffa_rxtx_map((uintptr_t)mb.send, (uintptr_t)mb.recv, 1);
+
+ if (ret.ret0 != FFA_SUCCESS_SMC32) {
+ ERROR("ffa_rxtx_map failed (%lx)\n", ret.ret0);
+ return TEST_RESULT_FAIL;
+ }
+ rxtx_mapped = true;
+ }
+
+ /**********************************************************************
+ * Verify that cactus primary SP is deployed in the system.
+ **********************************************************************/
+ SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(mb, PRIMARY_UUID);
+
+ struct ffa_memory_region_constituent constituents[] = {
+ {(void *)share_page, 1, 0}
+ };
+
+ const uint32_t constituents_count = sizeof(constituents) /
+ sizeof(struct ffa_memory_region_constituent);
+
+ enum ffa_data_access data_access = (mem_func == FFA_MEM_DONATE_SMC32) ?
+ FFA_DATA_ACCESS_NOT_SPECIFIED :
+ FFA_DATA_ACCESS_RW;
+
+ /*
+ * TODO: Revise shareability attribute in function call
+ * below.
+ * https://lists.trustedfirmware.org/pipermail/hafnium/2020-June/000023.html
+ */
+ remaining_constituent_count = ffa_memory_region_init(
+ mb.send, MAILBOX_SIZE, SENDER, RECEIVER, constituents,
+ constituents_count, 0, 0,
+ data_access,
+ FFA_INSTRUCTION_ACCESS_NOT_SPECIFIED,
+ FFA_MEMORY_NORMAL_MEM,
+ FFA_MEMORY_CACHE_WRITE_BACK,
+ FFA_MEMORY_OUTER_SHAREABLE,
+ &total_length,
+ &fragment_length
+ );
+
+ switch (mem_func) {
+ case FFA_MEM_SHARE_SMC32:
+ ret = ffa_mem_share(total_length, fragment_length);
+ break;
+ case FFA_MEM_LEND_SMC32:
+ ret = ffa_mem_lend(total_length, fragment_length);
+ break;
+ case FFA_MEM_DONATE_SMC32:
+ ret = ffa_mem_donate(total_length, fragment_length);
+ break;
+ default:
+ NOTICE("TFTF - Invalid func id!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ sent_length = fragment_length;
+
+ if (ret.ret0 != FFA_SUCCESS_SMC32) {
+ tftf_testcase_printf("Failed to send memory to SP %x.\n",
+ RECEIVER);
+ return TEST_RESULT_FAIL;
+ }
+
+ if (sent_length != total_length) {
+ tftf_testcase_printf("Sent and Total lengths must be equal!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ if (remaining_constituent_count != 0) {
+ tftf_testcase_printf("Remaining constituent should be 0\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ handle = ffa_mem_success_handle(ret);
+
+ VERBOSE("TFTF - Handle: %llx\nTFTF - Address: %p\n",
+ handle, constituents[0].address);
+
+ ptr = (uint32_t *)constituents[0].address;
+
+ ret = CACTUS_MEM_SEND_CMD(SENDER, RECEIVER, mem_func, handle);
+
+ if (ret.ret0 != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
+ ERROR("Failed to send message. error: %lx\n",
+ ret.ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ if (CACTUS_GET_RESPONSE(ret) != CACTUS_SUCCESS) {
+ tftf_testcase_printf("Failed memory send operation!\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ /*
+ * Print 5 words from the memory region to validate SP wrote to the
+ * memory region.
+ */
+ VERBOSE("TFTF - Memory contents after SP use:\n");
+ for (unsigned int i = 0U; i < 5U; i++)
+ VERBOSE(" %u: %x\n", i, ptr[i]);
+
+ /* To make the compiler happy in case it is not a verbose build */
+ if (LOG_LEVEL < LOG_LEVEL_VERBOSE)
+ (void)ptr;
+
+ if (mem_func != FFA_MEM_DONATE_SMC32 &&
+ ffa_mem_reclaim(handle, 0).ret0 == FFA_ERROR) {
+ tftf_testcase_printf("Couldn't reclaim memory\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+test_result_t test_mem_share_sp(void)
+{
+ return test_memory_send_sp(FFA_MEM_SHARE_SMC32);
+}
+
+test_result_t test_mem_lend_sp(void)
+{
+ return test_memory_send_sp(FFA_MEM_LEND_SMC32);
+}
+
+test_result_t test_mem_donate_sp(void)
+{
+ return test_memory_send_sp(FFA_MEM_DONATE_SMC32);
+}
diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk
index bef373fbb..ee339b5a4 100644
--- a/tftf/tests/tests-spm.mk
+++ b/tftf/tests/tests-spm.mk
@@ -10,4 +10,5 @@ TESTS_SOURCES += \
test_ffa_direct_messaging.c \
test_ffa_version.c \
test_ffa_features.c \
+ test_ffa_memory_sharing.c \
)
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index e2f29bfe1..85001f22a 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -30,6 +30,16 @@
</testsuite>
+ <testsuite name="FF-A Memory Sharing"
+ description="Test FF-A Memory Sharing ABIs" >
+ <testcase name="Lend Memory to Secure World"
+ function="test_mem_lend_sp" />
+ <testcase name="Share Memory with Secure World"
+ function="test_mem_share_sp" />
+ <testcase name="Donate Memory to Secure World"
+ function="test_mem_donate_sp"/>
+ </testsuite>
+
<testsuite name="PSA FF-A features"
description="Test FFA_FEATURES ABI" >
<testcase name="Test FFA_FEATURES"