tftf(rme): intermittently switch to Realm while doing NS SVE ops

Interleave NS SVE operations with Realm SVE operations and check whether
SVE vectors are not affected.

This test also configures SVE op array and SVE vector length with random
value in NS and Realm for test each iteration.

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I7a9ba4bd0d298f187baa3048ec622eb97ec3d99f
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
index 2fdaa55..5907ef9 100644
--- a/include/lib/extensions/sve.h
+++ b/include/lib/extensions/sve.h
@@ -8,6 +8,7 @@
 #define SVE_H
 
 #include <arch.h>
+#include <stdlib.h> /* for rand() */
 
 #define fill_sve_helper(num) "ldr z"#num", [%0, #"#num", MUL VL];"
 #define read_sve_helper(num) "str z"#num", [%0, #"#num", MUL VL];"
@@ -27,6 +28,9 @@
 /* convert SVE VQ to bits */
 #define SVE_VQ_TO_BITS(vq)		(((vq) + 1U) << 7U)
 
+/* get a random SVE VQ b/w 0 to SVE_VQ_ARCH_MAX */
+#define SVE_GET_RANDOM_VQ		(rand() % (SVE_VQ_ARCH_MAX + 1))
+
 #ifndef __ASSEMBLY__
 
 typedef uint8_t sve_vector_t[SVE_VECTOR_LEN_BYTES];
diff --git a/include/runtime_services/host_realm_managment/host_shared_data.h b/include/runtime_services/host_realm_managment/host_shared_data.h
index cd19640..c852d89 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -53,7 +53,8 @@
 	REALM_REQ_FPU_CMP_CMD,
 	REALM_SVE_RDVL,
 	REALM_SVE_ID_REGISTERS,
-	REALM_SVE_PROBE_VL
+	REALM_SVE_PROBE_VL,
+	REALM_SVE_OPS
 };
 
 /*
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index c1c780b..13a063a 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -15,6 +15,7 @@
 bool test_realm_sve_rdvl(void);
 bool test_realm_sve_read_id_registers(void);
 bool test_realm_sve_probe_vl(void);
+bool test_realm_sve_ops(void);
 
 #endif /* REALM_TESTS_H */
 
diff --git a/realm/realm.mk b/realm/realm.mk
index e12f3e1..047dff8 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -43,7 +43,8 @@
 	lib/locks/${ARCH}/spinlock.S					\
 	lib/delay/delay.c						\
 	lib/extensions/fpu/fpu.c					\
-	lib/extensions/sve/aarch64/sve.c
+	lib/extensions/sve/aarch64/sve.c				\
+	lib/extensions/sve/aarch64/sve_helpers.S
 
 # TODO: Remove dependency on TFTF files.
 REALM_SOURCES	+=							\
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index f19dd3e..b13e0a1 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -102,6 +102,9 @@
 		case REALM_SVE_PROBE_VL:
 			test_succeed = test_realm_sve_probe_vl();
 			break;
+		case REALM_SVE_OPS:
+			test_succeed = test_realm_sve_ops();
+			break;
 		default:
 			realm_printf("%s() invalid cmd %u\n", __func__, cmd);
 			break;
diff --git a/realm/realm_sve.c b/realm/realm_sve.c
index 349b8d7..ed6c7c7 100644
--- a/realm/realm_sve.c
+++ b/realm/realm_sve.c
@@ -8,11 +8,18 @@
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
+#include <stdlib.h>
 #include <lib/extensions/sve.h>
 
 #include <host_realm_sve.h>
 #include <host_shared_data.h>
 
+#define RL_SVE_OP_ARRAYSIZE		512U
+#define SVE_TEST_ITERATIONS		4U
+
+static int rl_sve_op_1[RL_SVE_OP_ARRAYSIZE];
+static int rl_sve_op_2[RL_SVE_OP_ARRAYSIZE];
+
 /* Returns the maximum supported VL. This test is called only by sve Realm */
 bool test_realm_sve_rdvl(void)
 {
@@ -69,3 +76,36 @@
 
 	return true;
 }
