Adding tests for multi CPU delegation and fail conditions

This testing patch has the following test scenarios for realm payload:

1. Query the RMI Version on a single CPU.
2. Multi CPU version query.
3. Test to delegate and undelegate a buffer using RMI Delegate and
Undelegate commands.
4. Multi CPU delegation with granules that are randomly initialized
Each CPU is assigned its own set of granules to avoid locking issues.
5. Fail scenarios for delegation including double delegation of a
granule and submission of a misaligned address.

Signed-off-by: Mark Dykes <mark.dykes@arm.com>
Change-Id: Ib09995568f229d3adb269c2f06d123103ce596cc
diff --git a/include/runtime_services/realm_payload/realm_payload_test.h b/include/runtime_services/realm_payload/realm_payload_test.h
index 27918bc..5ce8f8e 100644
--- a/include/runtime_services/realm_payload/realm_payload_test.h
+++ b/include/runtime_services/realm_payload/realm_payload_test.h
@@ -26,7 +26,7 @@
 #define RMI_FNUM_VERSION_REQ		U(0)
 
 #define RMI_FNUM_GRAN_NS_REALM		U(1)
-#define RMI_FNUM_GRAN_REALM_NS		U(2)
+#define RMI_FNUM_GRAN_REALM_NS		U(0x10)
 
 /********************************************************************************/
 
@@ -40,9 +40,13 @@
 #define RMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
 #define RMI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
 
-#define GRANULE_SIZE 			4096
+#define NUM_GRANULES			5
+#define NUM_RANDOM_ITERATIONS		7
+#define GRANULE_SIZE			4096
+
+#define B_DELEGATED			0
+#define B_UNDELEGATED			1
 
 u_register_t realm_version(void);
 u_register_t realm_granule_delegate(uintptr_t);
 u_register_t realm_granule_undelegate(uintptr_t);
-test_result_t realm_multi_cpu_payload_test(void);
diff --git a/tftf/tests/runtime_services/realm_payload/realm_payload_test.c b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
index 40cdb60..ce5ff07 100644
--- a/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
+++ b/tftf/tests/runtime_services/realm_payload/realm_payload_test.c
@@ -4,12 +4,20 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <stdlib.h>
+
 #include <arch_features.h>
 #include <plat_topology.h>
 #include <power_management.h>
+#include <platform.h>
 #include <runtime_services/realm_payload/realm_payload_test.h>
 
-static char bufferdelegate[GRANULE_SIZE] __aligned(GRANULE_SIZE);
+static test_result_t realm_multi_cpu_payload_test(void);
+static test_result_t realm_multi_cpu_payload_del_undel(void);
+
+/* 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];
 
 /*
  * Overall test for realm payload in three sections:
@@ -19,8 +27,35 @@
  * version information from all CPU's in system
  * 3. Delegate and Undelegate Non-Secure granule via
  * SMC call to realm payload
+ * 4. Multi CPU delegation where random assignment of states
+ * (realm, non-secure)is assigned to a set of granules.
+ * Each CPU is given a number of granules to delegate in
+ * parallel with the other CPU's
+ * 5. Fail testing of delegation parameters such as
+ * attempting to perform a delegation on the same granule
+ * twice and then testing a misaligned address
  */
 
+test_result_t init_buffer_del(void)
+{
+	u_register_t retrmm;
+
+	for (int i = 0; i < (NUM_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+		if ((rand() % 2) == 0) {
+			retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+			bufferstate[i] = B_DELEGATED;
+			if (retrmm != 0UL) {
+				tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+				return TEST_RESULT_FAIL;
+			}
+		} else {
+			bufferstate[i] = B_UNDELEGATED;
+		}
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+
 /*
  * Single CPU version check function
  */
@@ -122,7 +157,7 @@
 	return TEST_RESULT_SUCCESS;
 }
 
-test_result_t realm_multi_cpu_payload_test(void)
+static test_result_t realm_multi_cpu_payload_test(void)
 {
 	u_register_t retrmm = realm_version();
 
@@ -132,3 +167,119 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+/*
+ * Select all CPU's to randomly delegate/undelegate
+ * granule pages to stress the delegate mechanism
+ */
+test_result_t realm_delundel_multi_cpu(void)
+{
+	u_register_t lead_mpid, target_mpid;
+	int cpu_node;
+	long long ret;
+
+	if (get_armv9_2_feat_rme_support() == 0U) {
+		return TEST_RESULT_SKIPPED;
+	}
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	if (init_buffer_del() == TEST_RESULT_FAIL) {
+		return TEST_RESULT_FAIL;
+	}
+
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		ret = tftf_cpu_on(target_mpid,
+			(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)target_mpid);
+			return TEST_RESULT_FAIL;
+		}
+
+	}
+
+	for_each_cpu(cpu_node) {
+		target_mpid = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+				PSCI_STATE_OFF) {
+			continue;
+		}
+	}
+
+	ret = TEST_RESULT_SUCCESS;
+	return ret;
+}
+
+/*
+ * Multi CPU testing of delegate and undelegate of granules
+ * The granules are first randomly initialized to either realm or non secure
+ * using the function init_buffer_del and then the function below
+ * assigns NUM_GRANULES to each CPU for delegation or undelgation
+ * depending upon the initial state
+ */
+static test_result_t realm_multi_cpu_payload_del_undel(void)
+{
+	u_register_t retrmm;
+	unsigned int cpu_node;
+
+	cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+	for (int i = 0; i < NUM_GRANULES; i++) {
+		if (bufferstate[((cpu_node * NUM_GRANULES) + i)] == B_UNDELEGATED) {
+			retrmm = realm_granule_delegate((u_register_t)
+					&bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+			bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_DELEGATED;
+		} else {
+			retrmm = realm_granule_undelegate((u_register_t)
+					&bufferdelegate[((cpu_node * NUM_GRANULES) + i) * GRANULE_SIZE]);
+			bufferstate[((cpu_node * NUM_GRANULES) + i)] = B_UNDELEGATED;
+		}
+		if (retrmm != 0UL) {
+			tftf_testcase_printf("Delegate operation returns fail, %lx\n", retrmm);
+			return TEST_RESULT_FAIL;
+		}
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+/*Fail testing of delegation process. The first is an error expected
+ * for processing the same granule twice and the second is submission of
+ * a misaligned address
+ */
+
+test_result_t realm_fail_del(void)
+{
+	u_register_t retrmm;
+
+	retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+	retrmm = realm_granule_delegate((u_register_t)&bufferdelegate[0]);
+
+	if (retrmm == 0UL) {
+		tftf_testcase_printf
+			("Delegate operation does not fail as expected for double delegation, %lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	retrmm = realm_granule_undelegate((u_register_t)&bufferdelegate[1]);
+
+	if (retrmm == 0UL) {
+		tftf_testcase_printf
+			("Delegate operation does not return fail for misaligned address, %lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 8acdc2e..b458db6 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -12,6 +12,8 @@
 	  <testcase name="Realm payload boot" function="realm_version_single_cpu" />
 	  <testcase name="Realm payload multi CPU request" function="realm_version_multi_cpu" />
 	  <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" />
   </testsuite>
 
 </testsuites>