feat(sve): enable SVE tests in tftf

Adding two tests to check that floating point context is preserved.
1. Use SIMD instructions on SVE-enabled system.
2. Use SVE instruction on a full-length vectors.
Both tests check that floating point context is preserved after
returning from the secure world.

Signed-off-by: Max Shvetsov <maksims.svecovs@arm.com>
Change-Id: Idccff7c3f1658cc66b64e144cc00cda6e0aeea50
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 3ee2b53..9c5f6e4 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -107,6 +107,14 @@
 		}								\
 	} while (0)
 
+#define SKIP_TEST_IF_SVE_NOT_SUPPORTED()					\
+	do {									\
+		if (!is_armv8_2_sve_present()) {				\
+			tftf_testcase_printf("SVE not supported\n");		\
+			return TEST_RESULT_SKIPPED;				\
+		}								\
+	} while (0)
+
 #define SKIP_TEST_IF_ECV_NOT_SELF_SYNC()					\
 	do {									\
 		if (get_armv8_6_ecv_support() !=				\
@@ -228,6 +236,7 @@
 
 #define CHECK_SPMC_TESTING_SETUP(ffa_major, ffa_minor, expected_uuids)		\
 	do {									\
+		SKIP_TEST_IF_AARCH32();						\
 		const size_t expected_uuids_size =				\
 			 sizeof(expected_uuids) / sizeof(struct ffa_uuid);	\
 		test_result_t ret = check_spmc_testing_set_up(			\
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
new file mode 100644
index 0000000..278dcf3
--- /dev/null
+++ b/include/lib/extensions/sve.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SVE_H
+#define SVE_H
+
+#define fill_sve_helper(num) "ldr z"#num", [%0, #"#num", MUL VL];"
+#define read_sve_helper(num) "str z"#num", [%0, #"#num", MUL VL];"
+
+#endif /* SVE_H */
\ No newline at end of file
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 685e732..5ccf395 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -83,22 +83,29 @@
 /*
  * Vector length:
  * SIMD: 128 bits = 16 bytes
+ * SVE:	 512 bits = 64 bytes
  */
 #define SIMD_VECTOR_LEN_BYTES		16
+#define SVE_VECTOR_LEN_BYTES		64
+
 #define SIMD_NUM_VECTORS		32
+#define SVE_NUM_VECTORS			32
 typedef uint8_t simd_vector_t[SIMD_VECTOR_LEN_BYTES];
+typedef uint8_t sve_vector_t[SVE_VECTOR_LEN_BYTES];
 
 /*
- * Fills SIMD registers with the content of the container v.
- * Number of vectors is assumed to be SIMD_NUM_VECTORS.
+ * Fills SIMD/SVE registers with the content of the container v.
+ * Number of vectors is assumed to be SIMD/SVE_NUM_VECTORS.
  */
 void fill_simd_vector_regs(const simd_vector_t v[SIMD_NUM_VECTORS]);
+void fill_sve_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS]);
 
 /*
- * Reads contents of SIMD registers into the provided container v.
- * Number of vectors is assumed to be SIMD_NUM_VECTORS.
+ * Reads contents of SIMD/SVE registers into the provided container v.
+ * Number of vectors is assumed to be SIMD/SVE_NUM_VECTORS.
  */
 void read_simd_vector_regs(simd_vector_t v[SIMD_NUM_VECTORS]);
+void read_sve_vector_regs(sve_vector_t v[SVE_NUM_VECTORS]);
 
 bool check_spmc_execution_level(void);
 
diff --git a/tftf/tests/extensions/sve/test_sve.c b/tftf/tests/extensions/sve/test_sve.c
index 235e2b8..eabc0de 100644
--- a/tftf/tests/extensions/sve/test_sve.c
+++ b/tftf/tests/extensions/sve/test_sve.c
@@ -8,6 +8,7 @@
 #include <arch_helpers.h>
 #include <debug.h>
 #include <stdlib.h>
+#include <test_helpers.h>
 #include <tftf_lib.h>
 
 #include "./test_sve.h"
@@ -32,11 +33,7 @@
  */
 test_result_t test_sve_support(void)
 {
-	/* Check if SVE is implemented and usable */
-	if (is_armv8_2_sve_present() == false) {
-		tftf_testcase_printf("SVE support absent\n");
-		return TEST_RESULT_SKIPPED;
-	}
+	SKIP_TEST_IF_SVE_NOT_SUPPORTED();
 
 	for (int i = 0; i < SVE_ARRAYSIZE; i++) {
 		/* Generate a random number between 200 and 299 */
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index e2d3392..e2c7361 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -7,12 +7,17 @@
 #include <debug.h>
 #include <ffa_endpoints.h>
 #include <ffa_svc.h>
+#include <lib/extensions/sve.h>
 #include <spm_common.h>
 #include <xlat_tables_v2.h>
 
 #define __STR(x) #x
 #define STR(x) __STR(x)
-#define SIMD_TWO_VECTORS_BYTES_STR	(2 * SIMD_VECTOR_LEN_BYTES)
+
+#define fill_simd_helper(num1, num2) "ldp q"#num1", q"#num2",\
+	[%0], #"STR(2 * SIMD_VECTOR_LEN_BYTES)";"
+#define read_simd_helper(num1, num2) "stp q"#num1", q"#num2",\
+	[%0], #"STR(2 * SIMD_VECTOR_LEN_BYTES)";"
 
 /**
  * Helper to log errors after FF-A calls.
@@ -59,27 +64,26 @@
 
 	return false;
 }
-
 void fill_simd_vector_regs(const simd_vector_t v[SIMD_NUM_VECTORS])
 {
 #ifdef __aarch64__
 	__asm__ volatile(
-		"ldp q0, q1, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q2, q3, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q4, q5, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q6, q7, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q8, q9, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q10, q11, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q12, q13, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q14, q15, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q16, q17, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q18, q19, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q20, q21, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q22, q23, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q24, q25, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q26, q27, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q28, q29, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"ldp q30, q31, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
+		fill_simd_helper(0, 1)
+		fill_simd_helper(2, 3)
+		fill_simd_helper(4, 5)
+		fill_simd_helper(6, 7)
+		fill_simd_helper(8, 9)
+		fill_simd_helper(10, 11)
+		fill_simd_helper(12, 13)
+		fill_simd_helper(14, 15)
+		fill_simd_helper(16, 17)
+		fill_simd_helper(18, 19)
+		fill_simd_helper(20, 21)
+		fill_simd_helper(22, 23)
+		fill_simd_helper(24, 25)
+		fill_simd_helper(26, 27)
+		fill_simd_helper(28, 29)
+		fill_simd_helper(30, 31)
 		"sub %0, %0, #" STR(SIMD_NUM_VECTORS * SIMD_VECTOR_LEN_BYTES) ";"
 		: : "r" (v));
 #endif
@@ -89,29 +93,113 @@
 {
 #ifdef __aarch64__
 	memset(v, 0, sizeof(simd_vector_t) * SIMD_NUM_VECTORS);
-
 	__asm__ volatile(
-		"stp q0, q1, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q2, q3, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q4, q5, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q6, q7, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q8, q9, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q10, q11, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q12, q13, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q14, q15, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q16, q17, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q18, q19, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q20, q21, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q22, q23, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q24, q25, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q26, q27, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q28, q29, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
-		"stp q30, q31, [%0], #" STR(SIMD_TWO_VECTORS_BYTES_STR) ";"
+		read_simd_helper(0, 1)
+		read_simd_helper(2, 3)
+		read_simd_helper(4, 5)
+		read_simd_helper(6, 7)
+		read_simd_helper(8, 9)
+		read_simd_helper(10, 11)
+		read_simd_helper(12, 13)
+		read_simd_helper(14, 15)
+		read_simd_helper(16, 17)
+		read_simd_helper(18, 19)
+		read_simd_helper(20, 21)
+		read_simd_helper(22, 23)
+		read_simd_helper(24, 25)
+		read_simd_helper(26, 27)
+		read_simd_helper(28, 29)
+		read_simd_helper(30, 31)
 		"sub %0, %0, #" STR(SIMD_NUM_VECTORS * SIMD_VECTOR_LEN_BYTES) ";"
 		: : "r" (v));
 #endif
 }
 
+void fill_sve_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS])
+{
+#ifdef __aarch64__
+	__asm__ volatile(
+		".arch_extension sve\n"
+		fill_sve_helper(0)
+		fill_sve_helper(1)
+		fill_sve_helper(2)
+		fill_sve_helper(3)
+		fill_sve_helper(4)
+		fill_sve_helper(5)
+		fill_sve_helper(6)
+		fill_sve_helper(7)
+		fill_sve_helper(8)
+		fill_sve_helper(9)
+		fill_sve_helper(10)
+		fill_sve_helper(11)
+		fill_sve_helper(12)
+		fill_sve_helper(13)
+		fill_sve_helper(14)
+		fill_sve_helper(15)
+		fill_sve_helper(16)
+		fill_sve_helper(17)
+		fill_sve_helper(18)
+		fill_sve_helper(19)
+		fill_sve_helper(20)
+		fill_sve_helper(21)
+		fill_sve_helper(22)
+		fill_sve_helper(23)
+		fill_sve_helper(24)
+		fill_sve_helper(25)
+		fill_sve_helper(26)
+		fill_sve_helper(27)
+		fill_sve_helper(28)
+		fill_sve_helper(29)
+		fill_sve_helper(30)
+		fill_sve_helper(31)
+		".arch_extension nosve\n"
+		: : "r" (v));
+#endif
+}
+
+void read_sve_vector_regs(sve_vector_t v[SVE_NUM_VECTORS])
+{
+#ifdef __aarch64__
+	memset(v, 0, sizeof(sve_vector_t) * SVE_NUM_VECTORS);
+	__asm__ volatile(
+		".arch_extension sve\n"
+		read_sve_helper(0)
+		read_sve_helper(1)
+		read_sve_helper(2)
+		read_sve_helper(3)
+		read_sve_helper(4)
+		read_sve_helper(5)
+		read_sve_helper(6)
+		read_sve_helper(7)
+		read_sve_helper(8)
+		read_sve_helper(9)
+		read_sve_helper(10)
+		read_sve_helper(11)
+		read_sve_helper(12)
+		read_sve_helper(13)
+		read_sve_helper(14)
+		read_sve_helper(15)
+		read_sve_helper(16)
+		read_sve_helper(17)
+		read_sve_helper(18)
+		read_sve_helper(19)
+		read_sve_helper(20)
+		read_sve_helper(21)
+		read_sve_helper(22)
+		read_sve_helper(23)
+		read_sve_helper(24)
+		read_sve_helper(25)
+		read_sve_helper(26)
+		read_sve_helper(27)
+		read_sve_helper(28)
+		read_sve_helper(29)
+		read_sve_helper(30)
+		read_sve_helper(31)
+		".arch_extension nosve\n"
+		: : "r" (v));
+#endif
+}
+
 /*
  * check_spmc_execution_level
  *
diff --git a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
index f57fa24..655f9d9 100644
--- a/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
+++ b/tftf/tests/runtime_services/secure_service/test_spm_cpu_features.c
@@ -14,15 +14,11 @@
 
 static const struct ffa_uuid expected_sp_uuids[] = { {PRIMARY_UUID} };
 
-static test_result_t simd_vector_compare(simd_vector_t a[SIMD_NUM_VECTORS],
-					 simd_vector_t b[SIMD_NUM_VECTORS])
+static test_result_t fp_vector_compare(uint8_t *a, uint8_t *b,
+	size_t vector_size, uint8_t vectors_num)
 {
-	for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
-		if (memcmp(a[num], b[num], sizeof(simd_vector_t)) != 0) {
-			ERROR("Vectors not equal: a:0x%llx b:0x%llx\n",
-				(uint64_t)a[num][0], (uint64_t)b[num][0]);
-			return TEST_RESULT_FAIL;
-		}
+	if (memcmp(a, b, vector_size * vectors_num) != 0) {
+		return TEST_RESULT_FAIL;
 	}
 	return TEST_RESULT_SUCCESS;
 }
@@ -35,8 +31,6 @@
  */
 test_result_t test_simd_vectors_preserved(void)
 {
-	SKIP_TEST_IF_AARCH32();
-
 	/**********************************************************************
 	 * Verify that FFA is there and that it has the correct version.
 	 **********************************************************************/
@@ -50,7 +44,6 @@
 	for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
 		memset(simd_vectors_send[num], 0x11 * num, sizeof(simd_vector_t));
 	}
-
 	fill_simd_vector_regs(simd_vectors_send);
 
 	smc_ret_values ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
@@ -65,5 +58,50 @@
 
 	read_simd_vector_regs(simd_vectors_receive);
 
-	return simd_vector_compare(simd_vectors_send, simd_vectors_receive);
+	return fp_vector_compare((uint8_t *)simd_vectors_send,
+				 (uint8_t *)simd_vectors_receive,
+				 sizeof(simd_vector_t), SIMD_NUM_VECTORS);
+}
+
+/*
+ * Tests that SVE vectors are preserved during the context switches between
+ * normal world and the secure world.
+ * Fills the SVE vectors with known values, requests SP to fill the vectors
+ * with a different values, checks that the context is restored on return.
+ */
+test_result_t test_sve_vectors_preserved(void)
+{
+	SKIP_TEST_IF_SVE_NOT_SUPPORTED();
+
+	/**********************************************************************
+	 * Verify that FFA is there and that it has the correct version.
+	 **********************************************************************/
+	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
+
+	sve_vector_t sve_vectors_send[SVE_NUM_VECTORS],
+		     sve_vectors_receive[SVE_NUM_VECTORS];
+
+	/* 0x11 is just a dummy value to be distinguished from the value in the
+	 * secure world. */
+	for (unsigned int num = 0U; num < SVE_NUM_VECTORS; num++) {
+		memset(sve_vectors_send[num], 0x11 * num, sizeof(sve_vector_t));
+	}
+
+	fill_sve_vector_regs(sve_vectors_send);
+
+	smc_ret_values ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
+
+	if (!is_ffa_direct_response(ret)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	if (cactus_get_response(ret) == CACTUS_ERROR) {
+		return TEST_RESULT_FAIL;
+	}
+
+	read_sve_vector_regs(sve_vectors_receive);
+
+	return fp_vector_compare((uint8_t *)sve_vectors_send,
+				 (uint8_t *)sve_vectors_receive,
+				 sizeof(sve_vector_t), SVE_NUM_VECTORS);
 }
diff --git a/tftf/tests/tests-spm.xml b/tftf/tests/tests-spm.xml
index cafbc46..ea76778 100644
--- a/tftf/tests/tests-spm.xml
+++ b/tftf/tests/tests-spm.xml
@@ -70,6 +70,8 @@
              description="Validate context switch between NWd and SWd" >
      <testcase name="Check that SIMD registers context is preserved"
                function="test_simd_vectors_preserved" />
+     <testcase name="Check that SVE registers context is preserved"
+               function="test_sve_vectors_preserved" />
   </testsuite>
 
    <testsuite name="FF-A Interrupt"