fix(sve): discover the SVE vector length

Currently the (SPM) test that the SVE vectors are preserved
assumes that the SVE vector length is whatever the hard
coded maximum vector length we have at build time is,
currently 512 bits. The tests fill a buffer that can
hold the full set of maximally sized vectors, load it
into the registers, do a call and then read the values
back into a separate buffer and compare with the original
buffer. If the VL is less than the maximum then this
comparison will fail since only the subset of the read
buffer used by the actual vector length will be filled.

Fix this by reading the SVE vector length at runtime and
using that when verifying the read data rather than the
hard coded maximum value.

Increase the SVE test buffers to the maximum permitted by
the architecture. Configure ZCR_EL2.LEN to the maximum
permitted value (to the limit of the implementation and
EL3 constraint).

Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I1d96327d3423f2f8a3d7289ae02ab06a4bf9fde3
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
index 278dcf3..45481d7 100644
--- a/include/lib/extensions/sve.h
+++ b/include/lib/extensions/sve.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2022, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,4 +10,32 @@
 #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
+/*
+ * Max. vector length permitted by the architecture:
+ * SVE:	 2048 bits = 256 bytes
+ */
+#define SVE_VECTOR_LEN_BYTES		256
+#define SVE_NUM_VECTORS			32
+
+typedef uint8_t sve_vector_t[SVE_VECTOR_LEN_BYTES];
+
+#ifdef __aarch64__
+
+/* Returns the SVE implemented VL in bytes (constrained by ZCR_EL3.LEN) */
+static inline uint64_t sve_vector_length_get(void)
+{
+	uint64_t vl;
+
+	__asm__ volatile(
+		".arch_extension sve\n"
+		"rdvl %0, #1;"
+		".arch_extension nosve\n"
+		: "=r" (vl)
+	);
+
+	return vl;
+}
+
+#endif /* __aarch64__ */
+
+#endif /* SVE_H */
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index cb4fb4d..7a81e9c 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -14,6 +14,8 @@
 
 #include <ffa_helpers.h>
 
+#include <lib/extensions/sve.h>
+
 /* Hypervisor ID at physical FFA instance */
 #define HYP_ID          (0)
 /* SPMC ID */
@@ -94,17 +96,14 @@
 void dump_ffa_value(struct ffa_value ret);
 
 /*
- * Vector length:
+ * Max. 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/SVE registers with the content of the container v.
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 9359b8a..2e7f348 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -207,7 +207,6 @@
 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)
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 4924df4..2927fc2 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
@@ -7,6 +7,7 @@
 #include <cactus_test_cmds.h>
 #include <ffa_endpoints.h>
 #include <ffa_helpers.h>
+#include <lib/extensions/sve.h>
 #include <test_helpers.h>
 
 #define SENDER HYP_ID
@@ -23,6 +24,11 @@
 	return TEST_RESULT_SUCCESS;
 }
 
+#ifdef __aarch64__
+static sve_vector_t sve_vectors_input[SVE_NUM_VECTORS] __aligned(16);
+static sve_vector_t sve_vectors_output[SVE_NUM_VECTORS] __aligned(16);
+#endif
+
 /*
  * Tests that SIMD vectors are preserved during the context switches between
  * normal world and the secure world.
@@ -42,7 +48,7 @@
 	/* 0x11 is just a dummy value to be distinguished from the value in the
 	 * secure world. */
 	for (unsigned int num = 0U; num < SIMD_NUM_VECTORS; num++) {
-		memset(simd_vectors_send[num], 0x11 * num, sizeof(simd_vector_t));
+		memset(simd_vectors_send[num], 0x11 * (num+1), sizeof(simd_vector_t));
 	}
 	fill_simd_vector_regs(simd_vectors_send);
 
@@ -71,6 +77,10 @@
  */
 test_result_t test_sve_vectors_preserved(void)
 {
+#ifdef __aarch64__
+	uint64_t vl;
+	uint8_t *sve_vector;
+
 	SKIP_TEST_IF_SVE_NOT_SUPPORTED();
 
 	/**********************************************************************
@@ -78,17 +88,34 @@
 	 **********************************************************************/
 	CHECK_SPMC_TESTING_SETUP(1, 0, expected_sp_uuids);
 
-	sve_vector_t sve_vectors_send[SVE_NUM_VECTORS],
-		     sve_vectors_receive[SVE_NUM_VECTORS];
+	/*
+	 * Clear SVE vectors buffers used to compare the SVE state before calling
+	 * into the Swd compared to SVE state restored after returning to NWd.
+	 */
+	memset(sve_vectors_input, sizeof(sve_vector_t) * SVE_NUM_VECTORS, 0);
+	memset(sve_vectors_output, sizeof(sve_vector_t) * SVE_NUM_VECTORS, 0);
 
-	/* 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));
+	/* Set ZCR_EL2.LEN to implemented VL (constrained by EL3). */
+	write_zcr_el2(0xf);
+	isb();
+
+	/* Get the implemented VL. */
+	vl = sve_vector_length_get();
+
+	/* Fill each vector for the VL size with a fixed pattern. */
+	sve_vector = (uint8_t *) sve_vectors_input;
+	for (uint32_t vector_num = 0U; vector_num < SVE_NUM_VECTORS; vector_num++) {
+		memset(sve_vector, 0x11 * (vector_num + 1), vl);
+		sve_vector += vl;
 	}
 
-	fill_sve_vector_regs(sve_vectors_send);
+	/* Fill SVE vector registers with the buffer contents prepared above. */
+	fill_sve_vector_regs(sve_vectors_input);
 
+	/*
+	 * Call cactus secure partition which uses SIMD (and expect it doesn't
+	 * affect the normal world state on return).
+	 */
 	struct ffa_value ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
 
 	if (!is_ffa_direct_response(ret)) {
@@ -99,9 +126,14 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	read_sve_vector_regs(sve_vectors_receive);
+	/* Get the SVE vectors state after returning to normal world. */
+	read_sve_vector_regs(sve_vectors_output);
 
-	return fp_vector_compare((uint8_t *)sve_vectors_send,
-				 (uint8_t *)sve_vectors_receive,
-				 sizeof(sve_vector_t), SVE_NUM_VECTORS);
+	/* Compare to state before calling into secure world. */
+	return fp_vector_compare((uint8_t *)sve_vectors_input,
+				 (uint8_t *)sve_vectors_output,
+				 vl, SVE_NUM_VECTORS);
+#else
+	return TEST_RESULT_SKIPPED;
+#endif /* __aarch64__ */
 }