diff options
author | Olivier Deprez <olivier.deprez@arm.com> | 2021-01-21 10:00:00 +0000 |
---|---|---|
committer | TrustedFirmware Code Review <review@review.trustedfirmware.org> | 2021-01-21 10:00:00 +0000 |
commit | 4904c8632c255b6ac3fb77109f807b3a11cb910b (patch) | |
tree | 86bf81fa9377e50cc9aa040c93bab7c213f525af | |
parent | 52387275bd4ab47aecaf101526e683134e0440fb (diff) | |
parent | b9085f851d37d66276e85ad05e9be1a9f4bfb99a (diff) | |
download | tf-a-tests-4904c8632c255b6ac3fb77109f807b3a11cb910b.tar.gz |
Merge changes from topic "sp_to_sp_mem_share"
* changes:
Cactus: cmd for mem share tests
TFTF: tests to request SP-to-SP memory share
cactus: test SP-to-SP memory share operations
cactus: add command to request memory sharing between SPs
TFTF: Refactor FF-A memory sharing tests
-rw-r--r-- | include/runtime_services/ffa_helpers.h | 10 | ||||
-rw-r--r-- | spm/cactus/cactus_ffa_tests.c | 6 | ||||
-rw-r--r-- | spm/cactus/cactus_main.c | 94 | ||||
-rw-r--r-- | spm/cactus/cactus_test_cmds.h | 38 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/ffa_helpers.c | 86 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c | 165 | ||||
-rw-r--r-- | tftf/tests/tests-spm.xml | 18 |
7 files changed, 316 insertions, 101 deletions
diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h index ed3302fb2..b8928d439 100644 --- a/include/runtime_services/ffa_helpers.h +++ b/include/runtime_services/ffa_helpers.h @@ -397,6 +397,16 @@ uint32_t ffa_memory_region_init( enum ffa_memory_shareability shareability, uint32_t *total_length, uint32_t *fragment_length); +ffa_memory_handle_t ffa_memory_send( + struct ffa_memory_region *memory_region, uint32_t mem_func, + uint32_t fragment_length, uint32_t total_length); + +ffa_memory_handle_t ffa_memory_init_and_send( + 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 constituents_count, uint32_t mem_func); + bool check_spmc_execution_level(void); smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id, uint32_t message); smc_ret_values ffa_msg_send_direct_req64(uint32_t source_id, uint32_t dest_id, uint64_t message); diff --git a/spm/cactus/cactus_ffa_tests.c b/spm/cactus/cactus_ffa_tests.c index 07aaacab8..5863456af 100644 --- a/spm/cactus/cactus_ffa_tests.c +++ b/spm/cactus/cactus_ffa_tests.c @@ -307,7 +307,11 @@ void ffa_memory_management_test(struct mailbox_buffers *mb, ffa_vm_id_t vm_id, m->receivers[0].receiver_permissions.permissions), FFA_DATA_ACCESS_RW); - mem_attrs = MT_RW_DATA | MT_NS | MT_EXECUTE_NEVER; + mem_attrs = MT_RW_DATA | MT_EXECUTE_NEVER; + + if (!IS_SP_ID(sender)) { + mem_attrs |= MT_NS; + } ret = mmap_add_dynamic_region( (uint64_t)composite->constituents[0].address, diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c index da7e9139f..de1e555b6 100644 --- a/spm/cactus/cactus_main.c +++ b/spm/cactus/cactus_main.c @@ -30,6 +30,9 @@ extern const char build_message[]; extern const char version_string[]; +/* Memory section to be used for memory share operations */ +static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE]; + /* * * Message loop function @@ -46,7 +49,6 @@ static void __dead2 message_loop(ffa_vm_id_t vm_id, struct mailbox_buffers *mb) ffa_vm_id_t destination; uint64_t cactus_cmd; - /* * This initial wait call is necessary to inform SPMD that * SP initialization has completed. It blocks until receiving @@ -85,12 +87,10 @@ static void __dead2 message_loop(ffa_vm_id_t vm_id, struct mailbox_buffers *mb) cactus_cmd = CACTUS_GET_CMD(ffa_ret); switch (cactus_cmd) { - case FFA_MEM_SHARE_SMC32: - case FFA_MEM_LEND_SMC32: - case FFA_MEM_DONATE_SMC32: + case CACTUS_MEM_SEND_CMD: ffa_memory_management_test( mb, vm_id, source, - CACTUS_GET_CMD(ffa_ret), + CACTUS_MEM_SEND_GET_FUNC(ffa_ret), CACTUS_MEM_SEND_GET_HANDLE(ffa_ret)); /* @@ -99,7 +99,91 @@ static void __dead2 message_loop(ffa_vm_id_t vm_id, struct mailbox_buffers *mb) */ ffa_ret = CACTUS_SUCCESS_RESP(vm_id, source); break; + case CACTUS_REQ_MEM_SEND_CMD: + { + uint32_t mem_func = + CACTUS_REQ_MEM_SEND_GET_MEM_FUNC(ffa_ret); + ffa_vm_id_t receiver = + CACTUS_REQ_MEM_SEND_GET_RECEIVER(ffa_ret); + ffa_memory_handle_t handle; + + VERBOSE("%x requested to send memory to %x (func: %x)\n", + source, receiver, mem_func); + + const struct ffa_memory_region_constituent + constituents[] = { + {(void *)share_page, 1, 0} + }; + + const uint32_t constituents_count = ( + sizeof(constituents) / + sizeof(constituents[0]) + ); + + handle = ffa_memory_init_and_send( + (struct ffa_memory_region *)mb->send, PAGE_SIZE, + vm_id, receiver, constituents, + constituents_count, mem_func); + + /* + * If returned an invalid handle, we should break the + * test. + */ + expect(handle != FFA_MEMORY_HANDLE_INVALID, true); + ffa_ret = CACTUS_MEM_SEND_CMD_SEND(vm_id, receiver, + mem_func, handle); + + if (ffa_ret.ret0 != FFA_MSG_SEND_DIRECT_RESP_SMC32) { + ERROR("Failed to send message. error: %lx\n", + ffa_ret.ret2); + ffa_ret = CACTUS_ERROR_RESP(vm_id, source); + break; + } + + /* If anything went bad on the receiver's end. */ + if (CACTUS_IS_ERROR_RESP(ffa_ret)) { + ERROR("Received error from receiver!\n"); + ffa_ret = CACTUS_ERROR_RESP(vm_id, source); + break; + } + + if (mem_func != FFA_MEM_DONATE_SMC32) { + /* + * Do a memory reclaim only if the mem_func + * regards to memory share or lend operations, + * as with a donate the owner is permanently + * given up access to the memory region. + */ + if (ffa_mem_reclaim(handle, 0) + .ret0 == FFA_ERROR) { + ERROR("Failed to reclaim memory!\n"); + ffa_ret = CACTUS_ERROR_RESP(vm_id, + source); + break; + } + + /** + * Read Content that has been written to memory + * to validate access to memory segment has been + * reestablished, and receiver made use of + * memory region. + */ + #if (LOG_LEVEL >= LOG_LEVEL_VERBOSE) + uint32_t *ptr = + (uint32_t *)constituents + ->address; + VERBOSE("Memory contents after receiver" + " SP's use:\n"); + for (unsigned int i = 0U; i < 5U; i++) + VERBOSE(" %u: %x\n", i, + ptr[i]); + #endif + } + + ffa_ret = CACTUS_SUCCESS_RESP(vm_id, source); + } + break; case CACTUS_ECHO_CMD: { uint64_t echo_val = CACTUS_ECHO_GET_VAL(ffa_ret); diff --git a/spm/cactus/cactus_test_cmds.h b/spm/cactus/cactus_test_cmds.h index 3e16e579b..7555b8b29 100644 --- a/spm/cactus/cactus_test_cmds.h +++ b/spm/cactus/cactus_test_cmds.h @@ -96,22 +96,45 @@ /** * Command to notify cactus of a memory management operation. The cmd value * should be the memory management smc function id. + * + * The id is the hex representation of the string "mem" + */ +#define CACTUS_MEM_SEND_CMD U(0x6d656d) + +#define CACTUS_MEM_SEND_CMD_SEND(source, dest, mem_func, handle) \ + CACTUS_SEND_CMD(source, dest, CACTUS_MEM_SEND_CMD, \ + mem_func, handle, 0, 0) + +#define CACTUS_MEM_SEND_GET_FUNC(smc_ret) smc_ret.ret4 + +#define CACTUS_MEM_SEND_GET_HANDLE(smc_ret) smc_ret.ret5 + +/** + * Command to request a memory management operation. The 'mem_func' argument + * identifies the operation that is to be performend, and 'receiver' is the id + * of the partition to receive the memory region. + * + * The command id is the hex representation of the string "memory". */ -#define CACTUS_MEM_SEND_CMD(source, dest, mem_func, handle) \ - CACTUS_SEND_CMD(source, dest, mem_func, handle, 0, 0, 0) +#define CACTUS_REQ_MEM_SEND_CMD U(0x6d656d6f7279) -#define CACTUS_MEM_SEND_GET_HANDLE(smc_ret) smc_ret.ret4 +#define CACTUS_REQ_MEM_SEND_SEND_CMD(source, dest, mem_func, receiver) \ + CACTUS_SEND_CMD(source, dest, CACTUS_REQ_MEM_SEND_CMD, mem_func, \ + receiver, 0, 0) + +#define CACTUS_REQ_MEM_SEND_GET_MEM_FUNC(smc_ret) smc_ret.ret4 +#define CACTUS_REQ_MEM_SEND_GET_RECEIVER(smc_ret) smc_ret.ret5 /** * Template for responses to CACTUS commands. */ -#define CACTUS_RESPONSE(source, dest, response) \ +#define CACTUS_RESPONSE(source, dest, response) \ ffa_msg_send_direct_resp(source, dest, response) -#define CACTUS_SUCCESS_RESP(source, dest) \ +#define CACTUS_SUCCESS_RESP(source, dest) \ CACTUS_RESPONSE(source, dest, CACTUS_SUCCESS) -#define CACTUS_ERROR_RESP(source, dest) \ +#define CACTUS_ERROR_RESP(source, dest) \ CACTUS_RESPONSE(source, dest, CACTUS_ERROR) #define CACTUS_GET_RESPONSE(smc_ret) smc_ret.ret3 @@ -119,4 +142,7 @@ #define CACTUS_IS_SUCCESS_RESP(smc_ret) \ (CACTUS_GET_RESPONSE(smc_ret) == CACTUS_SUCCESS) +#define CACTUS_IS_ERROR_RESP(smc_ret) \ + (CACTUS_GET_RESPONSE(smc_ret) == CACTUS_ERROR) + #endif diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c index 8ee4ebc76..1b790188a 100644 --- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c +++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c @@ -310,6 +310,92 @@ uint32_t ffa_memory_retrieve_request_init( memory_region->receiver_count * sizeof(struct ffa_memory_access); } +/** + * Helper to call memory send function whose func id is passed as a parameter. + * Returns a valid handle in case of successful operation or + * FFA_MEMORY_HANDLE_INVALID if something goes wrong. + * + * TODO: Do memory send with 'ffa_memory_region' taking multiple segments + */ +ffa_memory_handle_t ffa_memory_send( + struct ffa_memory_region *memory_region, uint32_t mem_func, + uint32_t fragment_length, uint32_t total_length) +{ + smc_ret_values ret; + ffa_vm_id_t receiver = + memory_region->receivers[0].receiver_permissions.receiver; + + if (fragment_length != total_length) { + ERROR("For now, fragment_length and total_length need to be" + " equal"); + return FFA_MEMORY_HANDLE_INVALID; + } + + 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: + ERROR("TFTF - Invalid func id %x!\n", mem_func); + return FFA_MEMORY_HANDLE_INVALID; + } + + if (ret.ret0 != FFA_SUCCESS_SMC32) { + ERROR("Failed to send memory to %x, error: %lx.\n", + receiver, ret.ret2); + return FFA_MEMORY_HANDLE_INVALID; + } + + return ffa_mem_success_handle(ret); +; +} + +/** + * Helper that initializes and sends a memory region. The memory region's + * configuration is statically defined and is implementation specific. However, + * doing it in this file for simplicity and for testing purposes. + */ +ffa_memory_handle_t ffa_memory_init_and_send( + 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 constituents_count, uint32_t mem_func) +{ + uint32_t remaining_constituent_count; + uint32_t total_length; + uint32_t fragment_length; + + enum ffa_data_access data_access = (mem_func == FFA_MEM_DONATE_SMC32) ? + FFA_DATA_ACCESS_NOT_SPECIFIED : + FFA_DATA_ACCESS_RW; + + remaining_constituent_count = ffa_memory_region_init( + memory_region, memory_region_max_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_INNER_SHAREABLE, &total_length, &fragment_length + ); + + /* + * For simplicity of the test, and at least for the time being, + * the following condition needs to be true. + */ + if (remaining_constituent_count != 0U) { + ERROR("Remaining constituent should be 0\n"); + return FFA_MEMORY_HANDLE_INVALID; + } + + return ffa_memory_send(memory_region, mem_func, fragment_length, + total_length); +} + /* * FFA Version ABI helper. * Version fields: 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 index fded19988..61f1aaa38 100644 --- a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c +++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c @@ -17,46 +17,44 @@ #define SENDER HYP_ID #define RECEIVER SP_ID(1) -/* Memory section to be sent over mem management ABIs */ +static const struct ffa_uuid expected_sp_uuids[] = { + {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID} + }; + +/* Memory section to be used for memory share operations */ static __aligned(PAGE_SIZE) uint8_t share_page[PAGE_SIZE]; +/** + * Tests that it is possible to share memory with SWd from NWd. + * After calling the respective memory send API, it will expect a reply from + * cactus SP, at which point it will reclaim access to the memory region and + * check the memory region has been used by receiver SP. + * + * Accessing memory before a memory reclaim operation should only be possible + * in the context of a memory share operation. + * According to the FF-A spec, the owner is temporarily relinquishing + * access to the memory region on a memory lend operation, and on a + * memory donate operation the access is relinquished permanently. + * SPMC is positioned in S-EL2, and doesn't control stage-1 mapping for + * EL2. Therefore, it is impossible to enforce the expected access + * policy for a donate and lend operations within the SPMC. + * Current SPMC implementation is under the assumption of trust that + * Hypervisor (sitting in EL2) would relinquish access from EL1/EL0 + * FF-A endpoint at relevant moment. + */ 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; struct mailbox_buffers mb; - const uint32_t primary_uuid[] = PRIMARY_UUID; - /********************************************************************** - * Verify that FFA is there and that it has the correct version. + /*********************************************************************** + * Check if SPMC has ffa_version and expected FFA endpoints are deployed. **********************************************************************/ - SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 0); + CHECK_HAFNIUM_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids); - /********************************************************************** - * 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 (!get_tftf_mailbox(&mb)) { - ERROR("Mailbox not configured!\n This test relies on" - " test suite \"FF-A RXTX Mapping\" to map/configure" - " RXTX buffers\n"); - return TEST_RESULT_FAIL; - } - - - /********************************************************************** - * Verify that cactus primary SP is deployed in the system. - **********************************************************************/ - SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(mb, primary_uuid); + GET_TFTF_MAILBOX(mb); struct ffa_memory_region_constituent constituents[] = { {(void *)share_page, 1, 0} @@ -65,68 +63,21 @@ static test_result_t test_memory_send_sp(uint32_t mem_func) 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; - } + handle = ffa_memory_init_and_send((struct ffa_memory_region *)mb.send, + MAILBOX_SIZE, SENDER, RECEIVER, + constituents, constituents_count, + mem_func); - if (sent_length != total_length) { - tftf_testcase_printf("Sent and Total lengths must be equal!\n"); + if (handle == FFA_MEMORY_HANDLE_INVALID) { 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); + ret = CACTUS_MEM_SEND_CMD_SEND(SENDER, RECEIVER, mem_func, handle); if (ret.ret0 != FFA_MSG_SEND_DIRECT_RESP_SMC32) { ERROR("Failed to send message. error: %lx\n", @@ -135,7 +86,7 @@ static test_result_t test_memory_send_sp(uint32_t mem_func) } if (CACTUS_GET_RESPONSE(ret) != CACTUS_SUCCESS) { - tftf_testcase_printf("Failed memory send operation!\n"); + ERROR("Failed memory send operation!\n"); return TEST_RESULT_FAIL; } @@ -174,3 +125,51 @@ test_result_t test_mem_donate_sp(void) { return test_memory_send_sp(FFA_MEM_DONATE_SMC32); } + +/* + * Test requests a memory send operation between cactus SPs. + * Cactus SP should reply to TFTF on whether the test succeeded or not. + */ +static test_result_t test_req_mem_send_sp_to_sp(uint32_t mem_func, + ffa_vm_id_t sender_sp, + ffa_vm_id_t receiver_sp) +{ + smc_ret_values ret; + + /*********************************************************************** + * Check if SPMC's ffa_version and presence of expected FF-A endpoints. + **********************************************************************/ + CHECK_HAFNIUM_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids); + + ret = CACTUS_REQ_MEM_SEND_SEND_CMD(HYP_ID, sender_sp, mem_func, + receiver_sp); + + 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_IS_ERROR_RESP(ret)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +test_result_t test_req_mem_share_sp_to_sp(void) +{ + return test_req_mem_send_sp_to_sp(FFA_MEM_SHARE_SMC32, SP_ID(3), + SP_ID(2)); +} + +test_result_t test_req_mem_lend_sp_to_sp(void) +{ + return test_req_mem_send_sp_to_sp(FFA_MEM_LEND_SMC32, SP_ID(2), + SP_ID(1)); +} + +test_result_t test_req_mem_donate_sp_to_sp(void) +{ + return test_req_mem_send_sp_to_sp(FFA_MEM_DONATE_SMC32, SP_ID(1), + SP_ID(3)); +} diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml index 14be8ca5a..2637acde0 100644 --- a/tftf/tests/tests-spm.xml +++ b/tftf/tests/tests-spm.xml @@ -46,12 +46,18 @@ <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"/> + <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"/> + <testcase name="Request Share Memory SP-to-SP" + function="test_req_mem_share_sp_to_sp" /> + <testcase name="Request Lend Memory SP-to-SP" + function="test_req_mem_lend_sp_to_sp" /> + <testcase name="Request Donate Memory SP-to-SP" + function="test_req_mem_donate_sp_to_sp" /> </testsuite> <testsuite name="FF-A features" |