diff options
author | Olivier Deprez <olivier.deprez@arm.com> | 2021-10-12 17:00:01 +0200 |
---|---|---|
committer | TrustedFirmware Code Review <review@review.trustedfirmware.org> | 2021-10-12 17:00:01 +0200 |
commit | 0c31afd95172d20d02bc79368a0d455bbcf3f3ca (patch) | |
tree | 1cffe0130527f66441f28323fb727fe2b76110d0 | |
parent | c01244e6e9eea9d0580623af0540ba41577c5f57 (diff) | |
parent | d63ae4bc3fb0b949fc88c31764b8dafada50772b (diff) |
Merge changes from topic "ja/notifications"
* changes:
test(ff-a): notifications set and get interfaces
feat(cactus): commands to set and get notifications
feat(ff-a): notifications set and get ABIs
test(ff-a): bind and unbind notifications
feat(cactus): commands for notifications bindings
test(ff-a): notifications bitmap create and destroy
feat(ff-a): notifications bind and unbind ABIs
feat(ff-a): notifications bitmap create and destroy ABIs
-rw-r--r-- | include/runtime_services/cactus_test_cmds.h | 119 | ||||
-rw-r--r-- | include/runtime_services/ffa_helpers.h | 55 | ||||
-rw-r--r-- | include/runtime_services/ffa_svc.h | 10 | ||||
-rw-r--r-- | spm/cactus/cactus.mk | 1 | ||||
-rw-r--r-- | spm/cactus/cactus_tests/cactus_test_notifications.c | 106 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/ffa_helpers.c | 108 | ||||
-rw-r--r-- | tftf/tests/runtime_services/secure_service/test_ffa_notifications.c | 652 | ||||
-rw-r--r-- | tftf/tests/tests-spm.mk | 1 | ||||
-rw-r--r-- | tftf/tests/tests-spm.xml | 30 |
9 files changed, 1077 insertions, 5 deletions
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h index 16bb36b..b588934 100644 --- a/include/runtime_services/cactus_test_cmds.h +++ b/include/runtime_services/cactus_test_cmds.h @@ -312,4 +312,123 @@ static inline smc_ret_values cactus_send_dma_cmd( return cactus_send_cmd(source, dest, CACTUS_DMA_SMMUv3_CMD, 0, 0, 0, 0); } + +/* + * Request SP to bind a notification to a FF-A endpoint. In case of error + * when using the FFA_NOTIFICATION_BIND interface, include the error code + * in the response to the command's request. The receiver and sender arguments + * are propagated through the command's arguments, to allow the test of + * erroneous uses of the FFA_NOTIFICATION_BIND interface. + * + * The command id is the hex representation of the string "bind". + */ +#define CACTUS_NOTIFICATION_BIND_CMD U(0x62696e64) + +static inline smc_ret_values cactus_notification_bind_send_cmd( + ffa_id_t source, ffa_id_t dest, ffa_id_t receiver, + ffa_id_t sender, ffa_notification_bitmap_t notifications, uint32_t flags) +{ + return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_BIND_CMD, + receiver, sender, notifications, flags); +} + +/** + * Request to SP unbind a notification. In case of error when using the + * FFA_NOTIFICATION_UNBIND interface, the test includes the error code in the + * response. The receiver and sender arguments are propagated throught the + * command's arguments, to allow the test of erroneous uses of the + * FFA_NOTIFICATION_BIND interface. + * + * The command id is the hex representation of the string "unbind". + */ +#define CACTUS_NOTIFICATION_UNBIND_CMD U(0x756e62696e64) + +static inline smc_ret_values cactus_notification_unbind_send_cmd( + ffa_id_t source, ffa_id_t dest, ffa_id_t receiver, + ffa_id_t sender, ffa_notification_bitmap_t notifications) +{ + return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_UNBIND_CMD, + receiver, sender, notifications, 0); +} + +static inline ffa_id_t cactus_notification_get_receiver( + smc_ret_values ret) +{ + return (ffa_id_t)ret.ret4; +} + +static inline ffa_id_t cactus_notification_get_sender( + smc_ret_values ret) +{ + return (ffa_id_t)ret.ret5; +} + +static inline ffa_notification_bitmap_t cactus_notification_get_notifications( + smc_ret_values ret) +{ + return (uint64_t)ret.ret6; +} + +/** + * Request SP to get notifications. The arguments to use in ffa_notification_get + * are propagated on the command to test erroneous uses of the interface. + * In a successful call to the interface, the SP's response payload should + * include all bitmaps returned by the SPMC. + * + * The command id is the hex representation of the string "getnot". + */ +#define CACTUS_NOTIFICATION_GET_CMD U(0x6765746e6f74) + +static inline smc_ret_values cactus_notification_get_send_cmd( + ffa_id_t source, ffa_id_t dest, ffa_id_t receiver, + uint32_t vcpu_id, uint32_t flags) +{ + return cactus_send_cmd(source, dest, CACTUS_NOTIFICATION_GET_CMD, + receiver, vcpu_id, 0, flags); +} + +static inline uint32_t cactus_notification_get_vcpu(smc_ret_values ret) +{ + return (uint32_t)ret.ret5; +} + +static inline uint32_t cactus_notification_get_flags(smc_ret_values ret) +{ + return (uint32_t)ret.ret7; +} + +static inline smc_ret_values cactus_notifications_get_success_resp( + ffa_id_t source, ffa_id_t dest, uint64_t from_sp, + uint64_t from_vm) +{ + return cactus_send_response(source, dest, CACTUS_SUCCESS, from_sp, + from_vm, 0, 0); +} + +static inline uint64_t cactus_notifications_get_from_sp(smc_ret_values ret) +{ + return (uint64_t)ret.ret4; +} + +static inline uint64_t cactus_notifications_get_from_vm(smc_ret_values ret) +{ + return (uint64_t)ret.ret5; +} + +/** + * Request SP to set notifications. The arguments to use in ffa_notification_set + * are propagated on the command to test erroneous uses of the interface. + * In case of error while calling the interface, the response should include the + * error code. + */ +#define CACTUS_NOTIFICATIONS_SET_CMD U(0x6e6f74736574) + +static inline smc_ret_values cactus_notifications_set_send_cmd( + ffa_id_t source, ffa_id_t dest, ffa_id_t receiver, + ffa_id_t sender, uint32_t flags, ffa_notification_bitmap_t notifications) +{ + return cactus_send_cmd(source, dest, CACTUS_NOTIFICATIONS_SET_CMD, + receiver, sender, notifications, flags); +} + #endif diff --git a/include/runtime_services/ffa_helpers.h b/include/runtime_services/ffa_helpers.h index c3f6294..eba1c9e 100644 --- a/include/runtime_services/ffa_helpers.h +++ b/include/runtime_services/ffa_helpers.h @@ -27,6 +27,7 @@ struct ffa_uuid { #ifndef __ASSEMBLY__ +#include <cassert.h> #include <stdint.h> /** Partition property: partition supports receipt of direct requests. */ @@ -47,11 +48,13 @@ struct ffa_partition_info { uint32_t properties; }; -static inline uint32_t ffa_func_id(smc_ret_values val) { +static inline uint32_t ffa_func_id(smc_ret_values val) +{ return (uint32_t) val.ret0; } -static inline int32_t ffa_error_code(smc_ret_values val) { +static inline int32_t ffa_error_code(smc_ret_values val) +{ return (int32_t) val.ret2; } @@ -59,6 +62,37 @@ static inline ffa_id_t ffa_endpoint_id(smc_ret_values val) { return (ffa_id_t) val.ret2 & 0xffff; } +typedef uint64_t ffa_notification_bitmap_t; + +#define FFA_NOTIFICATION(ID) (UINT64_C(1) << ID) + +#define MAX_FFA_NOTIFICATIONS UINT32_C(64) + +#define FFA_NOTIFICATIONS_FLAG_PER_VCPU UINT32_C(0x1 << 0) + +#define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16) + +#define FFA_NOTIFICATIONS_FLAG_BITMAP_SP UINT32_C(0x1 << 0) +#define FFA_NOTIFICATIONS_FLAG_BITMAP_VM UINT32_C(0x1 << 1) +#define FFA_NOTIFICATIONS_FLAG_BITMAP_SPM UINT32_C(0x1 << 2) +#define FFA_NOTIFICATIONS_FLAG_BITMAP_HYP UINT32_C(0x1 << 3) + +#define FFA_NOTIFICATIONS_BITMAP(lo, hi) \ + (ffa_notification_bitmap_t)(lo) | \ + (((ffa_notification_bitmap_t)hi << 32) & 0xFFFFFFFF00000000ULL) + +#define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16) + +static inline ffa_notification_bitmap_t ffa_notifications_get_from_sp(smc_ret_values val) +{ + return FFA_NOTIFICATIONS_BITMAP(val.ret2, val.ret3); +} + +static inline ffa_notification_bitmap_t ffa_notifications_get_from_vm(smc_ret_values val) +{ + return FFA_NOTIFICATIONS_BITMAP(val.ret4, val.ret5); +} + enum ffa_data_access { FFA_DATA_ACCESS_NOT_SPECIFIED, FFA_DATA_ACCESS_RO, @@ -318,7 +352,8 @@ struct ffa_mem_relinquish { static inline ffa_memory_handle_t ffa_assemble_handle(uint32_t h1, uint32_t h2) { - return (uint64_t)h1 | (uint64_t)h2 << 32; + return (ffa_notification_bitmap_t)h1 | + (ffa_notification_bitmap_t)h2 << 32; } static inline ffa_memory_handle_t ffa_mem_success_handle(smc_ret_values r) @@ -425,7 +460,19 @@ smc_ret_values ffa_mem_retrieve_req(uint32_t descriptor_length, uint32_t fragment_length); smc_ret_values ffa_mem_relinquish(void); smc_ret_values ffa_mem_reclaim(uint64_t handle, uint32_t flags); - +smc_ret_values ffa_notification_bitmap_create(ffa_id_t vm_id, + ffa_vcpu_count_t vcpu_count); +smc_ret_values ffa_notification_bitmap_destroy(ffa_id_t vm_id); +smc_ret_values ffa_notification_bind(ffa_id_t sender, ffa_id_t receiver, + uint32_t flags, + ffa_notification_bitmap_t notifications); +smc_ret_values ffa_notification_unbind(ffa_id_t sender, ffa_id_t receiver, + ffa_notification_bitmap_t notifications); +smc_ret_values ffa_notification_set(ffa_id_t sender, ffa_id_t receiver, + uint32_t flags, + ffa_notification_bitmap_t bitmap); +smc_ret_values ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id, + uint32_t flags); #endif /* __ASSEMBLY__ */ #endif /* FFA_HELPERS_H */ diff --git a/include/runtime_services/ffa_svc.h b/include/runtime_services/ffa_svc.h index 921fdbe..df19f98 100644 --- a/include/runtime_services/ffa_svc.h +++ b/include/runtime_services/ffa_svc.h @@ -126,7 +126,15 @@ FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_REQ) #define FFA_MEM_RETRIEVE_RESP FFA_FID(SMC_32, FFA_FNUM_MEM_RETRIEVE_RESP) #define FFA_MEM_RELINQUISH FFA_FID(SMC_32, FFA_FNUM_MEM_RELINQUISH) -#define FFA_MEM_RECLAIM FFA_FID(SMC_32, FFA_FNUM_MEM_RECLAIM) +#define FFA_MEM_RECLAIM FFA_FID(SMC_32, FFA_FNUM_MEM_RECLAIM) +#define FFA_NOTIFICATION_BITMAP_CREATE \ + FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_CREATE) +#define FFA_NOTIFICATION_BITMAP_DESTROY \ + FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BITMAP_DESTROY) +#define FFA_NOTIFICATION_BIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_BIND) +#define FFA_NOTIFICATION_UNBIND FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_UNBIND) +#define FFA_NOTIFICATION_SET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_SET) +#define FFA_NOTIFICATION_GET FFA_FID(SMC_32, FFA_FNUM_NOTIFICATION_GET) #define FFA_SPM_ID_GET FFA_FID(SMC_32, FFA_FNUM_SPM_ID_GET) /* FFA SMC64 FIDs */ diff --git a/spm/cactus/cactus.mk b/spm/cactus/cactus.mk index c21f44b..6252d2d 100644 --- a/spm/cactus/cactus.mk +++ b/spm/cactus/cactus.mk @@ -50,6 +50,7 @@ CACTUS_SOURCES := \ cactus_test_interrupts.c \ cactus_test_memory_sharing.c \ cactus_tests_smmuv3.c \ + cactus_test_notifications.c \ ) # TODO: Remove dependency on TFTF files. diff --git a/spm/cactus/cactus_tests/cactus_test_notifications.c b/spm/cactus/cactus_tests/cactus_test_notifications.c new file mode 100644 index 0000000..66eaf36 --- /dev/null +++ b/spm/cactus/cactus_tests/cactus_test_notifications.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "cactus_message_loop.h" +#include "cactus_test_cmds.h" +#include "cactus_tests.h" +#include <debug.h> +#include <ffa_helpers.h> + +CACTUS_CMD_HANDLER(notifications_bind, CACTUS_NOTIFICATION_BIND_CMD) +{ + ffa_id_t source = ffa_dir_msg_source(*args); + ffa_id_t vm_id = ffa_dir_msg_dest(*args); + ffa_id_t receiver = cactus_notification_get_receiver(*args); + ffa_id_t sender = cactus_notification_get_sender(*args); + ffa_notification_bitmap_t notifications = + cactus_notification_get_notifications(*args); + uint32_t flags = cactus_notification_get_flags(*args); + smc_ret_values ret; + + VERBOSE("Partition %x requested to bind notifications '%llx' to %x\n", + source, notifications, receiver); + + ret = ffa_notification_bind(sender, receiver, flags, notifications); + + if (is_ffa_call_error(ret)) { + return cactus_error_resp(vm_id, source, ffa_error_code(ret)); + } + + return cactus_response(vm_id, source, CACTUS_SUCCESS); +} + +CACTUS_CMD_HANDLER(notifications_unbind, CACTUS_NOTIFICATION_UNBIND_CMD) +{ + ffa_id_t source = ffa_dir_msg_source(*args); + ffa_id_t vm_id = ffa_dir_msg_dest(*args); + ffa_id_t receiver = cactus_notification_get_receiver(*args); + ffa_id_t sender = cactus_notification_get_sender(*args); + ffa_notification_bitmap_t notifications = + cactus_notification_get_notifications(*args); + smc_ret_values ret; + + VERBOSE("Partition %x requested to unbind notifications '%llx' to %x\n", + source, notifications, receiver); + + ret = ffa_notification_unbind(sender, receiver, notifications); + + if (is_ffa_call_error(ret)) { + return cactus_error_resp(vm_id, source, ffa_error_code(ret)); + } + + return cactus_response(vm_id, source, CACTUS_SUCCESS); +} + +CACTUS_CMD_HANDLER(notifications_get, CACTUS_NOTIFICATION_GET_CMD) +{ + ffa_id_t source = ffa_dir_msg_source(*args); + ffa_id_t vm_id = ffa_dir_msg_dest(*args); + ffa_id_t notification_receiver = + cactus_notification_get_receiver(*args); + uint32_t flags = cactus_notification_get_flags(*args); + uint32_t vcpu_id = cactus_notification_get_vcpu(*args); + smc_ret_values ret; + + VERBOSE("Partition %x requested to get notifications.\n", source); + + ret = ffa_notification_get(notification_receiver, vcpu_id, flags); + + if (is_ffa_call_error(ret)) { + return cactus_error_resp(vm_id, source, ffa_error_code(ret)); + } + + VERBOSE("Notifications returned:\n" + " from sp: %llx\n" + " from vm: %llx\n", + ffa_notifications_get_from_sp(ret), + ffa_notifications_get_from_vm(ret)); + + return cactus_notifications_get_success_resp( + vm_id, source, ffa_notifications_get_from_sp(ret), + ffa_notifications_get_from_vm(ret)); +} + +CACTUS_CMD_HANDLER(notifications_set, CACTUS_NOTIFICATIONS_SET_CMD) +{ + ffa_id_t source = ffa_dir_msg_source(*args); + ffa_id_t vm_id = ffa_dir_msg_dest(*args); + ffa_id_t receiver = cactus_notification_get_receiver(*args); + ffa_id_t sender = cactus_notification_get_sender(*args); + ffa_notification_bitmap_t notifications = cactus_notification_get_notifications(*args); + uint32_t flags = cactus_notification_get_flags(*args); + smc_ret_values ret; + + VERBOSE("Partition %x requested to set notifications.\n", source); + + ret = ffa_notification_set(sender, receiver, flags, notifications); + + if (is_ffa_call_error(ret)) { + return cactus_error_resp(vm_id, source, ffa_error_code(ret)); + } + + return cactus_response(vm_id, source, CACTUS_SUCCESS); +} diff --git a/tftf/tests/runtime_services/secure_service/ffa_helpers.c b/tftf/tests/runtime_services/secure_service/ffa_helpers.c index 2220148..6011d8b 100644 --- a/tftf/tests/runtime_services/secure_service/ffa_helpers.c +++ b/tftf/tests/runtime_services/secure_service/ffa_helpers.c @@ -499,3 +499,111 @@ smc_ret_values ffa_mem_reclaim(uint64_t handle, uint32_t flags) return tftf_smc(&args); } + +/** Create Notifications Bitmap for the given VM */ +smc_ret_values ffa_notification_bitmap_create(ffa_id_t vm_id, + ffa_vcpu_count_t vcpu_count) +{ + smc_args args = { + .fid = FFA_NOTIFICATION_BITMAP_CREATE, + .arg1 = vm_id, + .arg2 = vcpu_count, + .arg3 = FFA_PARAM_MBZ, + .arg4 = FFA_PARAM_MBZ, + .arg5 = FFA_PARAM_MBZ, + .arg6 = FFA_PARAM_MBZ, + .arg7 = FFA_PARAM_MBZ, + }; + + return tftf_smc(&args); +} + +/** Destroy Notifications Bitmap for the given VM */ +smc_ret_values ffa_notification_bitmap_destroy(ffa_id_t vm_id) +{ + smc_args args = { + .fid = FFA_NOTIFICATION_BITMAP_DESTROY, + .arg1 = vm_id, + .arg2 = FFA_PARAM_MBZ, + .arg3 = FFA_PARAM_MBZ, + .arg4 = FFA_PARAM_MBZ, + .arg5 = FFA_PARAM_MBZ, + .arg6 = FFA_PARAM_MBZ, + .arg7 = FFA_PARAM_MBZ, + }; + + return tftf_smc(&args); +} + +/** Bind VM to all the notifications in the bitmap */ +smc_ret_values ffa_notification_bind(ffa_id_t sender, ffa_id_t receiver, + uint32_t flags, + ffa_notification_bitmap_t bitmap) +{ + smc_args args = { + .fid = FFA_NOTIFICATION_BIND, + .arg1 = (sender << 16) | (receiver), + .arg2 = flags, + .arg3 = (uint32_t)(bitmap & 0xFFFFFFFFU), + .arg4 = (uint32_t)(bitmap >> 32), + .arg5 = FFA_PARAM_MBZ, + .arg6 = FFA_PARAM_MBZ, + .arg7 = FFA_PARAM_MBZ, + }; + + return tftf_smc(&args); +} + +/** Unbind previously bound VM from notifications in bitmap */ +smc_ret_values ffa_notification_unbind(ffa_id_t sender, + ffa_id_t receiver, + ffa_notification_bitmap_t bitmap) +{ + smc_args args = { + .fid = FFA_NOTIFICATION_UNBIND, + .arg1 = (sender << 16) | (receiver), + .arg2 = FFA_PARAM_MBZ, + .arg3 = (uint32_t)(bitmap), + .arg4 = (uint32_t)(bitmap >> 32), + .arg5 = FFA_PARAM_MBZ, + .arg6 = FFA_PARAM_MBZ, + .arg7 = FFA_PARAM_MBZ, + }; + + return tftf_smc(&args); +} + +smc_ret_values ffa_notification_set(ffa_id_t sender, ffa_id_t receiver, + uint32_t flags, + ffa_notification_bitmap_t bitmap) +{ + smc_args args = { + .fid = FFA_NOTIFICATION_SET, + .arg1 = (sender << 16) | (receiver), + .arg2 = flags, + .arg3 = (uint32_t)(bitmap & 0xFFFFFFFFU), + .arg4 = (uint32_t)(bitmap >> 32), + .arg5 = FFA_PARAM_MBZ, + .arg6 = FFA_PARAM_MBZ, + .arg7 = FFA_PARAM_MBZ + }; + + return tftf_smc(&args); +} + +smc_ret_values ffa_notification_get(ffa_id_t receiver, uint32_t vcpu_id, + uint32_t flags) +{ + smc_args args = { + .fid = FFA_NOTIFICATION_GET, + .arg1 = (receiver << 16) | (vcpu_id), + .arg2 = flags, + .arg3 = FFA_PARAM_MBZ, + .arg4 = FFA_PARAM_MBZ, + .arg5 = FFA_PARAM_MBZ, + .arg6 = FFA_PARAM_MBZ, + .arg7 = FFA_PARAM_MBZ + }; + + return tftf_smc(&args); +} diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c new file mode 100644 index 0000000..85a93a6 --- /dev/null +++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <debug.h> +#include <smccc.h> + +#include <arch_helpers.h> +#include <cactus_test_cmds.h> +#include <ffa_endpoints.h> +#include <ffa_svc.h> +#include <platform.h> +#include <spm_common.h> +#include <test_helpers.h> + +static const struct ffa_uuid expected_sp_uuids[] = { + {PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID} +}; + +static ffa_notification_bitmap_t g_notifications = FFA_NOTIFICATION(0) | + FFA_NOTIFICATION(1) | + FFA_NOTIFICATION(30) | + FFA_NOTIFICATION(50) | + FFA_NOTIFICATION(63); + +/** + * Helper to create bitmap for NWd VMs. + */ +static bool notifications_bitmap_create(ffa_id_t vm_id, + ffa_vcpu_count_t vcpu_count) +{ + VERBOSE("Creating bitmap for VM %x; cpu count: %u.\n", + vm_id, vcpu_count); + smc_ret_values ret = ffa_notification_bitmap_create(vm_id, vcpu_count); + + return !is_ffa_call_error(ret); +} + +/** + * Helper to destroy bitmap for NWd VMs. + */ +static bool notifications_bitmap_destroy(ffa_id_t vm_id) +{ + VERBOSE("Destroying bitmap of VM %x.\n", vm_id); + smc_ret_values ret = ffa_notification_bitmap_destroy(vm_id); + + return !is_ffa_call_error(ret); +} + +/** + * Test notifications bitmap create and destroy interfaces. + */ +test_result_t test_ffa_notifications_bitmap_create_destroy(void) +{ + const ffa_id_t vm_id = HYP_ID + 1; + + SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1); + + if (check_spmc_execution_level()) { + VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n"); + return TEST_RESULT_SKIPPED; + } + + if (!notifications_bitmap_create(vm_id, PLATFORM_CORE_COUNT)) { + return TEST_RESULT_FAIL; + } + + if (!notifications_bitmap_destroy(vm_id)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test notifications bitmap destroy in a case the bitmap hasn't been created. + */ +test_result_t test_ffa_notifications_destroy_not_created(void) +{ + SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1); + + if (check_spmc_execution_level()) { + VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n"); + return TEST_RESULT_SKIPPED; + } + + smc_ret_values ret = ffa_notification_bitmap_destroy(HYP_ID + 1); + + if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test attempt to create notifications bitmap for NWd VM if it had been + * already created. + */ +test_result_t test_ffa_notifications_create_after_create(void) +{ + smc_ret_values ret; + const ffa_id_t vm_id = HYP_ID + 2; + + SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1); + + if (check_spmc_execution_level()) { + VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n"); + return TEST_RESULT_SKIPPED; + } + + /* First successfully create a notifications bitmap */ + if (!notifications_bitmap_create(vm_id, 1)) { + return TEST_RESULT_FAIL; + } + + /* Attempt to do the same to the same VM. */ + ret = ffa_notification_bitmap_create(vm_id, 1); + + if (!is_expected_ffa_error(ret, FFA_ERROR_DENIED)) { + return TEST_RESULT_FAIL; + } + + /* Destroy to not affect other tests */ + if (!notifications_bitmap_destroy(vm_id)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Helper function to test FFA_NOTIFICATION_BIND interface. + * Receives all arguments to use 'cactus_notification_bind_send_cmd', and + * expected response for the test command. + * + * Returns: + * - 'true' if response was obtained and it was as expected; + * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or + * the obtained response was not as expected. + */ +static bool request_notification_bind( + ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender, + ffa_notification_bitmap_t notifications, uint32_t flags, + uint32_t expected_resp, uint32_t error_code) +{ + smc_ret_values ret; + + VERBOSE("TFTF requesting SP to bind notifications!\n"); + + ret = cactus_notification_bind_send_cmd(HYP_ID, cmd_dest, receiver, + sender, notifications, flags); + + return is_expected_cactus_response(ret, expected_resp, error_code); +} + +/** + * Helper function to test FFA_NOTIFICATION_UNBIND interface. + * Receives all arguments to use 'cactus_notification_unbind_send_cmd', and + * expected response for the test command. + * + * Returns: + * - 'true' if response was obtained and it was as expected; + * - 'false' if there was an error with use of FFA_MSG_SEND_DIRECT_REQ, or + * the obtained response was not as expected. + */ +static bool request_notification_unbind( + ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender, + ffa_notification_bitmap_t notifications, uint32_t expected_resp, + uint32_t error_code) +{ + smc_ret_values ret; + + VERBOSE("TFTF requesting SP to unbind notifications!\n"); + + ret = cactus_notification_unbind_send_cmd(HYP_ID, cmd_dest, receiver, + sender, notifications); + + return is_expected_cactus_response(ret, expected_resp, error_code); +} + +/** + * Test calls from SPs to the bind and unbind interfaces, expecting success + * returns. + * This test issues a request via direct messaging to the SP, which executes + * the test and responds with the result of the call. + */ +test_result_t test_ffa_notifications_sp_bind_unbind(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + + /** First bind... */ + if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2), + g_notifications, 0, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + if (!request_notification_bind(SP_ID(1), SP_ID(1), 1, + g_notifications, 0, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + /** ... then unbind using the same arguments. */ + if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2), + g_notifications, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + if (!request_notification_unbind(SP_ID(1), SP_ID(1), 1, + g_notifications, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test successful attempt of doing bind and unbind of the same set of + * notifications. + */ +test_result_t test_ffa_notifications_vm_bind_unbind(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + const ffa_id_t vm_id = 1; + smc_ret_values ret; + + if (!notifications_bitmap_create(vm_id, 1)) { + return TEST_RESULT_FAIL; + } + + ret = ffa_notification_bind(SP_ID(2), vm_id, 0, g_notifications); + + if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) { + return TEST_RESULT_FAIL; + } + + ret = ffa_notification_unbind(SP_ID(2), vm_id, g_notifications); + + if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) { + return TEST_RESULT_FAIL; + } + + if (!notifications_bitmap_destroy(vm_id)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test expected failure of using a NS FF-A ID for the sender. + */ +test_result_t test_ffa_notifications_vm_bind_vm(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + const ffa_id_t vm_id = 1; + const ffa_id_t sender_id = 2; + smc_ret_values ret; + + if (!notifications_bitmap_create(vm_id, 1)) { + return TEST_RESULT_FAIL; + } + + ret = ffa_notification_bind(sender_id, vm_id, 0, g_notifications); + + if (!is_expected_ffa_error(ret, FFA_ERROR_INVALID_PARAMETER)) { + return TEST_RESULT_FAIL; + } + + if (!notifications_bitmap_destroy(vm_id)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test failure of both bind and unbind in case at least one notification is + * already bound to another FF-A endpoint. + * Expect error code FFA_ERROR_DENIED. + */ +test_result_t test_ffa_notifications_already_bound(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + + /** Bind first to test */ + if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2), + g_notifications, 0, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + /** Attempt to bind notifications bound in above request. */ + if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(3), + g_notifications, 0, CACTUS_ERROR, + FFA_ERROR_DENIED)) { + return TEST_RESULT_FAIL; + } + + /** Attempt to unbind notifications bound in initial request. */ + if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(3), + g_notifications, CACTUS_ERROR, + FFA_ERROR_DENIED)) { + return TEST_RESULT_FAIL; + } + + /** Reset the state the SP's notifications state. */ + if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2), + g_notifications, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Try to bind/unbind notifications spoofing the identity of the receiver. + * Commands will be sent to SP_ID(1), which will use SP_ID(3) as the receiver. + * Expect error code FFA_ERROR_INVALID_PARAMETER. + */ +test_result_t test_ffa_notifications_bind_unbind_spoofing(void) +{ + ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(8); + + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + + if (!request_notification_bind(SP_ID(1), SP_ID(3), SP_ID(2), + notifications, 0, CACTUS_ERROR, + FFA_ERROR_INVALID_PARAMETER)) { + return TEST_RESULT_FAIL; + } + + if (!request_notification_unbind(SP_ID(1), SP_ID(3), SP_ID(2), + notifications, CACTUS_ERROR, + FFA_ERROR_INVALID_PARAMETER)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Call FFA_NOTIFICATION_BIND with notifications bitmap zeroed. + * Expecting error code FFA_ERROR_INVALID_PARAMETER. + */ +test_result_t test_ffa_notifications_bind_unbind_zeroed(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + + if (!request_notification_bind(SP_ID(1), SP_ID(1), SP_ID(2), + 0, 0, CACTUS_ERROR, + FFA_ERROR_INVALID_PARAMETER)) { + return TEST_RESULT_FAIL; + } + + if (!request_notification_unbind(SP_ID(1), SP_ID(1), SP_ID(2), + 0, CACTUS_ERROR, + FFA_ERROR_INVALID_PARAMETER)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Helper function to test FFA_NOTIFICATION_GET interface. + * Receives all arguments to use 'cactus_notification_get_send_cmd', and returns + * the received response. Depending on the testing scenario, this will allow + * to validate if the returned bitmaps are as expected. + * + * Returns: + * - 'true' if response was obtained. + * - 'false' if there was an error sending the request. + */ +static bool request_notification_get( + ffa_id_t cmd_dest, ffa_id_t receiver, uint32_t vcpu_id, + uint32_t flags, smc_ret_values *response) +{ + VERBOSE("TFTF requesting SP to get notifications!\n"); + + *response = cactus_notification_get_send_cmd(HYP_ID, cmd_dest, + receiver, vcpu_id, + flags); + + return is_ffa_direct_response(*response); +} + +static bool request_notification_set( + ffa_id_t cmd_dest, ffa_id_t receiver, ffa_id_t sender, uint32_t flags, + ffa_notification_bitmap_t notifications, uint32_t exp_resp, + int32_t exp_error) +{ + smc_ret_values ret; + + VERBOSE("TFTF requesting SP %x (as %x) to set notifications to %x\n", + cmd_dest, sender, receiver); + + ret = cactus_notifications_set_send_cmd(HYP_ID, cmd_dest, receiver, + sender, flags, notifications); + + return is_expected_cactus_response(ret, exp_resp, exp_error); +} + +/** + * Check that SP's response to CACTUS_NOTIFICATION_GET_CMD is as expected. + */ +static bool is_notifications_get_as_expected( + smc_ret_values *ret, uint64_t exp_from_sp, uint64_t exp_from_vm, + ffa_id_t receiver) +{ + uint64_t from_sp; + uint64_t from_vm; + bool success_ret; + + /** + * If receiver ID is SP, this is to evaluate the response to test + * command 'CACTUS_NOTIFICATION_GET_CMD'. + */ + if (IS_SP_ID(receiver)) { + success_ret = (cactus_get_response(*ret) == CACTUS_SUCCESS); + from_sp = cactus_notifications_get_from_sp(*ret); + from_vm = cactus_notifications_get_from_vm(*ret); + } else { + /** + * Else, this is to evaluate the return of FF-A call: + * ffa_notification_get. + */ + success_ret = (ffa_func_id(*ret) == FFA_SUCCESS_SMC32); + from_sp = ffa_notifications_get_from_sp(*ret); + from_vm = ffa_notifications_get_from_vm(*ret); + } + + if (success_ret != true || + exp_from_sp != from_sp || + exp_from_vm != from_vm) { + VERBOSE("Notifications not as expected:\n" + " from sp: %llx exp: %llx\n" + " from vm: %llx exp: %llx\n", + from_sp, exp_from_sp, from_vm, exp_from_vm); + return false; + } + + return true; +} + +/** + * Helper to bind notification and set it. + * If receiver is SP it will request SP to perform the bind, else invokes + * FFA_NOTIFICATION_BIND. + * If Sender is SP it will request it to perform the set, else invokes + * FFA_NOTIFICATION_SET. + */ +static bool notification_bind_and_set(ffa_id_t sender, + ffa_id_t receiver, ffa_notification_bitmap_t notifications, uint32_t flags) +{ + smc_ret_values ret; + uint32_t flags_bind = flags & FFA_NOTIFICATIONS_FLAG_PER_VCPU; + + /* Receiver binds notifications to sender. */ + if (!IS_SP_ID(receiver)) { + ret = ffa_notification_bind(sender, receiver, + flags_bind, notifications); + + if (is_ffa_call_error(ret)) { + return false; + } + } else { + if (!request_notification_bind(receiver, receiver, sender, + notifications, flags_bind, + CACTUS_SUCCESS, + 0)) { + return false; + } + } + + /* Sender sets notifications to receiver. */ + if (!IS_SP_ID(sender)) { + VERBOSE("VM %x Setting notifications %llx to receiver %x\n", + sender, notifications, receiver); + ret = ffa_notification_set(sender, receiver, flags, notifications); + + return is_expected_ffa_return(ret, FFA_SUCCESS_SMC32); + } + + return request_notification_set(sender, receiver, sender, flags, + notifications, CACTUS_SUCCESS, 0); +} + +/** + * Helper to request SP to get the notifications and validate the return. + */ +static bool notification_get_and_validate( + ffa_id_t receiver, ffa_notification_bitmap_t exp_from_sp, + ffa_notification_bitmap_t exp_from_vm, uint32_t vcpu_id, + uint32_t flags) +{ + smc_ret_values ret; + + /* Receiver gets pending notifications. */ + if (IS_SP_ID(receiver)) { + request_notification_get(receiver, receiver, vcpu_id, flags, + &ret); + } else { + ret = ffa_notification_get(receiver, vcpu_id, flags); + } + + return is_notifications_get_as_expected(&ret, exp_from_sp, exp_from_vm, + receiver); +} + +/** + * Test to validate a VM can signal an SP. + */ +test_result_t test_ffa_notifications_vm_signals_sp(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + const ffa_id_t sender = 1; + const ffa_id_t receiver = SP_ID(1); + ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(1) | FFA_NOTIFICATION(60); + const uint32_t flags_get = FFA_NOTIFICATIONS_FLAG_BITMAP_VM; + + if (!notification_bind_and_set(sender, receiver, notifications, 0)) { + return TEST_RESULT_FAIL; + } + + if (!notification_get_and_validate(receiver, 0, notifications, 0, + flags_get)) { + return TEST_RESULT_FAIL; + } + + if (!request_notification_unbind(receiver, receiver, sender, + notifications, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test to validate an SP can signal an SP. + */ +test_result_t test_ffa_notifications_sp_signals_sp(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + const ffa_id_t sender = SP_ID(1); + const ffa_id_t receiver = SP_ID(2); + uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP; + + /** Request receiver to bind a set of notifications to the sender */ + if (!notification_bind_and_set(sender, receiver, + g_notifications, 0)) { + return TEST_RESULT_FAIL; + } + + if (!notification_get_and_validate(receiver, g_notifications, 0, 0, + get_flags)) { + return TEST_RESULT_FAIL; + } + + if (!request_notification_unbind(receiver, receiver, sender, + g_notifications, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test to validate an SP can signal a VM. + */ +test_result_t test_ffa_notifications_sp_signals_vm(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + const ffa_id_t sender = SP_ID(1); + const ffa_id_t receiver = 1; + uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_SP; + smc_ret_values ret; + + /* Ask SPMC to allocate notifications bitmap. */ + if (!notifications_bitmap_create(receiver, 1)) { + return TEST_RESULT_FAIL; + } + + /* Request receiver to bind a set of notifications to the sender. */ + if (!notification_bind_and_set(sender, receiver, g_notifications, 0)) { + return TEST_RESULT_FAIL; + } + + /* Get pending notifications, and retrieve response. */ + if (!notification_get_and_validate(receiver, g_notifications, 0, 0, + get_flags)) { + return TEST_RESULT_FAIL; + } + + ret = ffa_notification_unbind(sender, receiver, g_notifications); + + if (!is_expected_ffa_return(ret, FFA_SUCCESS_SMC32)) { + return TEST_RESULT_FAIL; + } + + if (!notifications_bitmap_destroy(receiver)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} + +/** + * Test to validate it is not possible to unbind a pending notification. + */ +test_result_t test_ffa_notifications_unbind_pending(void) +{ + CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids); + const ffa_id_t receiver = SP_ID(1); + const ffa_id_t sender = 1; + const ffa_notification_bitmap_t notifications = FFA_NOTIFICATION(30) | + FFA_NOTIFICATION(35); + uint32_t get_flags = FFA_NOTIFICATIONS_FLAG_BITMAP_VM; + + /* Request receiver to bind a set of notifications to the sender. */ + if (!notification_bind_and_set(sender, receiver, notifications, 0)) { + return TEST_RESULT_FAIL; + } + + /* + * Attempt to unbind the pending notification, but expect error return + * given the notification is pending. + */ + if (!request_notification_unbind(receiver, receiver, sender, + FFA_NOTIFICATION(30), + CACTUS_ERROR, FFA_ERROR_DENIED)) { + return TEST_RESULT_FAIL; + } + + /* + * Request receiver partition to get pending notifications from VMs. + * Only notification 30 is expected. + */ + if (!notification_get_and_validate(receiver, 0, notifications, 0, + get_flags)) { + return TEST_RESULT_FAIL; + } + + /* Unbind all notifications, to not interfere with other tests. */ + if (!request_notification_unbind(receiver, receiver, sender, + notifications, CACTUS_SUCCESS, 0)) { + return TEST_RESULT_FAIL; + } + + return TEST_RESULT_SUCCESS; +} diff --git a/tftf/tests/tests-spm.mk b/tftf/tests/tests-spm.mk index dc99337..b5a9d0c 100644 --- a/tftf/tests/tests-spm.mk +++ b/tftf/tests/tests-spm.mk @@ -12,6 +12,7 @@ TESTS_SOURCES += \ test_ffa_interrupts.c \ test_ffa_memory_sharing.c \ test_ffa_setup_and_discovery.c \ + test_ffa_notifications.c \ test_spm_cpu_features.c \ test_spm_smmu.c \ ) diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml index 3e6c72c..b59ca0b 100644 --- a/tftf/tests/tests-spm.xml +++ b/tftf/tests/tests-spm.xml @@ -100,4 +100,34 @@ function="test_smmu_spm" /> </testsuite> + <testsuite name="FF-A Notifications" + description="Test Notifications functionality" > + <testcase name="Notifications bitmap create and destroy" + function="test_ffa_notifications_bitmap_create_destroy" /> + <testcase name="Notifications bitmap destroy not created" + function="test_ffa_notifications_destroy_not_created" /> + <testcase name="Notifications bitmap create after create" + function="test_ffa_notifications_create_after_create" /> + <testcase name="SP Notifications bind and unbind" + function="test_ffa_notifications_sp_bind_unbind" /> + <testcase name="VM Notifications bind and unbind" + function="test_ffa_notifications_vm_bind_unbind" /> + <testcase name="VM Notifications bind NS Sender" + function="test_ffa_notifications_vm_bind_vm" /> + <testcase name="Notifications bind/unbind of bound Notifications" + function="test_ffa_notifications_already_bound" /> + <testcase name="Notifications bind/unbind SPs spoofing receiver" + function="test_ffa_notifications_bind_unbind_spoofing" /> + <testcase name="Notifications zeroed in bind and unbind" + function="test_ffa_notifications_bind_unbind_zeroed" /> + <testcase name="Notifications VM signals SP" + function="test_ffa_notifications_vm_signals_sp" /> + <testcase name="Notifications SP signals SP" + function="test_ffa_notifications_sp_signals_sp" /> + <testcase name="Notifications SP signals VM" + function="test_ffa_notifications_sp_signals_vm" /> + <testcase name="Notifications unbind while pending" + function="test_ffa_notifications_unbind_pending" /> + </testsuite> + </testsuites> |