feat(rme/spm): test co-working of rmm and spm

To verify if rmm and spm can co-exist and work properly following
two test cases identified and implemented:

  1. normal world must be able to send direct message(FFA) to
  secure world and RMI call to realm world in series via SMC
  from a single core
  2. normal world must be able to send direct message(FFA) to
  secure world and RMI call to realm world in parallel via SMC
  using multiple cores

Signed-off-by: Nabil kahlouche <nabil.kahlouche@arm.com>
Change-Id: If5c24da9062d100419220fe0e5409b73596e773c
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
index 70b1b09..1aaa12c 100644
--- a/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_spm_test.c
@@ -26,12 +26,14 @@
 #define ECHO_VAL1 U(0xa0a0a0a0)
 #define ECHO_VAL2 U(0xb0b0b0b0)
 #define ECHO_VAL3 U(0xc0c0c0c0)
+#define MAX_REPEATED_TEST 3
 
 /* Buffer to delegate and undelegate */
 static char bufferdelegate[NUM_GRANULES * GRANULE_SIZE * PLATFORM_CORE_COUNT] __aligned(GRANULE_SIZE);
 static char bufferstate[NUM_GRANULES * PLATFORM_CORE_COUNT];
 static int cpu_test_spm_rmi[PLATFORM_CORE_COUNT];
