diff options
Diffstat (limited to 'tftf')
-rw-r--r-- | tftf/tests/runtime_services/secure_service/ffa_helpers.c | 255 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c | 187 | ||||
-rw-r--r-- | tftf/tests/tests-spm.mk | 1 | ||||
-rw-r--r-- | tftf/tests/tests-spm.xml | 10 |
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" |