test(ff-a): signaling per-vCPU notifications
Testing per-vCPU notifications, which are notifications whose vCPU is
specified by the sender. Each vCPU is targeted with a notification, as
such all CPUs are brought up, in each one of them TFTF sends a request
to the receiver Cactus SP to get its pending notifications.
Small changes to helper functions to include the flags argument to be
passed to notifications FF-A calls. Tests encompass SP to SP and NWd to
SP.
Signed-off-by: J-Alves <joao.alves@arm.com>
Change-Id: I86ba840b4c1d35cce95e2bc197293511db6783a1
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
index a8856b5..25b1e0a 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_notifications.c
@@ -15,6 +15,23 @@
#include <spm_common.h>
#include <test_helpers.h>
+/**
+ * Defining variables to test the per-vCPU notifications.
+ * The conceived test follows the same logic, despite the sender receiver type
+ * of endpoint (VM or secure partition).
+ * Using global variables because these need to be accessed in the cpu on handler
+ * function 'request_notification_get_per_vcpu_on_handler'.
+ * In each specific test function, change 'per_vcpu_receiver' and
+ * 'per_vcpu_sender' have the logic work for:
+ * - NWd to SP;
+ * - SP to NWd;
+ * - SP to SP.
+ */
+static ffa_id_t per_vcpu_receiver;
+static ffa_id_t per_vcpu_sender;
+uint32_t per_vcpu_flags_get;
+static event_t per_vcpu_finished[PLATFORM_CORE_COUNT];
+
static const struct ffa_uuid expected_sp_uuids[] = {
{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
};
@@ -578,6 +595,7 @@
uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
uint32_t lists_count;
uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
+ const bool more_notif_pending = false;
CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
@@ -593,7 +611,7 @@
if (!notifications_info_get(ids, lists_count, lists_sizes,
FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
- false)) {
+ more_notif_pending)) {
return TEST_RESULT_FAIL;
}
@@ -784,3 +802,177 @@
return TEST_RESULT_SUCCESS;
}
+
+/**
+ * CPU_ON handler for testing per-vCPU notifications to SPs (either from VMs
+ * or from SPs). It requests the SP to retrieve its pending notifications
+ * within its current Execution Context. The SP shall obtain all per-vCPU
+ * targeted to the running vCPU.
+ */
+static test_result_t request_notification_get_per_vcpu_on_handler(void)
+{
+ unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+ unsigned int core_pos = platform_get_core_pos(mpid);
+ smc_ret_values ret;
+ test_result_t result = TEST_RESULT_FAIL;
+
+ uint64_t exp_from_vm = 0;
+ uint64_t exp_from_sp = 0;
+
+ if (IS_SP_ID(per_vcpu_sender)) {
+ exp_from_sp = FFA_NOTIFICATION(core_pos);
+ } else {
+ exp_from_vm = FFA_NOTIFICATION(core_pos);
+ }
+
+ VERBOSE("Request get per-vCPU notification to %x, core: %u.\n",
+ per_vcpu_receiver, core_pos);
+
+ /*
+ * Secure Partitions secondary ECs need one round of ffa_run to reach
+ * the message loop.
+ */
+ if (per_vcpu_receiver != SP_ID(1)) {
+ ret = ffa_run(per_vcpu_receiver, core_pos);
+
+ if (ffa_func_id(ret) != FFA_MSG_WAIT) {
+ ERROR("Failed to run SP%x on core %u\n",
+ per_vcpu_receiver, core_pos);
+ goto out;
+ }
+ }
+
+ /* Request to get notifications sent to the respective vCPU. */
+ if (!notification_get_and_validate(
+ per_vcpu_receiver, exp_from_sp, exp_from_vm, core_pos,
+ per_vcpu_flags_get)) {
+ goto out;
+ }
+
+ result = TEST_RESULT_SUCCESS;
+
+out:
+ /* Tell the lead CPU that the calling CPU has completed the test. */
+ tftf_send_event(&per_vcpu_finished[core_pos]);
+
+ return result;
+}
+
+/**
+ * Base function to test signaling of per-vCPU notifications.
+ * Test whole flow between two FF-A endpoints: binding, getting notification
+ * info, and getting pending notifications.
+ * Each vCPU will receive a notification whose ID is the same as the core
+ * position.
+ */
+static test_result_t base_test_per_vcpu_notifications(ffa_id_t sender,
+ ffa_id_t receiver)
+{
+ CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
+
+ /*
+ * Manually set variables to validate what should be the return of to
+ * FFA_NOTIFICATION_INFO_GET.
+ */
+ uint16_t exp_ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ receiver, 0, 1, 2,
+ receiver, 3, 4, 5,
+ receiver, 6, 7, 0,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ };
+ uint32_t exp_lists_count = 3;
+ uint32_t exp_lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {
+ 3, 3, 2, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ const bool exp_more_notif_pending = false;
+ test_result_t result = TEST_RESULT_SUCCESS;
+ uint64_t notifications_to_unbind = 0;
+
+ per_vcpu_flags_get = IS_SP_ID(sender)
+ ? FFA_NOTIFICATIONS_FLAG_BITMAP_SP
+ : FFA_NOTIFICATIONS_FLAG_BITMAP_VM;
+
+ /*
+ * Prepare notifications bitmap to request Cactus to bind them as
+ * per-vCPU.
+ */
+ for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+ notifications_to_unbind |= FFA_NOTIFICATION(i);
+
+ uint32_t flags = FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+ FFA_NOTIFICATIONS_FLAGS_VCPU_ID((uint16_t)i);
+
+ if (!notification_bind_and_set(sender,
+ receiver,
+ FFA_NOTIFICATION(i),
+ flags)) {
+ return TEST_RESULT_FAIL;
+ }
+ }
+
+ /* Call FFA_NOTIFICATION_INFO_GET and validate return. */
+ if (!notifications_info_get(exp_ids, exp_lists_count, exp_lists_sizes,
+ FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
+ exp_more_notif_pending)) {
+ ERROR("Info Get Failed....\n");
+ result = TEST_RESULT_FAIL;
+ goto out;
+ }
+
+ /*
+ * Request SP to get notifications in core 0, as this is not iterated
+ * at the CPU ON handler.
+ */
+ if (!notification_get_and_validate(
+ receiver,
+ IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+ !IS_SP_ID(sender) ? FFA_NOTIFICATION(0) : 0,
+ 0,
+ per_vcpu_flags_get)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ /* Setting global variables to be accessed by the cpu_on handler. */
+ per_vcpu_receiver = receiver;
+ per_vcpu_sender = sender;
+
+ /*
+ * Bring up all the cores, and request the receiver to get notifications
+ * in each one of them.
+ */
+ if (spm_run_multi_core_test(
+ (uintptr_t)request_notification_get_per_vcpu_on_handler,
+ per_vcpu_finished) != TEST_RESULT_SUCCESS) {
+ result = TEST_RESULT_FAIL;
+ }
+
+out:
+ /* As a clean-up, unbind notifications. */
+ if (!request_notification_unbind(receiver, receiver,
+ sender,
+ notifications_to_unbind,
+ CACTUS_SUCCESS, 0)) {
+ result = TEST_RESULT_FAIL;
+ }
+
+ return result;
+}
+
+/**
+ * Test to validate a VM can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_vm_signals_sp_per_vcpu(void)
+{
+ return base_test_per_vcpu_notifications(0, SP_ID(1));
+}
+
+/**
+ * Test to validate an SP can signal a per-vCPU notification to an SP.
+ */
+test_result_t test_ffa_notifications_sp_signals_sp_per_vcpu(void)
+{
+ return base_test_per_vcpu_notifications(SP_ID(1), SP_ID(2));
+}
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index 968bd16..1a0134d 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -130,6 +130,10 @@
function="test_ffa_notifications_unbind_pending" />
<testcase name="Notifications info get no data"
function="test_ffa_notifications_info_get_none" />
+ <testcase name="Notifications VM signals SP per-vCPU"
+ function="test_ffa_notifications_vm_signals_sp_per_vcpu" />
+ <testcase name="Notifications SP signals SP per-vCPU"
+ function="test_ffa_notifications_sp_signals_sp_per_vcpu" />
</testsuite>
</testsuites>