-
+static event_t cpu_booted[PLATFORM_CORE_COUNT];
+static unsigned int lead_mpid;
 /*
  * The following test conducts SPM(direct messaging) tests on a subset of selected CPUs while
  * simultaneously performing another set of tests of the RMI(delegation)
@@ -120,15 +122,50 @@
 }
 
 /*
+ * Each CPU reaching this function will send a ready event to all other CPUs
+ * and wait for others CPUs before start executing its callback in parallel
+ * with all others CPUs
+ */
+static test_result_t wait_then_call(test_result_t (*callback)(void))
+{
+	unsigned int mpidr, this_mpidr = read_mpidr_el1() & MPID_MASK;
+	unsigned int cpu_node, core_pos, this_core_pos = platform_get_core_pos(this_mpidr);
+	tftf_send_event_to_all(&cpu_booted[this_core_pos]);
+	for_each_cpu(cpu_node) {
+		mpidr = tftf_get_mpidr_from_node(cpu_node);
+		/* Ignore myself and the lead core */
+		if (mpidr == this_mpidr || mpidr == lead_mpid) {
+			continue;
+		}
+		core_pos = platform_get_core_pos(mpidr);
+		tftf_wait_for_event(&cpu_booted[core_pos]);
+	}
+	/* All cores reach this call in approximately "same" time */
+	return (*callback)();
+}
+
+/*
+ * Power on the given cpu and provide it with entrypoint to run and return result
+ */
+static test_result_t run_on_cpu(unsigned int  mpidr, uintptr_t cpu_on_handler)
+{
+	int32_t ret;
+
+	ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
+	if (ret != PSCI_E_SUCCESS) {
+		ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
+		return TEST_RESULT_FAIL;
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
  * SPM functions for the direct messaging
  */
 static const struct ffa_uuid expected_sp_uuids[] = {
 		{PRIMARY_UUID}, {SECONDARY_UUID}, {TERTIARY_UUID}
 	};
 
-
-static event_t cpu_booted[PLATFORM_CORE_COUNT];
-
 static test_result_t send_cactus_echo_cmd(ffa_id_t sender,
 					  ffa_id_t dest,
 					  uint64_t value)
@@ -234,128 +271,27 @@
 	ret = TEST_RESULT_FAIL;
 
 out:
-	/* Tell the lead CPU that the calling CPU has completed the test */
-	tftf_send_event(&cpu_booted[core_pos]);
-
 	return ret;
 }
 
 /*
- * Test function to dispatch a number of SPM and RMI tests to the platform
- * number of CPU's.  The test is run twice on a another set of randomly determined
- * CPU's.
+ * Secondary core will perform sequentially a call to secure and realm worlds.
  */
-test_result_t test_ffa_secondary_core_direct_realm_msg(void)
+test_result_t non_secure_call_secure_and_realm(void)
 {
-	if (get_armv9_2_feat_rme_support() == 0U) {
-		return TEST_RESULT_SKIPPED;
-	}
+	test_result_t result = run_spm_direct_message();
+	if (result != TEST_RESULT_SUCCESS)
+		return result;
+	return realm_multi_cpu_payload_del_undel();
+}
 
-	unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
-	unsigned int cpu_node, mpidr;
-	int32_t ret;
-	u_register_t retrmm;
-
-	/**********************************************************************
-	 * Check SPMC has ffa_version and expected FFA endpoints are deployed.
-	 **********************************************************************/
-	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
-
-	for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
-		tftf_init_event(&cpu_booted[i]);
-	}
-
-	/*
-	 * Randomize the assignment of the CPU's to either SPM or RMI
-	 */
-	rand_cpu_spm_rmi();
-
-	/*
-	 * Randomize the initial state of the RMI granules to realm or non-secure
-	 */
-	if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
-		return TEST_RESULT_FAIL;
-	}
-
-	/*
-	 * Main test to run both SPM and RMI together
-	 */
-	for_each_cpu(cpu_node) {
-		mpidr = tftf_get_mpidr_from_node(cpu_node);
-		if (mpidr == lead_mpid) {
-			continue;
-		}
-
-		if (spm_rmi_test(mpidr) == 1) {
-			ret = tftf_cpu_on(mpidr, (uintptr_t)run_spm_direct_message, 0U);
-			if (ret != 0) {
-				ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
-				return TEST_RESULT_FAIL;
-			}
-		} else {
-			ret = tftf_cpu_on(mpidr,
-				(uintptr_t)realm_multi_cpu_payload_del_undel, 0);
-
-			if (ret != PSCI_E_SUCCESS) {
-				ERROR("CPU ON failed for 0x%llx\n",
-					(unsigned long long)mpidr);
-				return TEST_RESULT_FAIL;
-			}
-		}
-	}
-
-	VERBOSE("Waiting for secondary CPUs to turn off ...\n");
-
-	for_each_cpu(cpu_node) {
-		mpidr = tftf_get_mpidr_from_node(cpu_node);
-		if (mpidr == lead_mpid) {
-			continue;
-		}
-
-		while (tftf_psci_affinity_info(mpidr, MPIDR_AFFLVL0) !=
-				PSCI_STATE_OFF) {
-				continue;
-		}
-	}
-
-	/*
-	 * Randomize the CPU's again
-	 */
-	rand_cpu_spm_rmi();
-
-	/*
-	 * Run test again
-	 */
-	for_each_cpu(cpu_node) {
-		mpidr = tftf_get_mpidr_from_node(cpu_node);
-		if (mpidr == lead_mpid) {
-			continue;
-		}
-
-		if (spm_rmi_test(mpidr) == 1) {
-			ret = tftf_cpu_on(mpidr, (uintptr_t)run_spm_direct_message, 0U);
-			if (ret != 0) {
-				ERROR("tftf_cpu_on mpidr 0x%x returns %d\n", mpidr, ret);
-				return TEST_RESULT_FAIL;
-			}
-		} else {
-			ret = tftf_cpu_on(mpidr,
-				(uintptr_t)realm_multi_cpu_payload_del_undel, 0);
-
-			if (ret != PSCI_E_SUCCESS) {
-				ERROR("CPU ON failed for 0x%llx\n",
-					(unsigned long long)mpidr);
-				return TEST_RESULT_FAIL;
-			}
-		}
-	}
-
-	VERBOSE("Waiting for secondary CPUs to turn off ...\n");
-	wait_for_non_lead_cpus();
-
-	VERBOSE("Done exiting.\n");
-
-	return reset_buffer_del_spm_rmi();
+/*
+ * Non secure call secure synchronously in parallel
+ * with all other cores in this test
+ */
+static test_result_t non_secure_call_secure_multi_cpu_sync(void)
+{
+	return wait_then_call(run_spm_direct_message);
 }
 
 /*
@@ -389,6 +325,142 @@
 			return TEST_RESULT_FAIL;
 		}
 	}
-
 	return TEST_RESULT_SUCCESS;
 }
+
+/*
+ * Non secure call realm synchronously in parallel
+ * with all other cores in this test
+ */
+static test_result_t non_secure_call_realm_multi_cpu_sync(void)
+{
+	return wait_then_call(realm_multi_cpu_payload_del_undel);
+}
+
+/*
+ * NS world communicate with S and RL worlds in series via SMC from a single core.
+ */
+test_result_t test_spm_rmm_serial_smc(void)
+{
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int  mpidr;
+
+	/**********************************************************************
+	 * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+	 **********************************************************************/
+	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+	/*
+	 * Randomize the initial state of the RMI granules to realm or non-secure
+	 */
+	if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/*
+	 * Preparation step:
+	 * Find another CPU than the lead CPU and power it on.
+	 */
+	mpidr = tftf_find_any_cpu_other_than(lead_mpid);
+	assert(mpidr != INVALID_MPID);
+
+	/*
+	 * Run SPM direct message call and RMI call in serial on a second core.
+	 * wait for core power cycle between each call.
+	 */
+	for (size_t i = 0; i < MAX_REPEATED_TEST; i++) {
+		/* SPM FF-A direct message call */
+		if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+		(uintptr_t)non_secure_call_secure_and_realm)) {
+			return TEST_RESULT_FAIL;
+		}
+		/* Wait for the target CPU to finish the test execution */
+		wait_for_core_to_turn_off(mpidr);
+	}
+
+	if (TEST_RESULT_SUCCESS != reset_buffer_del_spm_rmi()) {
+		return TEST_RESULT_FAIL;
+	}
+
+	VERBOSE("Done exiting.\n");
+
+	/**********************************************************************
+	 * All tests passed.
+	 **********************************************************************/
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Test function to let NS world communicate with S and RL worlds in parallel
+ * via SMC using multiple cores
+ */
+test_result_t test_spm_rmm_parallel_smc(void)
+{
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int cpu_node, mpidr;
+
+	/**********************************************************************
+	 * Check SPMC has ffa_version and expected FFA endpoints are deployed.
+	 **********************************************************************/
+	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+	/*
+	 * Randomize the initial state of the RMI granules to realm or non-secure
+	 */
+	if (init_buffer_del_spm_rmi() == TEST_RESULT_FAIL) {
+		return TEST_RESULT_FAIL;
+	}
+
+	/*
+	 * Main test to run both SPM and RMM or TRP together in parallel
+	 */
+	for (int i = 0; i < MAX_REPEATED_TEST; i++) {
+		VERBOSE("Main test(%d) to run both SPM and RMM or TRP together in parallel...\n", i);
+
+		/* Reinitialize all CPUs event */
+		for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
+			tftf_init_event(&cpu_booted[i]);
+		}
+
+		/*
+		 * Randomise the assignment of the CPU's to either SPM or RMI
+		 */
+		rand_cpu_spm_rmi();
+
+		/*
+		 * for each CPU we assign it randomly either spm or rmi test function
+		 */
+		for_each_cpu(cpu_node) {
+			mpidr = tftf_get_mpidr_from_node(cpu_node);
+			if (mpidr == lead_mpid) {
+				continue;
+			}
+			if (spm_rmi_test(mpidr) == 1) {
+				if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+					(uintptr_t)non_secure_call_secure_multi_cpu_sync)) {
+					return TEST_RESULT_FAIL;
+				}
+			} else {
+				if (TEST_RESULT_SUCCESS != run_on_cpu(mpidr,
+					(uintptr_t)non_secure_call_realm_multi_cpu_sync)) {
+					return TEST_RESULT_FAIL;
+				}
+			}
+		}
+
+		VERBOSE("Waiting for secondary CPUs to turn off ...\n");
+		wait_for_non_lead_cpus();
+	}
+
+	VERBOSE("Done exiting.\n");
+
+	return reset_buffer_del_spm_rmi();
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index b401409..f80ead6 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -14,7 +14,8 @@
 	  <testcase name="Realm payload Delegate and Undelegate" function="realm_delegate_undelegate" />
 	  <testcase name="Multi CPU Realm payload Delegate and Undelegate" function="realm_delundel_multi_cpu" />
 	  <testcase name="Testing delegation fails" function="realm_fail_del" />
-	  <testcase name="Realm testing with SPM tests" function="test_ffa_secondary_core_direct_realm_msg" />
+	  <testcase name="Test TFTF can call RMM/TRP and SPM serially on a single core" function="test_spm_rmm_serial_smc" />
+	  <testcase name="Test TFTF can call RMM/TRP and SPM parallelly on a multi core" function="test_spm_rmm_parallel_smc" />
   </testsuite>
 
 </testsuites>