+
+bool test_realm_sve_ops(void)
+{
+	int val, i;
+
+	assert(is_armv8_2_sve_present());
+
+	/* get at random value to do sve_subtract */
+	val = rand();
+	for (i = 0; i < RL_SVE_OP_ARRAYSIZE; i++) {
+		rl_sve_op_1[i] = val - i;
+		rl_sve_op_2[i] = 1;
+	}
+
+	for (i = 0; i < SVE_TEST_ITERATIONS; i++) {
+		/* Config Realm with random SVE length */
+		sve_config_vq(SVE_GET_RANDOM_VQ);
+
+		/* Perform SVE operations, without world switch */
+		sve_subtract_arrays(rl_sve_op_1, rl_sve_op_1, rl_sve_op_2,
+				    RL_SVE_OP_ARRAYSIZE);
+	}
+
+	/* Check result of SVE operations. */
+	for (i = 0; i < RL_SVE_OP_ARRAYSIZE; i++) {
+		if (rl_sve_op_1[i] != (val - i - SVE_TEST_ITERATIONS)) {
+			realm_printf("Realm: SVE ops failed\n");
+			return false;
+		}
+	}
+
+	return true;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c
index 554a497..4d5e075 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c
@@ -16,6 +16,12 @@
 #include <host_realm_sve.h>
 #include <host_shared_data.h>
 
+#define NS_SVE_OP_ARRAYSIZE		1024U
+#define SVE_TEST_ITERATIONS		50U
+
+static int ns_sve_op_1[NS_SVE_OP_ARRAYSIZE];
+static int ns_sve_op_2[NS_SVE_OP_ARRAYSIZE];
+
 /* Skip test if SVE is not supported in H/W or in RMI features */
 #define CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(_reg0)				\
 	do {									\
@@ -374,3 +380,87 @@
 
 	return rc;
 }
+
+/*
+ * Sends command to Realm to do SVE operations, while NS is also doing SVE
+ * operations.
+ * Returns:
+ *	false - On success
+ *	true  - On failure
+ */
+static bool callback_enter_realm(void)
+{
+	bool realm_rc;
+
+	realm_rc = host_enter_realm_execute(REALM_SVE_OPS, NULL,
+					    RMI_EXIT_HOST_CALL);
+	if (realm_rc != true) {
+		return true;
+	}
+
+	return false;
+}
+
+/* Intermittently switch to Realm while doing NS SVE ops */
+test_result_t host_sve_realm_check_vectors_operations(void)
+{
+	u_register_t rmi_feat_reg0;
+	test_result_t rc;
+	uint8_t sve_vq;
+	bool cb_err;
+	unsigned int i;
+	int val;
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+	CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+	sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+	rc = host_create_sve_realm_payload(true, sve_vq);
+	if (rc != TEST_RESULT_SUCCESS) {
+		return rc;
+	}
+
+	/* get at random value to do sve_subtract */
+	val = rand();
+	for (i = 0U; i < NS_SVE_OP_ARRAYSIZE; i++) {
+		ns_sve_op_1[i] = val - i;
+		ns_sve_op_2[i] = 1;
+	}
+
+	for (i = 0U; i < SVE_TEST_ITERATIONS; i++) {
+		/* Config NS world with random SVE length */
+		sve_config_vq(SVE_GET_RANDOM_VQ);
+
+		/* Perform SVE operations with intermittent calls to Realm */
+		cb_err = sve_subtract_arrays_interleaved(ns_sve_op_1,
+							 ns_sve_op_1,
+							 ns_sve_op_2,
+							 NS_SVE_OP_ARRAYSIZE,
+							 &callback_enter_realm);
+		if (cb_err) {
+			ERROR("Callback to realm failed\n");
+			rc = TEST_RESULT_FAIL;
+			goto rm_realm;
+		}
+	}
+
+	/* Check result of SVE operations. */
+	rc = TEST_RESULT_SUCCESS;
+	for (i = 0U; i < NS_SVE_OP_ARRAYSIZE; i++) {
+		if (ns_sve_op_1[i] != (val - i - SVE_TEST_ITERATIONS)) {
+			ERROR("SVE op failed at idx: %u, expected: 0x%x "
+			      "received: 0x%x\n", i,
+			      (val - i - SVE_TEST_ITERATIONS), ns_sve_op_1[i]);
+			rc = TEST_RESULT_FAIL;
+		}
+	}
+
+rm_realm:
+	if (!host_destroy_realm()) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return rc;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 4d4bf81..80d498d 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -47,5 +47,7 @@
 	  function="host_sve_realm_cmd_probe_vl" />
 	  <testcase name="Check whether RMM preserves NS ZCR_EL2 register"
 	  function="host_sve_realm_check_config_register" />
+	  <testcase name="Intermittently switch to Realm while doing NS SVE ops"
+	  function="host_sve_realm_check_vectors_operations" />
   </testsuite>
 </testsuites>