Merge changes I3fc755f7,I861892f2,I3fa064c7,I10ae5487,I42955f80, ...
* changes:
test(rme): check various SIMD state preserved across NS/RL switch
fix(rme): enhance fpu state verification test
feat(sve): add helper routines to read, write, compare SVE registers
feat(fpu): add helper routines to read, write, compare FPU registers
fix(sve): represent sve Z0-31 registers as array of bytes
test(rme): check if non SVE realm gets undefined abort
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 39461d5..4b9c33e 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -614,8 +614,9 @@
/* FEAT_HCX HCRX_EL2 */
DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2)
-/* Control floating point behaviour */
+/* Floating point control and status register */
DEFINE_RENAME_SYSREG_RW_FUNCS(fpcr, FPCR)
+DEFINE_RENAME_SYSREG_RW_FUNCS(fpsr, FPSR)
/* ID_AA64ISAR2_EL1 */
DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64isar2_el1, ID_AA64ISAR2_EL1)
diff --git a/include/lib/extensions/fpu.h b/include/lib/extensions/fpu.h
index d7b4f99..1a82818 100644
--- a/include/lib/extensions/fpu.h
+++ b/include/lib/extensions/fpu.h
@@ -11,44 +11,35 @@
#define FPU_Q_SIZE 16U
#define FPU_Q_COUNT 32U
-/* These defines are needed by assembly code to access FPU registers. */
-#define FPU_OFFSET_Q 0U
-#define FPU_OFFSET_FPSR (FPU_Q_SIZE * FPU_Q_COUNT)
-#define FPU_OFFSET_FPCR (FPU_OFFSET_FPSR + 8)
-
#ifndef __ASSEMBLER__
#include <stdbool.h>
#include <stdint.h>
-typedef struct fpu_reg_state {
- uint8_t q[FPU_Q_COUNT][FPU_Q_SIZE];
- unsigned long fpsr;
+typedef uint8_t fpu_q_reg_t[FPU_Q_SIZE] __aligned(16);
+typedef struct fpu_cs_regs {
unsigned long fpcr;
-} fpu_reg_state_t __aligned(16);
+ unsigned long fpsr;
+} fpu_cs_regs_t __aligned(16);
-/*
- * Read and compare FPU state registers with provided template values in parameters.
- */
-bool fpu_state_compare_template(fpu_reg_state_t *fpu);
+typedef struct fpu_state {
+ fpu_q_reg_t q_regs[FPU_Q_COUNT];
+ fpu_cs_regs_t cs_regs;
+} fpu_state_t __aligned(16);
-/*
- * Fill the template with random values and copy it to
- * FPU state registers(SIMD vectors, FPCR, FPSR).
- */
-void fpu_state_fill_regs_and_template(fpu_reg_state_t *fpu);
+void fpu_cs_regs_write(const fpu_cs_regs_t *cs_regs);
+void fpu_cs_regs_write_rand(fpu_cs_regs_t *cs_regs);
+void fpu_cs_regs_read(fpu_cs_regs_t *cs_regs);
+int fpu_cs_regs_compare(const fpu_cs_regs_t *s1, const fpu_cs_regs_t *s2);
-/*
- * This function populates the provided FPU structure with the provided template
- * regs_val for all the 32 FPU/SMID registers, and the status registers FPCR/FPSR
- */
-void fpu_state_set(fpu_reg_state_t *vec,
- uint8_t regs_val);
+void fpu_q_regs_write_rand(fpu_q_reg_t q_regs[FPU_Q_COUNT]);
+void fpu_q_regs_read(fpu_q_reg_t q_regs[FPU_Q_COUNT]);
+int fpu_q_regs_compare(const fpu_q_reg_t s1[FPU_Q_COUNT],
+ const fpu_q_reg_t s2[FPU_Q_COUNT]);
-/*
- * This function prints the content of the provided FPU structure
- */
-void fpu_state_print(fpu_reg_state_t *vec);
+void fpu_state_write_rand(fpu_state_t *fpu_state);
+void fpu_state_read(fpu_state_t *fpu_state);
+int fpu_state_compare(const fpu_state_t *s1, const fpu_state_t *s2);
#endif /* __ASSEMBLER__ */
#endif /* FPU_H */
diff --git a/include/lib/extensions/sve.h b/include/lib/extensions/sve.h
index 60432a5..4458001 100644
--- a/include/lib/extensions/sve.h
+++ b/include/lib/extensions/sve.h
@@ -13,36 +13,66 @@
#define fill_sve_helper(num) "ldr z"#num", [%0, #"#num", MUL VL];"
#define read_sve_helper(num) "str z"#num", [%0, #"#num", MUL VL];"
+#define fill_sve_p_helper(num) "ldr p"#num", [%0, #"#num", MUL VL];"
+#define read_sve_p_helper(num) "str p"#num", [%0, #"#num", MUL VL];"
+
/*
* Max. vector length permitted by the architecture:
* SVE: 2048 bits = 256 bytes
*/
-#define SVE_VECTOR_LEN_BYTES 256
-#define SVE_NUM_VECTORS 32
+#define SVE_VECTOR_LEN_BYTES (256U)
+#define SVE_NUM_VECTORS (32U)
+
+/* Max size of one predicate register is 1/8 of Z register */
+#define SVE_P_REG_LEN_BYTES (SVE_VECTOR_LEN_BYTES / 8U)
+#define SVE_NUM_P_REGS (16U)
+
+/* Max size of one FFR register is 1/8 of Z register */
+#define SVE_FFR_REG_LEN_BYTES (SVE_VECTOR_LEN_BYTES / 8U)
+#define SVE_NUM_FFR_REGS (1U)
#define SVE_VQ_ARCH_MIN (0U)
-#define SVE_VQ_ARCH_MAX ((1 << ZCR_EL2_SVE_VL_WIDTH) - 1)
+#define SVE_VQ_ARCH_MAX ((1U << ZCR_EL2_SVE_VL_WIDTH) - 1U)
/* convert SVE VL in bytes to VQ */
-#define SVE_VL_TO_VQ(vl_bytes) (((vl_bytes) >> 4U) - 1)
+#define SVE_VL_TO_VQ(vl_bytes) (((vl_bytes) >> 4U) - 1U)
/* convert SVE VQ to bits */
#define SVE_VQ_TO_BITS(vq) (((vq) + 1U) << 7U)
/* convert SVE VQ to bytes */
-#define SVE_VQ_TO_BYTES(vq) (SVE_VQ_TO_BITS(vq) / 8)
+#define SVE_VQ_TO_BYTES(vq) (SVE_VQ_TO_BITS(vq) / 8U)
/* get a random SVE VQ b/w 0 to SVE_VQ_ARCH_MAX */
-#define SVE_GET_RANDOM_VQ (rand() % (SVE_VQ_ARCH_MAX + 1))
+#define SVE_GET_RANDOM_VQ (rand() % (SVE_VQ_ARCH_MAX + 1U))
#ifndef __ASSEMBLY__
-typedef uint8_t sve_vector_t[SVE_VECTOR_LEN_BYTES];
+typedef uint8_t sve_z_regs_t[SVE_NUM_VECTORS * SVE_VECTOR_LEN_BYTES]
+ __aligned(16);
+typedef uint8_t sve_p_regs_t[SVE_NUM_P_REGS * SVE_P_REG_LEN_BYTES]
+ __aligned(16);
+typedef uint8_t sve_ffr_regs_t[SVE_NUM_FFR_REGS * SVE_FFR_REG_LEN_BYTES]
+ __aligned(16);
void sve_config_vq(uint8_t sve_vq);
uint32_t sve_probe_vl(uint8_t sve_max_vq);
-void sve_fill_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS]);
-void sve_read_vector_regs(sve_vector_t v[SVE_NUM_VECTORS]);
+
+void sve_z_regs_write(const sve_z_regs_t *z_regs);
+void sve_z_regs_write_rand(sve_z_regs_t *z_regs);
+void sve_z_regs_read(sve_z_regs_t *z_regs);
+uint64_t sve_z_regs_compare(const sve_z_regs_t *s1, const sve_z_regs_t *s2);
+
+void sve_p_regs_write(const sve_p_regs_t *p_regs);
+void sve_p_regs_write_rand(sve_p_regs_t *p_regs);
+void sve_p_regs_read(sve_p_regs_t *p_regs);
+uint64_t sve_p_regs_compare(const sve_p_regs_t *s1, const sve_p_regs_t *s2);
+
+void sve_ffr_regs_write(const sve_ffr_regs_t *ffr_regs);
+void sve_ffr_regs_write_rand(sve_ffr_regs_t *ffr_regs);
+void sve_ffr_regs_read(sve_ffr_regs_t *ffr_regs);
+uint64_t sve_ffr_regs_compare(const sve_ffr_regs_t *s1,
+ const sve_ffr_regs_t *s2);
/* Assembly routines */
bool sve_subtract_arrays_interleaved(int *dst_array, int *src_array1,
@@ -55,7 +85,7 @@
#ifdef __aarch64__
/* Returns the SVE implemented VL in bytes (constrained by ZCR_EL3.LEN) */
-static inline uint64_t sve_vector_length_get(void)
+static inline uint64_t sve_rdvl_1(void)
{
uint64_t vl;
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 4cb3c0a..c8f9238 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -53,6 +53,8 @@
REALM_SVE_PROBE_VL,
REALM_SVE_OPS,
REALM_SVE_FILL_REGS,
+ REALM_SVE_CMP_REGS,
+ REALM_SVE_UNDEF_ABORT,
REALM_PAUTH_SET_CMD,
REALM_PAUTH_CHECK_CMD,
REALM_PAUTH_FAULT
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 48471bc..0c8ade1 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -99,18 +99,6 @@
uint32_t arg);
void dump_ffa_value(struct ffa_value ret);
-/*
- * Fills SIMD/SVE registers with the content of the container v.
- * Number of vectors is assumed to be SIMD/SVE_NUM_VECTORS.
- */
-void fill_sve_vector_regs(const sve_vector_t v[SVE_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_sve_vector_regs(sve_vector_t v[SVE_NUM_VECTORS]);
-
bool check_spmc_execution_level(void);
unsigned int get_ffa_feature_test_target(const struct ffa_features_test **test_target);
diff --git a/lib/extensions/fpu/fpu.c b/lib/extensions/fpu/fpu.c
index b08e64c..34cbafb 100644
--- a/lib/extensions/fpu/fpu.c
+++ b/lib/extensions/fpu/fpu.c
@@ -3,6 +3,8 @@
*
* SPDX-License-Identifier: BSD-3-Clause
*/
+
+#include <arch_helpers.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -18,21 +20,9 @@
#define read_simd_helper(num1, num2) "stp q"#num1", q"#num2",\
[%0], #"STR(2 * FPU_Q_SIZE)";"
-static fpu_reg_state_t g_fpu_read;
-
-static void read_fpu_state_registers(fpu_reg_state_t *fpu_template_in)
+/* Read FPU Q[0-31] and strore it in 'q_regs' */
+void fpu_q_regs_read(fpu_q_reg_t q_regs[FPU_Q_COUNT])
{
-#ifdef __aarch64__
-
- u_register_t fpsr;
- u_register_t fpcr;
-
- /* Read current FPCR FPSR and write to template. */
- __asm__ volatile ("mrs %0, fpsr\n" : "=r" (fpsr));
- __asm__ volatile ("mrs %0, fpcr\n" : "=r" (fpcr));
- fpu_template_in->fpsr = fpsr;
- fpu_template_in->fpcr = fpcr;
-
__asm__ volatile(
read_simd_helper(0, 1)
read_simd_helper(2, 3)
@@ -51,39 +41,12 @@
read_simd_helper(28, 29)
read_simd_helper(30, 31)
"sub %0, %0, #" STR(FPU_Q_COUNT * FPU_Q_SIZE) ";"
- : : "r" (fpu_template_in->q));
-#endif
+ : : "r" (q_regs));
}
-void fpu_state_fill_regs_and_template(fpu_reg_state_t *fpu_template_in)
+/* Write FPU Q[0-31] registers passed in 'q_regs' */
+static void fpu_q_regs_write(const fpu_q_reg_t q_regs[FPU_Q_COUNT])
{
- u_register_t fpsr;
- u_register_t fpcr;
- u_register_t temp;
-
- temp = rand();
- (void)memset((void *)fpu_template_in, 0, sizeof(fpu_reg_state_t));
-
- /*
- * Write random value to FPCR FPSR.
- * Note write will be ignored for reserved bits.
- */
- __asm__ volatile ("msr fpsr, %0\n" : : "r" (temp));
- __asm__ volatile ("msr fpcr, %0\n" : : "r" (temp));
-
- /*
- * Read back current FPCR FPSR and write to template,
- */
- __asm__ volatile ("mrs %0, fpsr\n" : "=r" (fpsr));
- __asm__ volatile ("mrs %0, fpcr\n" : "=r" (fpcr));
- fpu_template_in->fpsr = fpsr;
- fpu_template_in->fpcr = fpcr;
-
- for (unsigned int num = 0U; num < FPU_Q_COUNT; num++) {
- memset((uint8_t *)fpu_template_in->q[num], temp * (num + 1),
- sizeof(fpu_template_in->q[0]));
- }
-
__asm__ volatile(
fill_simd_helper(0, 1)
fill_simd_helper(2, 3)
@@ -102,35 +65,105 @@
fill_simd_helper(28, 29)
fill_simd_helper(30, 31)
"sub %0, %0, #" STR(FPU_Q_COUNT * FPU_Q_SIZE) ";"
- : : "r" (fpu_template_in->q));
+ : : "r" (q_regs));
}
-void fpu_state_print(fpu_reg_state_t *vec)
+/* Read FPCR and FPSR and store it in 'cs_regs' */
+void fpu_cs_regs_read(fpu_cs_regs_t *cs_regs)
{
- INFO("dumping FPU registers :\n");
+ cs_regs->fpcr = read_fpcr();
+ cs_regs->fpsr = read_fpsr();
+}
+
+/* Write FPCR and FPSR passed in 'cs_regs' */
+void fpu_cs_regs_write(const fpu_cs_regs_t *cs_regs)
+{
+ write_fpcr(cs_regs->fpcr);
+ write_fpsr(cs_regs->fpsr);
+}
+
+/*
+ * Generate random values and write it to 'q_regs', then write it to FPU Q
+ * registers.
+ */
+void fpu_q_regs_write_rand(fpu_q_reg_t q_regs[FPU_Q_COUNT])
+{
+ uint32_t rval;
+
+ rval = rand();
+
+ memset((void *)q_regs, 0, sizeof(fpu_q_reg_t) * FPU_Q_COUNT);
for (unsigned int num = 0U; num < FPU_Q_COUNT; num++) {
- uint64_t __unused *qreg = (uint64_t *)&vec->q[num];
-
- INFO("Q[%02u]=0x%016llx_%016llx\n", num, *qreg, *(qreg + 1));
+ memset((uint8_t *)q_regs[num], rval * (num + 1),
+ sizeof(fpu_q_reg_t));
}
- INFO("FPCR=0x%lx FPSR=0x%lx\n", vec->fpcr, vec->fpsr);
+ fpu_q_regs_write(q_regs);
}
-bool fpu_state_compare_template(fpu_reg_state_t *fpu_template_in)
+/*
+ * Generate random values and write it to 'cs_regs', then write it to FPU FPCR
+ * and FPSR.
+ */
+void fpu_cs_regs_write_rand(fpu_cs_regs_t *cs_regs)
{
- (void)memset((void *)&g_fpu_read, 0, sizeof(fpu_reg_state_t));
- read_fpu_state_registers(&g_fpu_read);
+ memset((void *)cs_regs, 0, sizeof(fpu_cs_regs_t));
- if (memcmp((uint8_t *)fpu_template_in,
- (uint8_t *)&g_fpu_read,
- sizeof(fpu_reg_state_t)) != 0U) {
- ERROR("%s failed\n", __func__);
- ERROR("Read values\n");
- fpu_state_print(&g_fpu_read);
- ERROR("Template values\n");
- fpu_state_print(fpu_template_in);
- return false;
- } else {
- return true;
+ cs_regs->fpcr = rand();
+ cs_regs->fpsr = rand();
+
+ /*
+ * Write random value to FPCR FPSR.
+ * Note write will be ignored for reserved bits.
+ */
+ fpu_cs_regs_write(cs_regs);
+
+ /* Read back current FPCR and FPSR */
+ fpu_cs_regs_read(cs_regs);
+}
+
+/*
+ * Generate random values and write it to 'fpu_state', then write it to FPU Q
+ * registers, FPCR and FPSR.
+ */
+void fpu_state_write_rand(fpu_state_t *fpu_state)
+{
+ fpu_q_regs_write_rand(fpu_state->q_regs);
+ fpu_cs_regs_write_rand(&fpu_state->cs_regs);
+}
+
+/* Read FPU Q registers, FPCR and FPSR write it to 'fpu_state' */
+void fpu_state_read(fpu_state_t *fpu_state)
+{
+ fpu_q_regs_read(fpu_state->q_regs);
+ fpu_cs_regs_read(&fpu_state->cs_regs);
+}
+
+/* Return zero if FPU Q registers 's1', 's2' matches else nonzero */
+int fpu_q_regs_compare(const fpu_q_reg_t s1[FPU_Q_COUNT],
+ const fpu_q_reg_t s2[FPU_Q_COUNT])
+{
+ return memcmp(s1, s2, sizeof(fpu_q_reg_t) * FPU_Q_COUNT);
+}
+
+/*
+ * Return zero if FPU control and status registers 's1', 's2' matches else
+ * nonzero
+ */
+int fpu_cs_regs_compare(const fpu_cs_regs_t *s1, const fpu_cs_regs_t *s2)
+{
+ return memcmp(s1, s2, sizeof(fpu_cs_regs_t));
+}
+
+/* Returns 0, if FPU state 's1', 's2' matches else non-zero */
+int fpu_state_compare(const fpu_state_t *s1, const fpu_state_t *s2)
+{
+ if (fpu_q_regs_compare(s1->q_regs, s2->q_regs) != 0) {
+ return 1;
}
+
+ if (fpu_cs_regs_compare(&s1->cs_regs, &s2->cs_regs) != 0) {
+ return 1;
+ }
+
+ return 0;
}
diff --git a/lib/extensions/sve/aarch64/sve.c b/lib/extensions/sve/aarch64/sve.c
index 83f61fe..b6b4182 100644
--- a/lib/extensions/sve/aarch64/sve.c
+++ b/lib/extensions/sve/aarch64/sve.c
@@ -22,6 +22,7 @@
} else {
write_zcr_el1(reg_val);
}
+
isb();
}
@@ -74,7 +75,7 @@
for (vq = 0; vq <= sve_max_vq; vq++) {
_sve_config_vq(vq);
- rdvl_vq = SVE_VL_TO_VQ(sve_vector_length_get());
+ rdvl_vq = SVE_VL_TO_VQ(sve_rdvl_1());
if (vl_bitmap & BIT_32(rdvl_vq)) {
continue;
}
@@ -84,10 +85,9 @@
return vl_bitmap;
}
-void sve_fill_vector_regs(const sve_vector_t v[SVE_NUM_VECTORS])
+/* Write SVE Z[0-31] registers passed in 'z_regs' */
+void sve_z_regs_write(const sve_z_regs_t *z_regs)
{
- assert(is_armv8_2_sve_present());
-
__asm__ volatile(
".arch_extension sve\n"
fill_sve_helper(0)
@@ -123,13 +123,12 @@
fill_sve_helper(30)
fill_sve_helper(31)
".arch_extension nosve\n"
- : : "r" (v));
+ : : "r" (z_regs));
}
-void sve_read_vector_regs(sve_vector_t v[SVE_NUM_VECTORS])
+/* Read SVE Z[0-31] and store it in 'zregs' */
+void sve_z_regs_read(sve_z_regs_t *z_regs)
{
- assert(is_armv8_2_sve_present());
-
__asm__ volatile(
".arch_extension sve\n"
read_sve_helper(0)
@@ -165,5 +164,248 @@
read_sve_helper(30)
read_sve_helper(31)
".arch_extension nosve\n"
- : : "r" (v));
+ : : "r" (z_regs));
+}
+
+/* Write SVE P[0-15] registers passed in 'p_regs' */
+void sve_p_regs_write(const sve_p_regs_t *p_regs)
+{
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ fill_sve_p_helper(0)
+ fill_sve_p_helper(1)
+ fill_sve_p_helper(2)
+ fill_sve_p_helper(3)
+ fill_sve_p_helper(4)
+ fill_sve_p_helper(5)
+ fill_sve_p_helper(6)
+ fill_sve_p_helper(7)
+ fill_sve_p_helper(8)
+ fill_sve_p_helper(9)
+ fill_sve_p_helper(10)
+ fill_sve_p_helper(11)
+ fill_sve_p_helper(12)
+ fill_sve_p_helper(13)
+ fill_sve_p_helper(14)
+ fill_sve_p_helper(15)
+ ".arch_extension nosve\n"
+ : : "r" (p_regs));
+}
+
+/* Read SVE P[0-15] registers and store it in 'p_regs' */
+void sve_p_regs_read(sve_p_regs_t *p_regs)
+{
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ read_sve_p_helper(0)
+ read_sve_p_helper(1)
+ read_sve_p_helper(2)
+ read_sve_p_helper(3)
+ read_sve_p_helper(4)
+ read_sve_p_helper(5)
+ read_sve_p_helper(6)
+ read_sve_p_helper(7)
+ read_sve_p_helper(8)
+ read_sve_p_helper(9)
+ read_sve_p_helper(10)
+ read_sve_p_helper(11)
+ read_sve_p_helper(12)
+ read_sve_p_helper(13)
+ read_sve_p_helper(14)
+ read_sve_p_helper(15)
+ ".arch_extension nosve\n"
+ : : "r" (p_regs));
+}
+
+/* Write SVE FFR registers passed in 'ffr_regs' */
+void sve_ffr_regs_write(const sve_ffr_regs_t *ffr_regs)
+{
+ uint8_t sve_p_reg[SVE_P_REG_LEN_BYTES];
+
+ /* Save p0. Load 'ffr_regs' to p0 and write FFR. Restore p0 */
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ " str p0, [%1]\n"
+ " ldr p0, [%0]\n"
+ " wrffr p0.B\n"
+ " ldr p0, [%1]\n"
+ ".arch_extension nosve\n"
+ :
+ : "r" (ffr_regs), "r" (sve_p_reg)
+ : "memory");
+}
+
+/* Read SVE FFR registers and store it in 'ffr_regs' */
+void sve_ffr_regs_read(sve_ffr_regs_t *ffr_regs)
+{
+ uint8_t sve_p_reg[SVE_P_REG_LEN_BYTES];
+
+ /* Save p0. Read FFR to p0 and save p0 (ffr) to 'ffr_regs'. Restore p0 */
+ __asm__ volatile(
+ ".arch_extension sve\n"
+ " str p0, [%1]\n"
+ " rdffr p0.B\n"
+ " str p0, [%0]\n"
+ " ldr p0, [%1]\n"
+ ".arch_extension nosve\n"
+ :
+ : "r" (ffr_regs), "r" (sve_p_reg)
+ : "memory");
+}
+
+/*
+ * Generate random values and write it to 'z_regs', then write it to SVE Z
+ * registers.
+ */
+void sve_z_regs_write_rand(sve_z_regs_t *z_regs)
+{
+ uint32_t rval;
+ uint32_t z_size;
+ uint8_t *z_reg;
+
+ z_size = (uint32_t)sve_rdvl_1();
+
+ /* Write Z regs */
+ rval = rand();
+ memset((void *)z_regs, 0, sizeof(sve_z_regs_t));
+ for (uint32_t i = 0U; i < SVE_NUM_VECTORS; i++) {
+ z_reg = (uint8_t *)z_regs + (i * z_size);
+
+ memset((void *)z_reg, rval * (i + 1), z_size);
+ }
+ sve_z_regs_write(z_regs);
+}
+
+/*
+ * Generate random values and write it to 'p_regs', then write it to SVE P
+ * registers.
+ */
+void sve_p_regs_write_rand(sve_p_regs_t *p_regs)
+{
+ uint32_t p_size;
+ uint8_t *p_reg;
+ uint32_t rval;
+
+ p_size = (uint32_t)sve_rdvl_1() / 8;
+
+ /* Write P regs */
+ rval = rand();
+ memset((void *)p_regs, 0, sizeof(sve_p_regs_t));
+ for (uint32_t i = 0U; i < SVE_NUM_P_REGS; i++) {
+ p_reg = (uint8_t *)p_regs + (i * p_size);
+
+ memset((void *)p_reg, rval * (i + 1), p_size);
+ }
+ sve_p_regs_write(p_regs);
+}
+
+/*
+ * Generate random values and write it to 'ffr_regs', then write it to SVE FFR
+ * registers.
+ */
+void sve_ffr_regs_write_rand(sve_ffr_regs_t *ffr_regs)
+{
+ uint32_t ffr_size;
+ uint8_t *ffr_reg;
+ uint32_t rval;
+
+ ffr_size = (uint32_t)sve_rdvl_1() / 8;
+
+ rval = rand();
+ memset((void *)ffr_regs, 0, sizeof(sve_ffr_regs_t));
+ for (uint32_t i = 0U; i < SVE_NUM_FFR_REGS; i++) {
+ ffr_reg = (uint8_t *)ffr_regs + (i * ffr_size);
+
+ memset((void *)ffr_reg, rval * (i + 1), ffr_size);
+ }
+ sve_ffr_regs_write(ffr_regs);
+}
+
+/*
+ * Compare Z registers passed in 's1' (old values) with 's2' (new values).
+ *
+ * Returns:
+ * 0 : All Z[0-31] registers in 's1' and 's2' are equal
+ * nonzero : Sets the Nth bit of the Z register that is not equal
+ */
+uint64_t sve_z_regs_compare(const sve_z_regs_t *s1, const sve_z_regs_t *s2)
+{
+ uint32_t z_size;
+ uint64_t cmp_bitmap = 0UL;
+
+ z_size = (uint32_t)sve_rdvl_1();
+
+ for (uint32_t i = 0U; i < SVE_NUM_VECTORS; i++) {
+ uint8_t *s1_z = (uint8_t *)s1 + (i * z_size);
+ uint8_t *s2_z = (uint8_t *)s2 + (i * z_size);
+
+ if ((memcmp(s1_z, s2_z, z_size) == 0)) {
+ continue;
+ }
+
+ cmp_bitmap |= BIT_64(i);
+ VERBOSE("SVE Z_%u mismatch\n", i);
+ }
+
+ return cmp_bitmap;
+}
+
+/*
+ * Compare P registers passed in 's1' (old values) with 's2' (new values).
+ *
+ * Returns:
+ * 0 : All P[0-15] registers in 's1' and 's2' are equal
+ * nonzero : Sets the Nth bit of the P register that is not equal
+ */
+uint64_t sve_p_regs_compare(const sve_p_regs_t *s1, const sve_p_regs_t *s2)
+{
+ uint32_t p_size;
+ uint64_t cmp_bitmap = 0UL;
+
+ /* Size of one predicate register 1/8 of Z register */
+ p_size = (uint32_t)sve_rdvl_1() / 8U;
+
+ for (uint32_t i = 0U; i < SVE_NUM_P_REGS; i++) {
+ uint8_t *s1_p = (uint8_t *)s1 + (i * p_size);
+ uint8_t *s2_p = (uint8_t *)s2 + (i * p_size);
+
+ if ((memcmp(s1_p, s2_p, p_size) == 0)) {
+ continue;
+ }
+
+ cmp_bitmap |= BIT_64(i);
+ VERBOSE("SVE P_%u mismatch\n", i);
+ }
+
+ return cmp_bitmap;
+}
+
+/*
+ * Compare FFR register passed in 's1' (old values) with 's2' (new values).
+ *
+ * Returns:
+ * 0 : FFR register in 's1' and 's2' are equal
+ * nonzero : FFR register is not equal
+ */
+uint64_t sve_ffr_regs_compare(const sve_ffr_regs_t *s1, const sve_ffr_regs_t *s2)
+{
+ uint32_t ffr_size;
+ uint64_t cmp_bitmap = 0UL;
+
+ /* Size of one FFR register 1/8 of Z register */
+ ffr_size = (uint32_t)sve_rdvl_1() / 8U;
+
+ for (uint32_t i = 0U; i < SVE_NUM_FFR_REGS; i++) {
+ uint8_t *s1_ffr = (uint8_t *)s1 + (i * ffr_size);
+ uint8_t *s2_ffr = (uint8_t *)s2 + (i * ffr_size);
+
+ if ((memcmp(s1_ffr, s2_ffr, ffr_size) == 0)) {
+ continue;
+ }
+
+ cmp_bitmap |= BIT_64(i);
+ VERBOSE("SVE FFR_%u mismatch:\n", i);
+ }
+
+ return cmp_bitmap;
}
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index 4bd260c..1351415 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -20,6 +20,8 @@
bool test_realm_sve_probe_vl(void);
bool test_realm_sve_ops(void);
bool test_realm_sve_fill_regs(void);
+bool test_realm_sve_cmp_regs(void);
+bool test_realm_sve_undef_abort(void);
#endif /* REALM_TESTS_H */
diff --git a/realm/realm.mk b/realm/realm.mk
index 23ebc0c..debbda2 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -34,7 +34,7 @@
realm_psci.c \
realm_rsi.c \
realm_shared_data.c \
- realm_sve.c \
+ realm_simd.c \
)
REALM_SOURCES += lib/${ARCH}/cache_helpers.S \
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index b8c27bd..43cbf2d 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -18,7 +18,9 @@
#include <realm_tests.h>
#include <tftf_lib.h>
-static fpu_reg_state_t fpu_temp_rl;
+static fpu_state_t rl_fpu_state_write;
+static fpu_state_t rl_fpu_state_read;
+
/*
* This function reads sleep time in ms from shared buffer and spins PE
* in a loop for that time period.
@@ -98,11 +100,13 @@
test_succeed = test_pmuv3_overflow_interrupt();
break;
case REALM_REQ_FPU_FILL_CMD:
- fpu_state_fill_regs_and_template(&fpu_temp_rl);
+ fpu_state_write_rand(&rl_fpu_state_write);
test_succeed = true;
break;
case REALM_REQ_FPU_CMP_CMD:
- test_succeed = fpu_state_compare_template(&fpu_temp_rl);
+ fpu_state_read(&rl_fpu_state_read);
+ test_succeed = !fpu_state_compare(&rl_fpu_state_write,
+ &rl_fpu_state_read);
break;
case REALM_SVE_RDVL:
test_succeed = test_realm_sve_rdvl();
@@ -119,6 +123,12 @@
case REALM_SVE_FILL_REGS:
test_succeed = test_realm_sve_fill_regs();
break;
+ case REALM_SVE_CMP_REGS:
+ test_succeed = test_realm_sve_cmp_regs();
+ break;
+ case REALM_SVE_UNDEF_ABORT:
+ test_succeed = test_realm_sve_undef_abort();
+ break;
default:
realm_printf("%s() invalid cmd %u\n", __func__, cmd);
break;
diff --git a/realm/realm_simd.c b/realm/realm_simd.c
new file mode 100644
index 0000000..273696b
--- /dev/null
+++ b/realm/realm_simd.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_features.h>
+#include <arch_helpers.h>
+#include <assert.h>
+#include <debug.h>
+#include <stdlib.h>
+#include <sync.h>
+#include <lib/extensions/fpu.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];
+
+static sve_z_regs_t rl_sve_z_regs_write;
+static sve_z_regs_t rl_sve_z_regs_read;
+
+static sve_p_regs_t rl_sve_p_regs_write;
+static sve_p_regs_t rl_sve_p_regs_read;
+
+static sve_ffr_regs_t rl_sve_ffr_regs_write;
+static sve_ffr_regs_t rl_sve_ffr_regs_read;
+
+static fpu_cs_regs_t rl_fpu_cs_regs_write;
+static fpu_cs_regs_t rl_fpu_cs_regs_read;
+
+static int volatile realm_got_undef_abort;
+
+/* Returns the maximum supported VL. This test is called only by sve Realm */
+bool test_realm_sve_rdvl(void)
+{
+ host_shared_data_t *sd = realm_get_my_shared_structure();
+ struct sve_cmd_rdvl *output;
+
+ assert(is_armv8_2_sve_present());
+
+ output = (struct sve_cmd_rdvl *)sd->realm_cmd_output_buffer;
+ memset((void *)output, 0, sizeof(struct sve_cmd_rdvl));
+
+ sve_config_vq(SVE_VQ_ARCH_MAX);
+ output->rdvl = sve_rdvl_1();
+
+ return true;
+}
+
+/*
+ * Reads and returns the ID_AA64PFR0_EL1 and ID_AA64ZFR0_EL1 registers
+ * This test could be called from sve or non-sve Realm
+ */
+bool test_realm_sve_read_id_registers(void)
+{
+ host_shared_data_t *sd = realm_get_my_shared_structure();
+ struct sve_cmd_id_regs *output;
+
+ output = (struct sve_cmd_id_regs *)sd->realm_cmd_output_buffer;
+ memset((void *)output, 0, sizeof(struct sve_cmd_id_regs));
+
+ realm_printf("Realm: reading ID registers: ID_AA64PFR0_EL1, "
+ " ID_AA64ZFR0_EL1\n");
+ output->id_aa64pfr0_el1 = read_id_aa64pfr0_el1();
+ output->id_aa64zfr0_el1 = read_id_aa64zfr0_el1();
+
+ return true;
+}
+
+/*
+ * Probes all VLs and return the bitmap with the bit set for each corresponding
+ * valid VQ. This test is called only by sve Realm
+ */
+bool test_realm_sve_probe_vl(void)
+{
+ host_shared_data_t *sd = realm_get_my_shared_structure();
+ struct sve_cmd_probe_vl *output;
+
+ assert(is_armv8_2_sve_present());
+
+ output = (struct sve_cmd_probe_vl *)&sd->realm_cmd_output_buffer;
+ memset((void *)output, 0, sizeof(struct sve_cmd_probe_vl));
+
+ /* Probe all VLs */
+ output->vl_bitmap = sve_probe_vl(SVE_VQ_ARCH_MAX);
+
+ 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;
+}
+
+/* Fill SVE Z registers with known pattern */
+bool test_realm_sve_fill_regs(void)
+{
+ assert(is_armv8_2_sve_present());
+
+ /* Config Realm with max SVE length */
+ sve_config_vq(SVE_VQ_ARCH_MAX);
+
+ sve_z_regs_write_rand(&rl_sve_z_regs_write);
+ sve_p_regs_write_rand(&rl_sve_p_regs_write);
+ sve_ffr_regs_write_rand(&rl_sve_ffr_regs_write);
+
+ /* fpcr, fpsr common registers */
+ fpu_cs_regs_write_rand(&rl_fpu_cs_regs_write);
+
+ return true;
+}
+
+/* Compare SVE Z registers with last filled in values */
+bool test_realm_sve_cmp_regs(void)
+{
+ bool rc = true;
+ uint64_t bit_map;
+
+ assert(is_armv8_2_sve_present());
+
+ memset(&rl_sve_z_regs_read, 0, sizeof(rl_sve_z_regs_read));
+ memset(&rl_sve_p_regs_read, 0, sizeof(rl_sve_p_regs_read));
+ memset(&rl_sve_ffr_regs_read, 0, sizeof(rl_sve_ffr_regs_read));
+
+ /* Read all SVE registers */
+ sve_z_regs_read(&rl_sve_z_regs_read);
+ sve_p_regs_read(&rl_sve_p_regs_read);
+ sve_ffr_regs_read(&rl_sve_ffr_regs_read);
+
+ /* Compare the read values with last written values */
+ bit_map = sve_z_regs_compare(&rl_sve_z_regs_write, &rl_sve_z_regs_read);
+ if (bit_map) {
+ rc = false;
+ }
+
+ bit_map = sve_p_regs_compare(&rl_sve_p_regs_write, &rl_sve_p_regs_read);
+ if (bit_map) {
+ rc = false;
+ }
+
+ bit_map = sve_ffr_regs_compare(&rl_sve_ffr_regs_write,
+ &rl_sve_ffr_regs_read);
+ if (bit_map) {
+ rc = false;
+ }
+
+ /* fpcr, fpsr common registers */
+ fpu_cs_regs_read(&rl_fpu_cs_regs_read);
+ if (fpu_cs_regs_compare(&rl_fpu_cs_regs_write, &rl_fpu_cs_regs_read)) {
+ ERROR("Realm: FPCR/FPSR mismatch\n");
+ rc = false;
+ }
+
+ return rc;
+}
+
+static bool realm_sync_exception_handler(void)
+{
+ uint64_t esr_el1 = read_esr_el1();
+
+ if (EC_BITS(esr_el1) == EC_UNKNOWN) {
+ realm_printf("Realm: received undefined abort. "
+ "esr_el1: 0x%llx elr_el1: 0x%llx\n",
+ esr_el1, read_elr_el1());
+ realm_got_undef_abort++;
+ }
+
+ return true;
+}
+
+/* Check if Realm gets undefined abort when it accesses SVE functionality */
+bool test_realm_sve_undef_abort(void)
+{
+ realm_got_undef_abort = 0UL;
+
+ /* install exception handler to catch undef abort */
+ register_custom_sync_exception_handler(&realm_sync_exception_handler);
+ (void)sve_rdvl_1();
+ unregister_custom_sync_exception_handler();
+
+ if (realm_got_undef_abort == 0UL) {
+ return false;
+ }
+
+ return true;
+}
diff --git a/realm/realm_sve.c b/realm/realm_sve.c
deleted file mode 100644
index 0512789..0000000
--- a/realm/realm_sve.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <arch_features.h>
-#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];
-
-static sve_vector_t rl_sve_vectors_write[SVE_NUM_VECTORS] __aligned(16);
-
-/* Returns the maximum supported VL. This test is called only by sve Realm */
-bool test_realm_sve_rdvl(void)
-{
- host_shared_data_t *sd = realm_get_my_shared_structure();
- struct sve_cmd_rdvl *output;
-
- assert(is_armv8_2_sve_present());
-
- output = (struct sve_cmd_rdvl *)sd->realm_cmd_output_buffer;
- memset((void *)output, 0, sizeof(struct sve_cmd_rdvl));
-
- sve_config_vq(SVE_VQ_ARCH_MAX);
- output->rdvl = sve_vector_length_get();
-
- return true;
-}
-
-/*
- * Reads and returns the ID_AA64PFR0_EL1 and ID_AA64ZFR0_EL1 registers
- * This test could be called from sve or non-sve Realm
- */
-bool test_realm_sve_read_id_registers(void)
-{
- host_shared_data_t *sd = realm_get_my_shared_structure();
- struct sve_cmd_id_regs *output;
-
- output = (struct sve_cmd_id_regs *)sd->realm_cmd_output_buffer;
- memset((void *)output, 0, sizeof(struct sve_cmd_id_regs));
-
- realm_printf("Realm: reading ID registers: ID_AA64PFR0_EL1, "
- " ID_AA64ZFR0_EL1\n");
- output->id_aa64pfr0_el1 = read_id_aa64pfr0_el1();
- output->id_aa64zfr0_el1 = read_id_aa64zfr0_el1();
-
- return true;
-}
-
-/*
- * Probes all VLs and return the bitmap with the bit set for each corresponding
- * valid VQ. This test is called only by sve Realm
- */
-bool test_realm_sve_probe_vl(void)
-{
- host_shared_data_t *sd = realm_get_my_shared_structure();
- struct sve_cmd_probe_vl *output;
-
- assert(is_armv8_2_sve_present());
-
- output = (struct sve_cmd_probe_vl *)&sd->realm_cmd_output_buffer;
- memset((void *)output, 0, sizeof(struct sve_cmd_probe_vl));
-
- /* Probe all VLs */
- output->vl_bitmap = sve_probe_vl(SVE_VQ_ARCH_MAX);
-
- 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;
-}
-
-/* Fill SVE Z registers with known pattern */
-bool test_realm_sve_fill_regs(void)
-{
- uint32_t vl;
-
- assert(is_armv8_2_sve_present());
-
- /* Config Realm with max SVE length */
- sve_config_vq(SVE_VQ_ARCH_MAX);
- vl = sve_vector_length_get();
-
- memset((void *)&rl_sve_vectors_write, 0xcd, vl * SVE_NUM_VECTORS);
- sve_fill_vector_regs(rl_sve_vectors_write);
-
- return true;
-}
diff --git a/spm/cactus/cactus_tests/cactus_test_cpu_features.c b/spm/cactus/cactus_tests/cactus_test_cpu_features.c
index 78b89ac..a1366d3 100644
--- a/spm/cactus/cactus_tests/cactus_test_cpu_features.c
+++ b/spm/cactus/cactus_tests/cactus_test_cpu_features.c
@@ -13,7 +13,8 @@
* Note Test must exercise FILL and COMPARE command in
* sequence and on same CPU.
*/
-static fpu_reg_state_t g_fpu_temp;
+static fpu_state_t sp_fpu_state_write;
+static fpu_state_t sp_fpu_state_read;
static unsigned int core_pos;
/*
* Fill SIMD vectors from secure world side with a unique value.
@@ -21,7 +22,7 @@
CACTUS_CMD_HANDLER(req_simd_fill, CACTUS_REQ_SIMD_FILL_CMD)
{
core_pos = platform_get_core_pos(read_mpidr_el1());
- fpu_state_fill_regs_and_template(&g_fpu_temp);
+ fpu_state_write_rand(&sp_fpu_state_write);
return cactus_response(ffa_dir_msg_dest(*args),
ffa_dir_msg_source(*args),
CACTUS_SUCCESS);
@@ -37,7 +38,11 @@
unsigned int core_pos1 = platform_get_core_pos(read_mpidr_el1());
if (core_pos1 == core_pos) {
- test_succeed = fpu_state_compare_template(&g_fpu_temp);
+ fpu_state_read(&sp_fpu_state_read);
+ if (fpu_state_compare(&sp_fpu_state_write,
+ &sp_fpu_state_read) == 0) {
+ test_succeed = true;
+ }
}
return cactus_response(ffa_dir_msg_dest(*args),
ffa_dir_msg_source(*args),
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c
new file mode 100644
index 0000000..3fd18ba
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_simd_tests.c
@@ -0,0 +1,937 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <assert.h>
+#include <arch_features.h>
+#include <debug.h>
+#include <test_helpers.h>
+#include <lib/extensions/fpu.h>
+#include <lib/extensions/sve.h>
+
+#include <host_realm_helper.h>
+#include <host_realm_mem_layout.h>
+#include <host_realm_sve.h>
+#include <host_shared_data.h>
+
+#define NS_SVE_OP_ARRAYSIZE 1024U
+#define SVE_TEST_ITERATIONS 50U
+
+/* Min test iteration count for 'host_and_realm_check_simd' test */
+#define TEST_ITERATIONS_MIN (16U)
+
+/* Number of FPU configs: none */
+#define NUM_FPU_CONFIGS (0U)
+
+/* Number of SVE configs: SVE_VL */
+#define NUM_SVE_CONFIGS (1U)
+
+typedef enum security_state {
+ NONSECURE_WORLD = 0U,
+ REALM_WORLD,
+ SECURITY_STATE_MAX
+} security_state_t;
+
+typedef enum {
+ TEST_FPU = 0U,
+ TEST_SVE,
+} simd_test_t;
+
+static int ns_sve_op_1[NS_SVE_OP_ARRAYSIZE];
+static int ns_sve_op_2[NS_SVE_OP_ARRAYSIZE];
+
+static sve_z_regs_t ns_sve_z_regs_write;
+static sve_z_regs_t ns_sve_z_regs_read;
+
+static sve_p_regs_t ns_sve_p_regs_write;
+static sve_p_regs_t ns_sve_p_regs_read;
+
+static sve_ffr_regs_t ns_sve_ffr_regs_write;
+static sve_ffr_regs_t ns_sve_ffr_regs_read;
+
+static fpu_q_reg_t ns_fpu_q_regs_write[FPU_Q_COUNT];
+static fpu_q_reg_t ns_fpu_q_regs_read[FPU_Q_COUNT];
+
+static fpu_cs_regs_t ns_fpu_cs_regs_write;
+static fpu_cs_regs_t ns_fpu_cs_regs_read;
+
+/* 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 { \
+ SKIP_TEST_IF_SVE_NOT_SUPPORTED(); \
+ \
+ /* Get RMM support for SVE and its max SVE VL */ \
+ if (host_rmi_features(0UL, &_reg0) != REALM_SUCCESS) { \
+ ERROR("Failed to get RMI feat_reg0\n"); \
+ return TEST_RESULT_FAIL; \
+ } \
+ \
+ /* SVE not supported in RMI features? */ \
+ if ((_reg0 & RMI_FEATURE_REGISTER_0_SVE_EN) == 0UL) { \
+ ERROR("SVE not in RMI features, skipping\n"); \
+ return TEST_RESULT_SKIPPED; \
+ } \
+ } while (false)
+
+static test_result_t host_create_sve_realm_payload(bool sve_en, uint8_t sve_vq)
+{
+ u_register_t feature_flag;
+ u_register_t rec_flag[1] = {RMI_RUNNABLE};
+
+ if (sve_en) {
+ feature_flag = RMI_FEATURE_REGISTER_0_SVE_EN |
+ INPLACE(FEATURE_SVE_VL, sve_vq);
+ } else {
+ feature_flag = 0UL;
+ }
+
+ /* Initialise Realm payload */
+ if (!host_create_realm_payload((u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)(PAGE_POOL_MAX_SIZE +
+ NS_REALM_SHARED_MEM_SIZE),
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ feature_flag, rec_flag, 1U)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Create shared memory between Host and Realm */
+ if (!host_create_shared_mem(NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * RMI should report SVE VL in RMI features and it must be the same value as the
+ * max SVE VL seen by the NS world.
+ */
+test_result_t host_check_rmi_reports_proper_sve_vl(void)
+{
+ u_register_t rmi_feat_reg0;
+ uint8_t rmi_sve_vq;
+ uint8_t ns_sve_vq;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ rmi_sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ /*
+ * Configure NS to arch supported max VL and get the value reported
+ * by rdvl
+ */
+ sve_config_vq(SVE_VQ_ARCH_MAX);
+ ns_sve_vq = SVE_VL_TO_VQ(sve_rdvl_1());
+
+ if (rmi_sve_vq != ns_sve_vq) {
+ ERROR("RMI max SVE VL %u bits don't match NS max "
+ "SVE VL %u bits\n", SVE_VQ_TO_BITS(rmi_sve_vq),
+ SVE_VQ_TO_BITS(ns_sve_vq));
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+/* Test Realm creation with SVE enabled and run command rdvl */
+test_result_t host_sve_realm_cmd_rdvl(void)
+{
+ host_shared_data_t *sd;
+ struct sve_cmd_rdvl *rl_output;
+ uint8_t sve_vq, rl_max_sve_vq;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ bool realm_rc;
+
+ 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) {
+ ERROR("Failed to create Realm with SVE\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (realm_rc != true) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ /* Check if rdvl matches the SVE VL created */
+ sd = host_get_shared_structure(0U);
+ rl_output = (struct sve_cmd_rdvl *)sd->realm_cmd_output_buffer;
+ rl_max_sve_vq = SVE_VL_TO_VQ(rl_output->rdvl);
+ if (sve_vq == rl_max_sve_vq) {
+ rc = TEST_RESULT_SUCCESS;
+ } else {
+ ERROR("Realm created with max VL: %u bits, but Realm reported "
+ "max VL as: %u bits\n", SVE_VQ_TO_BITS(sve_vq),
+ SVE_VQ_TO_BITS(rl_max_sve_vq));
+ rc = TEST_RESULT_FAIL;
+ }
+
+rm_realm:
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/* Test Realm creation with SVE enabled but with invalid SVE VL */
+test_result_t host_sve_realm_test_invalid_vl(void)
+{
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ uint8_t sve_vq;
+
+ 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);
+
+ /*
+ * Pass a sve_vq that is greater than the value supported by RMM
+ * and check whether creating Realm fails
+ */
+ rc = host_create_sve_realm_payload(true, (sve_vq + 1));
+ if (rc == TEST_RESULT_SUCCESS) {
+ ERROR("Error: Realm created with invalid SVE VL %u\n", (sve_vq + 1));
+ host_destroy_realm();
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t _host_sve_realm_check_id_registers(bool sve_en)
+{
+ host_shared_data_t *sd;
+ struct sve_cmd_id_regs *r_regs;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ bool realm_rc;
+ uint8_t sve_vq = 0U;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (sve_en) {
+ 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(sve_en, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_ID_REGISTERS, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ sd = host_get_shared_structure(0U);
+ r_regs = (struct sve_cmd_id_regs *)sd->realm_cmd_output_buffer;
+
+ /* Check ID register SVE flags */
+ if (sve_en) {
+ rc = TEST_RESULT_SUCCESS;
+ if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) == 0UL) {
+ ERROR("ID_AA64PFR0_EL1: SVE not enabled\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ if (r_regs->id_aa64zfr0_el1 == 0UL) {
+ ERROR("ID_AA64ZFR0_EL1: No SVE features present\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ } else {
+ rc = TEST_RESULT_SUCCESS;
+ if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) != 0UL) {
+ ERROR("ID_AA64PFR0_EL1: SVE enabled\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ if (r_regs->id_aa64zfr0_el1 != 0UL) {
+ ERROR("ID_AA64ZFR0_EL1: Realm reported non-zero value\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ }
+
+rm_realm:
+ host_destroy_realm();
+ return rc;
+}
+
+/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in SVE Realm */
+test_result_t host_sve_realm_cmd_id_registers(void)
+{
+ return _host_sve_realm_check_id_registers(true);
+}
+
+/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in non SVE Realm */
+test_result_t host_non_sve_realm_cmd_id_registers(void)
+{
+ return _host_sve_realm_check_id_registers(false);
+}
+
+static void print_sve_vl_bitmap(uint32_t vl_bitmap)
+{
+ for (uint8_t vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
+ if ((vl_bitmap & BIT_32(vq)) != 0U) {
+ INFO("\t%u\n", SVE_VQ_TO_BITS(vq));
+ }
+ }
+}
+
+/* Create SVE Realm and probe all the supported VLs */
+test_result_t host_sve_realm_cmd_probe_vl(void)
+{
+ host_shared_data_t *sd;
+ struct sve_cmd_probe_vl *rl_output;
+ uint32_t vl_bitmap_expected;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ bool realm_rc;
+ uint8_t sve_vq;
+
+ 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;
+ }
+
+ /*
+ * Configure TFTF with sve_vq and probe all VLs and compare it with
+ * the bitmap returned from Realm
+ */
+ vl_bitmap_expected = sve_probe_vl(sve_vq);
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_PROBE_VL, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ sd = host_get_shared_structure(0U);
+ rl_output = (struct sve_cmd_probe_vl *)sd->realm_cmd_output_buffer;
+
+ INFO("Supported SVE vector length in bits (expected):\n");
+ print_sve_vl_bitmap(vl_bitmap_expected);
+
+ INFO("Supported SVE vector length in bits (probed):\n");
+ print_sve_vl_bitmap(rl_output->vl_bitmap);
+
+ if (vl_bitmap_expected == rl_output->vl_bitmap) {
+ rc = TEST_RESULT_SUCCESS;
+ } else {
+ rc = TEST_RESULT_FAIL;
+ }
+
+rm_realm:
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/* Check whether RMM preserves NS ZCR_EL2 register. */
+test_result_t host_sve_realm_check_config_register(void)
+{
+ u_register_t ns_zcr_el2, ns_zcr_el2_cur;
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ uint8_t vq;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
+
+ vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ rc = host_create_sve_realm_payload(true, vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ /*
+ * Configure TFTF from 0 to SVE_VQ_ARCH_MAX, and in each iteration check
+ * if NS ZCR_EL2 is same before and after call to run Realm.
+ */
+ rc = TEST_RESULT_SUCCESS;
+ for (vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
+ bool realm_rc;
+
+ sve_config_vq(vq);
+ ns_zcr_el2 = read_zcr_el2();
+
+ /* Call Realm to run SVE command */
+ realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ ERROR("Realm command REALM_SVE_RDVL failed\n");
+ rc = TEST_RESULT_FAIL;
+ break;
+ }
+ ns_zcr_el2_cur = read_zcr_el2();
+
+ if (ns_zcr_el2 != ns_zcr_el2_cur) {
+ ERROR("NS ZCR_EL2 expected: 0x%lx, got: 0x%lx\n",
+ ns_zcr_el2, ns_zcr_el2_cur);
+ rc = TEST_RESULT_FAIL;
+ }
+ }
+
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ 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)
+{
+
+ return !host_enter_realm_execute(REALM_SVE_OPS, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+}
+
+/* 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;
+}
+
+/*
+ * Check if RMM leaks Realm SVE registers.
+ * This test is skipped if the supported max VQ is 128 bits, as we won't be able
+ * to run NS and Realm context with lower and higher VQ respectively.
+ * This test does the below steps:
+ *
+ * 1. Set NS SVE VQ to max and write known pattern
+ * 2. NS programs ZCR_EL2 with VQ as 0 (128 bits).
+ * 3. Create Realm with max VQ (higher than NS SVE VQ).
+ * 4. Call Realm to fill in Z registers
+ * 5. Once Realm returns, NS sets ZCR_EL2 with max VQ and reads the Z registers
+ * 6. The upper bits of Z registers must be either 0 or the old values filled by
+ * NS world at step 1.
+ */
+test_result_t host_sve_realm_check_vectors_leaked(void)
+{
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ uint64_t bitmap;
+ bool realm_rc;
+ uint8_t sve_vq;
+
+ 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);
+
+ /* Skip test if the supported max VQ is 128 bits */
+ if (sve_vq == SVE_VQ_ARCH_MIN) {
+ return TEST_RESULT_SKIPPED;
+ }
+
+ /* 1. Set NS SVE VQ to max and write known pattern */
+ sve_config_vq(sve_vq);
+ (void)memset((void *)&ns_sve_z_regs_write, 0xAA,
+ SVE_VQ_TO_BYTES(sve_vq) * SVE_NUM_VECTORS);
+ sve_z_regs_write(&ns_sve_z_regs_write);
+
+ /* 2. NS programs ZCR_EL2 with VQ as 0 */
+ sve_config_vq(SVE_VQ_ARCH_MIN);
+
+ /* 3. Create Realm with max VQ (higher than NS SVE VQ) */
+ rc = host_create_sve_realm_payload(true, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ /* 4. Call Realm to fill in Z registers */
+ realm_rc = host_enter_realm_execute(REALM_SVE_FILL_REGS, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ /* 5. NS sets ZCR_EL2 with max VQ and reads the Z registers */
+ sve_config_vq(sve_vq);
+ sve_z_regs_read(&ns_sve_z_regs_read);
+
+ /*
+ * 6. The upper bits in Z vectors (sve_vq - SVE_VQ_ARCH_MIN) must
+ * be either 0 or the old values filled by NS world.
+ * TODO: check if upper bits are zero
+ */
+ bitmap = sve_z_regs_compare(&ns_sve_z_regs_write, &ns_sve_z_regs_read);
+ if (bitmap != 0UL) {
+ ERROR("SVE Z regs compare failed (bitmap: 0x%016llx)\n",
+ bitmap);
+ rc = TEST_RESULT_FAIL;
+ } else {
+ rc = TEST_RESULT_SUCCESS;
+ }
+
+rm_realm:
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/*
+ * Create a non SVE Realm and try to access SVE, the Realm must receive
+ * undefined abort.
+ */
+test_result_t host_non_sve_realm_check_undef_abort(void)
+{
+ test_result_t rc;
+ bool realm_rc;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+ SKIP_TEST_IF_SVE_NOT_SUPPORTED();
+
+ rc = host_create_sve_realm_payload(false, 0);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ realm_rc = host_enter_realm_execute(REALM_SVE_UNDEF_ABORT, NULL,
+ RMI_EXIT_HOST_CALL, 0U);
+ if (!realm_rc) {
+ ERROR("Realm didn't receive undefined abort\n");
+ rc = TEST_RESULT_FAIL;
+ } else {
+ rc = TEST_RESULT_SUCCESS;
+ }
+
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/* Generate random values and write it to SVE Z, P and FFR registers */
+static void ns_sve_write_rand(void)
+{
+ sve_z_regs_write_rand(&ns_sve_z_regs_write);
+ sve_p_regs_write_rand(&ns_sve_p_regs_write);
+ sve_ffr_regs_write_rand(&ns_sve_ffr_regs_write);
+}
+
+/* Read SVE Z, P and FFR registers and compare it with the last written values */
+static test_result_t ns_sve_read_and_compare(void)
+{
+ test_result_t rc = TEST_RESULT_SUCCESS;
+ uint64_t bitmap;
+
+ /* Clear old state */
+ memset((void *)&ns_sve_z_regs_read, 0, sizeof(ns_sve_z_regs_read));
+ memset((void *)&ns_sve_p_regs_read, 0, sizeof(ns_sve_p_regs_read));
+ memset((void *)&ns_sve_ffr_regs_read, 0, sizeof(ns_sve_ffr_regs_read));
+
+ /* Read Z, P, FFR registers to compare it with the last written values */
+ sve_z_regs_read(&ns_sve_z_regs_read);
+ sve_p_regs_read(&ns_sve_p_regs_read);
+ sve_ffr_regs_read(&ns_sve_ffr_regs_read);
+
+ bitmap = sve_z_regs_compare(&ns_sve_z_regs_write, &ns_sve_z_regs_read);
+ if (bitmap != 0UL) {
+ ERROR("SVE Z regs compare failed (bitmap: 0x%016llx)\n",
+ bitmap);
+ rc = TEST_RESULT_FAIL;
+ }
+
+ bitmap = sve_p_regs_compare(&ns_sve_p_regs_write, &ns_sve_p_regs_read);
+ if (bitmap != 0UL) {
+ ERROR("SVE P regs compare failed (bitmap: 0x%016llx)\n",
+ bitmap);
+ rc = TEST_RESULT_FAIL;
+ }
+
+ bitmap = sve_ffr_regs_compare(&ns_sve_ffr_regs_write,
+ &ns_sve_ffr_regs_read);
+ if (bitmap != 0) {
+ ERROR("SVE FFR regs compare failed (bitmap: 0x%016llx)\n",
+ bitmap);
+ rc = TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+static char *simd_type_to_str(simd_test_t type)
+{
+ if (type == TEST_FPU) {
+ return "FPU";
+ } else if (type == TEST_SVE) {
+ return "SVE";
+ } else {
+ return "UNKNOWN";
+ }
+}
+
+static void ns_simd_print_cmd_config(bool cmd, simd_test_t type)
+{
+ char __unused *tstr = simd_type_to_str(type);
+ char __unused *cstr = cmd ? "write rand" : "read and compare";
+
+ if (type == TEST_SVE) {
+ INFO("TFTF: NS [%s] %s. Config: zcr: 0x%llx\n", tstr, cstr,
+ (uint64_t)read_zcr_el2());
+ } else {
+ INFO("TFTF: NS [%s] %s\n", tstr, cstr);
+ }
+}
+
+/*
+ * Randomly select TEST_SVE or TEST_FPU. For TEST_SVE, configure zcr_el2 with
+ * random vector length
+ */
+static simd_test_t ns_sve_select_random_config(void)
+{
+ simd_test_t type;
+
+ if (rand() % 2) {
+ sve_config_vq(SVE_GET_RANDOM_VQ);
+ type = TEST_SVE;
+ } else {
+ type = TEST_FPU;
+ }
+
+ return type;
+}
+
+/*
+ * Configure NS world SIMD. Randomly choose to test SVE or FPU registers if
+ * system supports SVE.
+ *
+ * Returns either TEST_FPU or TEST_SVE
+ */
+static simd_test_t ns_simd_select_random_config(void)
+{
+ simd_test_t type;
+
+ if (is_armv8_2_sve_present()) {
+ type = ns_sve_select_random_config();
+ } else {
+ type = TEST_FPU;
+ }
+
+ return type;
+}
+
+/* Select random NS SIMD config and write random values to its registers */
+static simd_test_t ns_simd_write_rand(void)
+{
+ simd_test_t type;
+
+ type = ns_simd_select_random_config();
+
+ ns_simd_print_cmd_config(true, type);
+
+ if (type == TEST_SVE) {
+ ns_sve_write_rand();
+ } else {
+ fpu_q_regs_write_rand(ns_fpu_q_regs_write);
+ }
+
+ /* fpcr, fpsr common to all configs */
+ fpu_cs_regs_write_rand(&ns_fpu_cs_regs_write);
+
+ return type;
+}
+
+/* Read and compare the NS SIMD registers with the last written values */
+static test_result_t ns_simd_read_and_compare(simd_test_t type)
+{
+ test_result_t rc = TEST_RESULT_SUCCESS;
+
+ ns_simd_print_cmd_config(false, type);
+
+ if (type == TEST_SVE) {
+ rc = ns_sve_read_and_compare();
+ } else {
+ fpu_q_regs_read(ns_fpu_q_regs_read);
+ if (fpu_q_regs_compare(ns_fpu_q_regs_write,
+ ns_fpu_q_regs_read)) {
+ ERROR("FPU Q registers compare failed\n");
+ rc = TEST_RESULT_FAIL;
+ }
+ }
+
+ /* fpcr, fpsr common to all configs */
+ fpu_cs_regs_read(&ns_fpu_cs_regs_read);
+ if (fpu_cs_regs_compare(&ns_fpu_cs_regs_write, &ns_fpu_cs_regs_read)) {
+ ERROR("FPCR/FPSR registers compare failed\n");
+ rc = TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
+
+/* Select random Realm SIMD config and write random values to its registers */
+static simd_test_t rl_simd_write_rand(bool rl_sve_en)
+{
+ enum realm_cmd rl_fill_cmd;
+ simd_test_t type;
+ bool __unused rc;
+
+ /* Select random commands to test. SVE or FPU registers in Realm */
+ if (rl_sve_en && (rand() % 2)) {
+ type = TEST_SVE;
+ } else {
+ type = TEST_FPU;
+ }
+
+ INFO("TFTF: RL [%s] write random\n", simd_type_to_str(type));
+ if (type == TEST_SVE) {
+ rl_fill_cmd = REALM_SVE_FILL_REGS;
+ } else {
+ rl_fill_cmd = REALM_REQ_FPU_FILL_CMD;
+ }
+
+ rc = host_enter_realm_execute(rl_fill_cmd, NULL, RMI_EXIT_HOST_CALL, 0U);
+ assert(rc);
+
+ return type;
+}
+
+/* Read and compare the Realm SIMD registers with the last written values */
+static bool rl_simd_read_and_compare(simd_test_t type)
+{
+ enum realm_cmd rl_cmp_cmd;
+
+ INFO("TFTF: RL [%s] read and compare\n", simd_type_to_str(type));
+ if (type == TEST_SVE) {
+ rl_cmp_cmd = REALM_SVE_CMP_REGS;
+ } else {
+ rl_cmp_cmd = REALM_REQ_FPU_CMP_CMD;
+ }
+
+ return host_enter_realm_execute(rl_cmp_cmd, NULL, RMI_EXIT_HOST_CALL,
+ 0U);
+}
+
+/*
+ * This test case verifies whether various SIMD related registers like Q[0-31],
+ * FPCR, FPSR, Z[0-31], P[0-15], FFR are preserved by RMM during world switch
+ * between NS world and Realm world.
+ *
+ * Randomly verify FPU registers or SVE registers if the system supports SVE.
+ * Within SVE, randomly configure SVE vector length.
+ *
+ * This testcase runs on below configs:
+ * - with SVE
+ * - without SVE
+ */
+test_result_t host_and_realm_check_simd(void)
+{
+ u_register_t rmi_feat_reg0;
+ test_result_t rc;
+ uint8_t sve_vq;
+ bool sve_en;
+ security_state_t sec_state;
+ simd_test_t ns_simd_type, rl_simd_type;
+ unsigned int test_iterations;
+ unsigned int num_simd_types;
+ unsigned int num_simd_configs;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ if (host_rmi_features(0UL, &rmi_feat_reg0) != REALM_SUCCESS) {
+ ERROR("Failed to get RMI feat_reg0\n");
+ return TEST_RESULT_FAIL;
+ }
+
+ sve_en = rmi_feat_reg0 & RMI_FEATURE_REGISTER_0_SVE_EN;
+ sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
+
+ /* Create Realm with SVE enabled if RMI features supports it */
+ INFO("TFTF: create realm sve_en/sve_vq: %d/%d\n", sve_en, sve_vq);
+ rc = host_create_sve_realm_payload(sve_en, sve_vq);
+ if (rc != TEST_RESULT_SUCCESS) {
+ return rc;
+ }
+
+ /*
+ * Randomly select and configure NS simd context to test. And fill it
+ * with random values.
+ */
+ ns_simd_type = ns_simd_write_rand();
+
+ /*
+ * Randomly select and configure Realm simd context to test. Enter realm
+ * and fill simd context with random values.
+ */
+ rl_simd_type = rl_simd_write_rand(sve_en);
+ sec_state = REALM_WORLD;
+
+ /*
+ * Find out test iterations based on if SVE is enabled and the number of
+ * configurations available in the SVE.
+ */
+
+ /* FPU is always available */
+ num_simd_types = 1U;
+ num_simd_configs = NUM_FPU_CONFIGS;
+
+ if (is_armv8_2_sve_present()) {
+ num_simd_types += 1;
+ num_simd_configs += NUM_SVE_CONFIGS;
+ }
+
+ if (num_simd_configs) {
+ test_iterations = TEST_ITERATIONS_MIN * num_simd_types *
+ num_simd_configs;
+ } else {
+ test_iterations = TEST_ITERATIONS_MIN * num_simd_types;
+ }
+
+ for (uint32_t i = 0U; i < test_iterations; i++) {
+ if (sec_state == NONSECURE_WORLD) {
+ sec_state = REALM_WORLD;
+ } else {
+ sec_state = NONSECURE_WORLD;
+ }
+
+ switch (sec_state) {
+ case NONSECURE_WORLD:
+ /*
+ * Read NS simd context and compare it with last written
+ * context.
+ */
+ rc = ns_simd_read_and_compare(ns_simd_type);
+ if (rc != TEST_RESULT_SUCCESS) {
+ goto rm_realm;
+ }
+
+ /*
+ * Randomly select and configure NS simd context. And
+ * fill it with random values for the next compare.
+ */
+ ns_simd_type = ns_simd_write_rand();
+ break;
+ case REALM_WORLD:
+ /*
+ * Enter Realm and read the simd context and compare it
+ * with last written context.
+ */
+ if (!rl_simd_read_and_compare(rl_simd_type)) {
+ ERROR("%s failed %d\n", __func__, __LINE__);
+ rc = TEST_RESULT_FAIL;
+ goto rm_realm;
+ }
+
+ /*
+ * Randomly select and configure Realm simd context to
+ * test. Enter realm and fill simd context with random
+ * values for the next compare.
+ */
+ rl_simd_type = rl_simd_write_rand(sve_en);
+ break;
+ default:
+ break;
+ }
+ }
+
+ rc = TEST_RESULT_SUCCESS;
+rm_realm:
+ if (!host_destroy_realm()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return rc;
+}
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
deleted file mode 100644
index 358c8bb..0000000
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_sve_tests.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (c) 2023, Arm Limited. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <stdlib.h>
-
-#include <assert.h>
-#include <arch_features.h>
-#include <debug.h>
-#include <test_helpers.h>
-#include <lib/extensions/sve.h>
-
-#include <host_realm_helper.h>
-#include <host_realm_mem_layout.h>
-#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];
-
-static sve_vector_t ns_sve_vectors_write[SVE_NUM_VECTORS] __aligned(16);
-static sve_vector_t ns_sve_vectors_read[SVE_NUM_VECTORS] __aligned(16);
-
-/* 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 { \
- SKIP_TEST_IF_SVE_NOT_SUPPORTED(); \
- \
- /* Get RMM support for SVE and its max SVE VL */ \
- if (host_rmi_features(0UL, &_reg0) != REALM_SUCCESS) { \
- ERROR("Failed to get RMI feat_reg0\n"); \
- return TEST_RESULT_FAIL; \
- } \
- \
- /* SVE not supported in RMI features? */ \
- if ((_reg0 & RMI_FEATURE_REGISTER_0_SVE_EN) == 0UL) { \
- ERROR("SVE not in RMI features, skipping\n"); \
- return TEST_RESULT_SKIPPED; \
- } \
- } while (false)
-
-static test_result_t host_create_sve_realm_payload(bool sve_en, uint8_t sve_vq)
-{
- u_register_t feature_flag;
- u_register_t rec_flag[1] = {RMI_RUNNABLE};
-
- if (sve_en) {
- feature_flag = RMI_FEATURE_REGISTER_0_SVE_EN |
- INPLACE(FEATURE_SVE_VL, sve_vq);
- } else {
- feature_flag = 0UL;
- }
-
- /* Initialise Realm payload */
- if (!host_create_realm_payload((u_register_t)REALM_IMAGE_BASE,
- (u_register_t)PAGE_POOL_BASE,
- (u_register_t)(PAGE_POOL_MAX_SIZE +
- NS_REALM_SHARED_MEM_SIZE),
- (u_register_t)PAGE_POOL_MAX_SIZE,
- feature_flag, rec_flag, 1U)) {
- return TEST_RESULT_FAIL;
- }
-
- /* Create shared memory between Host and Realm */
- if (!host_create_shared_mem(NS_REALM_SHARED_MEM_BASE,
- NS_REALM_SHARED_MEM_SIZE)) {
- return TEST_RESULT_FAIL;
- }
-
- return TEST_RESULT_SUCCESS;
-}
-
-/*
- * RMI should report SVE VL in RMI features and it must be the same value as the
- * max SVE VL seen by the NS world.
- */
-test_result_t host_check_rmi_reports_proper_sve_vl(void)
-{
- u_register_t rmi_feat_reg0;
- uint8_t rmi_sve_vq;
- uint8_t ns_sve_vq;
-
- SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
-
- CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
-
- rmi_sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
-
- /*
- * Configure NS to arch supported max VL and get the value reported
- * by rdvl
- */
- sve_config_vq(SVE_VQ_ARCH_MAX);
- ns_sve_vq = SVE_VL_TO_VQ(sve_vector_length_get());
-
- if (rmi_sve_vq != ns_sve_vq) {
- ERROR("RMI max SVE VL %u bits don't match NS max "
- "SVE VL %u bits\n", SVE_VQ_TO_BITS(rmi_sve_vq),
- SVE_VQ_TO_BITS(ns_sve_vq));
- return TEST_RESULT_FAIL;
- }
-
- return TEST_RESULT_SUCCESS;
-}
-
-/* Test Realm creation with SVE enabled and run command rdvl */
-test_result_t host_sve_realm_cmd_rdvl(void)
-{
- host_shared_data_t *sd;
- struct sve_cmd_rdvl *rl_output;
- uint8_t sve_vq, rl_max_sve_vq;
- u_register_t rmi_feat_reg0;
- test_result_t rc;
- bool realm_rc;
-
- 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) {
- ERROR("Failed to create Realm with SVE\n");
- return TEST_RESULT_FAIL;
- }
-
- realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
- RMI_EXIT_HOST_CALL, 0U);
- if (realm_rc != true) {
- rc = TEST_RESULT_FAIL;
- goto rm_realm;
- }
-
- /* Check if rdvl matches the SVE VL created */
- sd = host_get_shared_structure(0U);
- rl_output = (struct sve_cmd_rdvl *)sd->realm_cmd_output_buffer;
- rl_max_sve_vq = SVE_VL_TO_VQ(rl_output->rdvl);
- if (sve_vq == rl_max_sve_vq) {
- rc = TEST_RESULT_SUCCESS;
- } else {
- ERROR("Realm created with max VL: %u bits, but Realm reported "
- "max VL as: %u bits\n", SVE_VQ_TO_BITS(sve_vq),
- SVE_VQ_TO_BITS(rl_max_sve_vq));
- rc = TEST_RESULT_FAIL;
- }
-
-rm_realm:
- if (!host_destroy_realm()) {
- return TEST_RESULT_FAIL;
- }
-
- return rc;
-}
-
-/* Test Realm creation with SVE enabled but with invalid SVE VL */
-test_result_t host_sve_realm_test_invalid_vl(void)
-{
- u_register_t rmi_feat_reg0;
- test_result_t rc;
- uint8_t sve_vq;
-
- 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);
-
- /*
- * Pass a sve_vq that is greater than the value supported by RMM
- * and check whether creating Realm fails
- */
- rc = host_create_sve_realm_payload(true, (sve_vq + 1));
- if (rc == TEST_RESULT_SUCCESS) {
- ERROR("Error: Realm created with invalid SVE VL %u\n", (sve_vq + 1));
- host_destroy_realm();
- return TEST_RESULT_FAIL;
- }
-
- return TEST_RESULT_SUCCESS;
-}
-
-static test_result_t _host_sve_realm_check_id_registers(bool sve_en)
-{
- host_shared_data_t *sd;
- struct sve_cmd_id_regs *r_regs;
- u_register_t rmi_feat_reg0;
- test_result_t rc;
- bool realm_rc;
- uint8_t sve_vq = 0U;
-
- SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
-
- if (sve_en) {
- 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(sve_en, sve_vq);
- if (rc != TEST_RESULT_SUCCESS) {
- return rc;
- }
-
- realm_rc = host_enter_realm_execute(REALM_SVE_ID_REGISTERS, NULL,
- RMI_EXIT_HOST_CALL, 0U);
- if (!realm_rc) {
- rc = TEST_RESULT_FAIL;
- goto rm_realm;
- }
-
- sd = host_get_shared_structure(0U);
- r_regs = (struct sve_cmd_id_regs *)sd->realm_cmd_output_buffer;
-
- /* Check ID register SVE flags */
- if (sve_en) {
- rc = TEST_RESULT_SUCCESS;
- if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) == 0UL) {
- ERROR("ID_AA64PFR0_EL1: SVE not enabled\n");
- rc = TEST_RESULT_FAIL;
- }
- if (r_regs->id_aa64zfr0_el1 == 0UL) {
- ERROR("ID_AA64ZFR0_EL1: No SVE features present\n");
- rc = TEST_RESULT_FAIL;
- }
- } else {
- rc = TEST_RESULT_SUCCESS;
- if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) != 0UL) {
- ERROR("ID_AA64PFR0_EL1: SVE enabled\n");
- rc = TEST_RESULT_FAIL;
- }
- if (r_regs->id_aa64zfr0_el1 != 0UL) {
- ERROR("ID_AA64ZFR0_EL1: Realm reported non-zero value\n");
- rc = TEST_RESULT_FAIL;
- }
- }
-
-rm_realm:
- host_destroy_realm();
- return rc;
-}
-
-/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in SVE Realm */
-test_result_t host_sve_realm_cmd_id_registers(void)
-{
- return _host_sve_realm_check_id_registers(true);
-}
-
-/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in non SVE Realm */
-test_result_t host_non_sve_realm_cmd_id_registers(void)
-{
- return _host_sve_realm_check_id_registers(false);
-}
-
-static void print_sve_vl_bitmap(uint32_t vl_bitmap)
-{
- for (uint8_t vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
- if ((vl_bitmap & BIT_32(vq)) != 0U) {
- INFO("\t%u\n", SVE_VQ_TO_BITS(vq));
- }
- }
-}
-
-/* Create SVE Realm and probe all the supported VLs */
-test_result_t host_sve_realm_cmd_probe_vl(void)
-{
- host_shared_data_t *sd;
- struct sve_cmd_probe_vl *rl_output;
- uint32_t vl_bitmap_expected;
- u_register_t rmi_feat_reg0;
- test_result_t rc;
- bool realm_rc;
- uint8_t sve_vq;
-
- 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;
- }
-
- /*
- * Configure TFTF with sve_vq and probe all VLs and compare it with
- * the bitmap returned from Realm
- */
- vl_bitmap_expected = sve_probe_vl(sve_vq);
-
- realm_rc = host_enter_realm_execute(REALM_SVE_PROBE_VL, NULL,
- RMI_EXIT_HOST_CALL, 0U);
- if (!realm_rc) {
- rc = TEST_RESULT_FAIL;
- goto rm_realm;
- }
-
- sd = host_get_shared_structure(0U);
- rl_output = (struct sve_cmd_probe_vl *)sd->realm_cmd_output_buffer;
-
- INFO("Supported SVE vector length in bits (expected):\n");
- print_sve_vl_bitmap(vl_bitmap_expected);
-
- INFO("Supported SVE vector length in bits (probed):\n");
- print_sve_vl_bitmap(rl_output->vl_bitmap);
-
- if (vl_bitmap_expected == rl_output->vl_bitmap) {
- rc = TEST_RESULT_SUCCESS;
- } else {
- rc = TEST_RESULT_FAIL;
- }
-
-rm_realm:
- if (!host_destroy_realm()) {
- return TEST_RESULT_FAIL;
- }
-
- return rc;
-}
-
-/* Check whether RMM preserves NS ZCR_EL2 register. */
-test_result_t host_sve_realm_check_config_register(void)
-{
- u_register_t ns_zcr_el2, ns_zcr_el2_cur;
- u_register_t rmi_feat_reg0;
- test_result_t rc;
- uint8_t vq;
-
- SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
-
- CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
-
- vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
-
- rc = host_create_sve_realm_payload(true, vq);
- if (rc != TEST_RESULT_SUCCESS) {
- return rc;
- }
-
- /*
- * Configure TFTF from 0 to SVE_VQ_ARCH_MAX, and in each iteration check
- * if NS ZCR_EL2 is same before and after call to run Realm.
- */
- rc = TEST_RESULT_SUCCESS;
- for (vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
- bool realm_rc;
-
- sve_config_vq(vq);
- ns_zcr_el2 = read_zcr_el2();
-
- /* Call Realm to run SVE command */
- realm_rc = host_enter_realm_execute(REALM_SVE_RDVL, NULL,
- RMI_EXIT_HOST_CALL, 0U);
- if (!realm_rc) {
- ERROR("Realm command REALM_SVE_RDVL failed\n");
- rc = TEST_RESULT_FAIL;
- break;
- }
- ns_zcr_el2_cur = read_zcr_el2();
-
- if (ns_zcr_el2 != ns_zcr_el2_cur) {
- ERROR("NS ZCR_EL2 expected: 0x%lx, got: 0x%lx\n",
- ns_zcr_el2, ns_zcr_el2_cur);
- rc = TEST_RESULT_FAIL;
- }
- }
-
- if (!host_destroy_realm()) {
- return TEST_RESULT_FAIL;
- }
-
- 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)
-{
-
- return !host_enter_realm_execute(REALM_SVE_OPS, NULL,
- RMI_EXIT_HOST_CALL, 0U);
-}
-
-/* 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;
-}
-
-/*
- * Check if RMM leaks Realm SVE registers.
- * This test is skipped if the supported max VQ is 128 bits, as we won't be able
- * to run NS and Realm context with lower and higher VQ respectively.
- * This test does the below steps:
- *
- * 1. Set NS SVE VQ to max and write known pattern
- * 2. NS programs ZCR_EL2 with VQ as 0 (128 bits).
- * 3. Create Realm with max VQ (higher than NS SVE VQ).
- * 4. Call Realm to fill in Z registers
- * 5. Once Realm returns, NS sets ZCR_EL2 with max VQ and reads the Z registers
- * 6. The upper bits of Z registers must be either 0 or the old values filled by
- * NS world at step 1.
- */
-test_result_t host_sve_realm_check_vectors_leaked(void)
-{
- u_register_t rmi_feat_reg0;
- uint8_t *regs_base_wr, *regs_base_rd;
- test_result_t rc;
- bool realm_rc;
- uint8_t sve_vq;
-
- 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);
-
- /* Skip test if the supported max VQ is 128 bits */
- if (sve_vq == SVE_VQ_ARCH_MIN) {
- return TEST_RESULT_SKIPPED;
- }
-
- /* 1. Set NS SVE VQ to max and write known pattern */
- sve_config_vq(sve_vq);
- (void)memset((void *)&ns_sve_vectors_write, 0xAA,
- SVE_VQ_TO_BYTES(sve_vq) * SVE_NUM_VECTORS);
- sve_fill_vector_regs(ns_sve_vectors_write);
-
- /* 2. NS programs ZCR_EL2 with VQ as 0 */
- sve_config_vq(SVE_VQ_ARCH_MIN);
-
- /* 3. Create Realm with max VQ (higher than NS SVE VQ) */
- rc = host_create_sve_realm_payload(true, sve_vq);
- if (rc != TEST_RESULT_SUCCESS) {
- return rc;
- }
-
- /* 4. Call Realm to fill in Z registers */
- realm_rc = host_enter_realm_execute(REALM_SVE_FILL_REGS, NULL,
- RMI_EXIT_HOST_CALL, 0U);
- if (!realm_rc) {
- rc = TEST_RESULT_FAIL;
- goto rm_realm;
- }
-
- /* 5. NS sets ZCR_EL2 with max VQ and reads the Z registers */
- sve_config_vq(sve_vq);
- sve_read_vector_regs(ns_sve_vectors_read);
-
- /*
- * 6. The upper bits in Z vectors (sve_vq - SVE_VQ_ARCH_MIN) must
- * be either 0 or the old values filled by NS world.
- * TODO: check if upper bits are zero
- */
- regs_base_wr = (uint8_t *)&ns_sve_vectors_write;
- regs_base_rd = (uint8_t *)&ns_sve_vectors_read;
-
- rc = TEST_RESULT_SUCCESS;
- for (int i = 0U; i < SVE_NUM_VECTORS; i++) {
- if (memcmp(regs_base_wr + (i * SVE_VQ_TO_BYTES(sve_vq)),
- regs_base_rd + (i * SVE_VQ_TO_BYTES(sve_vq)),
- SVE_VQ_TO_BYTES(sve_vq)) != 0) {
- ERROR("SVE Z%d mismatch\n", i);
- rc = TEST_RESULT_FAIL;
- }
- }
-
-rm_realm:
- if (!host_destroy_realm()) {
- return TEST_RESULT_FAIL;
- }
-
- return rc;
-}
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_spm.c b/tftf/tests/runtime_services/realm_payload/host_realm_spm.c
index 64de113..a187584 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_spm.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_spm.c
@@ -22,18 +22,16 @@
static const struct ffa_uuid expected_sp_uuids[] = { {PRIMARY_UUID} };
static struct mailbox_buffers mb;
static bool secure_mailbox_initialised;
-static fpu_reg_state_t fpu_temp_ns;
-typedef enum test_rl_sec_fp_cmd {
- CMD_SIMD_NS_FILL = 0U,
- CMD_SIMD_NS_CMP,
- CMD_SIMD_RL_FILL,
- CMD_SIMD_RL_CMP,
- CMD_MAX_THREE_WORLD,
- CMD_SIMD_SEC_FILL,
- CMD_SIMD_SEC_CMP,
- CMD_MAX_COUNT
-} realm_test_cmd_t;
+static fpu_state_t ns_fpu_state_write;
+static fpu_state_t ns_fpu_state_read;
+
+typedef enum security_state {
+ NONSECURE_WORLD = 0U,
+ REALM_WORLD,
+ SECURE_WORLD,
+ SECURITY_STATE_MAX
+} security_state_t;
/*
* This function helps to Initialise secure_mailbox, creates realm payload and
@@ -42,9 +40,6 @@
*/
static test_result_t init_sp(void)
{
- /* Verify that FFA is there and that it has the correct version. */
- SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
-
if (!secure_mailbox_initialised) {
GET_TFTF_MAILBOX(mb);
CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
@@ -55,22 +50,8 @@
static test_result_t init_realm(void)
{
- u_register_t retrmm;
u_register_t rec_flag[1] = {RMI_RUNNABLE};
- if (get_armv9_2_feat_rme_support() == 0U) {
- return TEST_RESULT_SKIPPED;
- }
-
- retrmm = host_rmi_version();
-
- /*
- * Skip test if RMM is TRP, TRP version is always null.
- */
- if (retrmm == 0UL) {
- return TEST_RESULT_SKIPPED;
- }
-
/*
* Initialise Realm payload
*/
@@ -203,6 +184,12 @@
struct ffa_value ret_values;
test_result_t res;
+ /* Verify RME is present and RMM is not TRP */
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ /* Verify that FFA is there and that it has the correct version. */
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
+
res = init_sp();
if (res != TEST_RESULT_SUCCESS) {
return res;
@@ -215,17 +202,17 @@
/* Enable trusted watchdog interrupt as IRQ in the secure side. */
if (!enable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
- return TEST_RESULT_FAIL;
+ goto destroy_realm;
}
/*
* Send a message to SP1 through direct messaging.
*/
- ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER, (REALM_TIME_SLEEP/2));
-
+ ret_values = cactus_send_twdog_cmd(SENDER, RECEIVER,
+ (REALM_TIME_SLEEP/2));
if (!is_ffa_direct_response(ret_values)) {
ERROR("Expected a direct response for starting TWDOG timer\n");
- return TEST_RESULT_FAIL;
+ goto destroy_realm;
}
/*
@@ -240,8 +227,7 @@
*/
if (!host_realm_handle_fiq_exit(realm_ptr, 0U)) {
ERROR("Trusted watchdog timer interrupt not fired\n");
- host_destroy_realm();
- return TEST_RESULT_FAIL;
+ goto destroy_realm;
}
/* Check for the last serviced secure virtual interrupt. */
@@ -250,18 +236,18 @@
if (!is_ffa_direct_response(ret_values)) {
ERROR("Expected a direct response for last serviced interrupt"
" command\n");
- return TEST_RESULT_FAIL;
+ goto destroy_realm;
}
/* Make sure Trusted Watchdog timer interrupt was serviced*/
if (cactus_get_response(ret_values) != IRQ_TWDOG_INTID) {
ERROR("Trusted watchdog timer interrupt not serviced by SP\n");
- return TEST_RESULT_FAIL;
+ goto destroy_realm;
}
/* Disable Trusted Watchdog interrupt. */
if (!disable_trusted_wdog_interrupt(SENDER, RECEIVER)) {
- return TEST_RESULT_FAIL;
+ goto destroy_realm;
}
if (!host_destroy_realm()) {
@@ -270,91 +256,148 @@
}
return TEST_RESULT_SUCCESS;
+
+destroy_realm:
+ host_destroy_realm();
+ return TEST_RESULT_FAIL;
+}
+
+/* Choose a random security state that is different from the 'current' state */
+static security_state_t get_random_security_state(security_state_t current,
+ bool is_sp_present)
+{
+ security_state_t next;
+
+ /*
+ * 3 world config: Switch between NS world and Realm world as Secure
+ * world is not enabled or SP is not loaded.
+ */
+ if (!is_sp_present) {
+ if (current == NONSECURE_WORLD) {
+ return REALM_WORLD;
+ } else {
+ return NONSECURE_WORLD;
+ }
+ }
+
+ /*
+ * 4 world config: Randomly select a security_state between Realm, NS
+ * and Secure until the new state is not equal to the current state.
+ */
+ while (true) {
+ next = rand() % SECURITY_STATE_MAX;
+ if (next == current) {
+ continue;
+ }
+
+ break;
+ }
+
+ return next;
}
/*
- * Test that FPU/SIMD state are preserved during a randomly context switch
- * between secure/non-secure/realm(R-EL1)worlds.
- * FPU/SIMD state consist of the 32 SIMD vectors, FPCR and FPSR registers,
- * the test runs for 1000 iterations with random combination of:
- * SECURE_FILL_FPU, SECURE_READ_FPU, REALM_FILL_FPU, REALM_READ_FPU,
- * NONSECURE_FILL_FPU, NONSECURE_READ_FPU commands,to test all possible situations
- * of synchronous context switch between worlds, while the content of those registers
- * is being used.
+ * Test whether FPU/SIMD state (32 SIMD vectors, FPCR and FPSR registers) are
+ * preserved during a random context switch between Secure/Non-Secure/Realm world
+ *
+ * Below steps are performed by this test:
+ *
+ * Init:
+ * Fill FPU registers with random values in
+ * 1. NS World (NS-EL2)
+ * 2. Realm world (R-EL1)
+ * 3. Secure world (S-EL1) (if SP loaded)
+ *
+ * Test loop:
+ * security_state_next = get_random_security_state(current, is_sp_present)
+ *
+ * switch to security_state_next
+ * if (FPU registers read != last filled values)
+ * break loop; return TC_FAIL
+ *
+ * Fill FPU registers with new random values for the next comparison.
*/
test_result_t host_realm_fpu_access_in_rl_ns_se(void)
{
- int cmd = -1, old_cmd = -1, cmd_max;
+ security_state_t sec_state;
+ bool is_sp_present;
test_result_t res;
- res = init_sp();
- if (res != TEST_RESULT_SUCCESS) {
- cmd_max = CMD_MAX_THREE_WORLD;
- } else {
- cmd_max = CMD_MAX_COUNT;
- if (!fpu_fill_sec()) {
- ERROR("fpu_fill_sec error\n");
- return TEST_RESULT_FAIL;
- }
- }
+ /* Verify RME is present and RMM is not TRP */
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ /* Verify that FFA is there and that it has the correct version. */
+ SKIP_TEST_IF_FFA_VERSION_LESS_THAN(1, 1);
res = init_realm();
if (res != TEST_RESULT_SUCCESS) {
return res;
}
- /*
- * Fill all 3 world's FPU/SIMD state regs with some known values in the
- * beginning to have something later to compare to.
- */
- fpu_state_fill_regs_and_template(&fpu_temp_ns);
+ /* Fill FPU registers in Non-secure world */
+ fpu_state_write_rand(&ns_fpu_state_write);
+
+ /* Fill FPU registers in Realm world */
if (!fpu_fill_rl()) {
ERROR("fpu_fill_rl error\n");
goto destroy_realm;
}
+ sec_state = REALM_WORLD;
- for (uint32_t i = 0; i < 1000; i++) {
- cmd = rand() % cmd_max;
- if ((cmd == old_cmd) || cmd == CMD_MAX_THREE_WORLD) {
- continue;
+ /* Fill FPU registers in Secure world if present */
+ res = init_sp();
+ if (res == TEST_RESULT_SUCCESS) {
+ if (!fpu_fill_sec()) {
+ ERROR("fpu_fill_sec error\n");
+ goto destroy_realm;
}
- old_cmd = cmd;
- switch (cmd) {
- case CMD_SIMD_NS_FILL:
- /* Non secure world fill FPU/SIMD state registers */
- fpu_state_fill_regs_and_template(&fpu_temp_ns);
- break;
- case CMD_SIMD_NS_CMP:
- /* Normal world verify its FPU/SIMD state registers data */
- if (!fpu_state_compare_template(&fpu_temp_ns)) {
+ sec_state = SECURE_WORLD;
+ is_sp_present = true;
+ } else {
+ is_sp_present = false;
+ }
+
+ for (uint32_t i = 0; i < 128; i++) {
+ sec_state = get_random_security_state(sec_state, is_sp_present);
+
+ switch (sec_state) {
+ case NONSECURE_WORLD:
+ /* NS world verify its FPU/SIMD state registers */
+ fpu_state_read(&ns_fpu_state_read);
+ if (fpu_state_compare(&ns_fpu_state_write,
+ &ns_fpu_state_read)) {
ERROR("%s failed %d\n", __func__, __LINE__);
goto destroy_realm;
}
+
+ /* Fill FPU state with new random values in NS world */
+ fpu_state_write_rand(&ns_fpu_state_write);
break;
- case CMD_SIMD_SEC_FILL:
- /* secure world fill FPU/SIMD state registers */
- if (!fpu_fill_sec()) {
- goto destroy_realm;
- }
- break;
- case CMD_SIMD_SEC_CMP:
- /* Secure world verify its FPU/SIMD state registers data */
- if (!fpu_cmp_sec()) {
- goto destroy_realm;
- }
- break;
- case CMD_SIMD_RL_FILL:
- /* Realm R-EL1 world fill FPU/SIMD state registers */
- if (!fpu_fill_rl()) {
- goto destroy_realm;
- }
- break;
- case CMD_SIMD_RL_CMP:
- /* Realm R-EL1 world verify its FPU/SIMD state registers data */
+ case REALM_WORLD:
+ /* Realm world verify its FPU/SIMD state registers */
if (!fpu_cmp_rl()) {
goto destroy_realm;
}
+
+ /* Fill FPU state with new random values in Realm */
+ if (!fpu_fill_rl()) {
+ goto destroy_realm;
+ }
+
+ break;
+ case SECURE_WORLD:
+ /* Secure world verify its FPU/SIMD state registers */
+ if (!fpu_cmp_sec()) {
+ goto destroy_realm;
+ }
+
+ /* Fill FPU state with new random values in SP */
+ if (!fpu_fill_sec()) {
+ goto destroy_realm;
+
+ }
+
break;
default:
break;
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 efd6c8a..cfc931f 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
@@ -19,20 +19,12 @@
static const struct ffa_uuid expected_sp_uuids[] = { {PRIMARY_UUID} };
-static test_result_t fp_vector_compare(uint8_t *a, uint8_t *b,
- size_t vector_size, uint8_t vectors_num)
-{
- if (memcmp(a, b, vector_size * vectors_num) != 0) {
- return TEST_RESULT_FAIL;
- }
- return TEST_RESULT_SUCCESS;
-}
-
-static sve_vector_t sve_vectors_input[SVE_NUM_VECTORS] __aligned(16);
-static sve_vector_t sve_vectors_output[SVE_NUM_VECTORS] __aligned(16);
+static sve_z_regs_t sve_vectors_input;
+static sve_z_regs_t sve_vectors_output;
static int sve_op_1[NS_SVE_OP_ARRAYSIZE];
static int sve_op_2[NS_SVE_OP_ARRAYSIZE];
-static fpu_reg_state_t g_fpu_template;
+static fpu_state_t g_fpu_state_write;
+static fpu_state_t g_fpu_state_read;
/*
* Tests that SIMD vectors and FPU state are preserved during the context switches between
@@ -48,7 +40,7 @@
**********************************************************************/
CHECK_SPMC_TESTING_SETUP(1, 1, expected_sp_uuids);
- fpu_state_fill_regs_and_template(&g_fpu_template);
+ fpu_state_write_rand(&g_fpu_state_write);
struct ffa_value ret = cactus_req_simd_fill_send_cmd(SENDER, RECEIVER);
if (!is_ffa_direct_response(ret)) {
@@ -68,9 +60,14 @@
if (cactus_get_response(ret) == CACTUS_ERROR) {
return TEST_RESULT_FAIL;
}
+
/* Normal world verify its FPU/SIMD state registers data */
- return fpu_state_compare_template(&g_fpu_template) ? TEST_RESULT_SUCCESS :
- TEST_RESULT_FAIL;
+ fpu_state_read(&g_fpu_state_read);
+ if (fpu_state_compare(&g_fpu_state_write, &g_fpu_state_read) != 0) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
}
/*
@@ -95,15 +92,15 @@
* 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);
+ memset(sve_vectors_input, 0, sizeof(sve_vectors_input));
+ memset(sve_vectors_output, 0, sizeof(sve_vectors_output));
/* Set ZCR_EL2.LEN to implemented VL (constrained by EL3). */
write_zcr_el2(0xf);
isb();
/* Get the implemented VL. */
- vl = sve_vector_length_get();
+ vl = sve_rdvl_1();
/* Fill each vector for the VL size with a fixed pattern. */
sve_vector = (uint8_t *) sve_vectors_input;
@@ -113,7 +110,7 @@
}
/* Fill SVE vector registers with the buffer contents prepared above. */
- sve_fill_vector_regs(sve_vectors_input);
+ sve_z_regs_write(&sve_vectors_input);
/*
* Call cactus secure partition which uses SIMD (and expect it doesn't
@@ -130,12 +127,14 @@
}
/* Get the SVE vectors state after returning to normal world. */
- sve_read_vector_regs(sve_vectors_output);
+ sve_z_regs_read(&sve_vectors_output);
/* 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);
+ if (sve_z_regs_compare(&sve_vectors_input, &sve_vectors_output) != 0UL) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
}
/*
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
index 406fbb2..a6d4d47 100644
--- a/tftf/tests/tests-realm-payload.mk
+++ b/tftf/tests/tests-realm-payload.mk
@@ -13,7 +13,7 @@
host_realm_payload_multiple_rec_tests.c \
host_realm_payload_tests.c \
host_realm_spm.c \
- host_realm_payload_sve_tests.c \
+ host_realm_payload_simd_tests.c \
)
TESTS_SOURCES += \
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 188ff29..10cc04b 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -34,7 +34,7 @@
function="host_realm_sec_interrupt_can_preempt_rl" />
<testcase name="Check that FPU state registers context is preserved in RL/SE/NS"
function="host_realm_fpu_access_in_rl_ns_se" />
- <!-- Test Realm with SVE support -->
+ <!-- Test case related to SVE support and SIMD state -->
<testcase name="Check RMI reports proper SVE VL"
function="host_check_rmi_reports_proper_sve_vl" />
<testcase name="Create SVE Realm with invalid VL"
@@ -53,6 +53,11 @@
function="host_sve_realm_check_vectors_operations" />
<testcase name="Check if RMM does not leak Realm SVE vector registers"
function="host_sve_realm_check_vectors_leaked" />
+ <testcase name="Check if Realm gets undefined abort if it access SVE"
+ function="host_non_sve_realm_check_undef_abort" />
+ <testcase name="Check various SIMD state preserved across NS/RL switch"
+ function="host_and_realm_check_simd" />
+ <!-- Test case related to PAuth -->
<testcase name="Check if PAuth keys are preserved in RL/SE/NS"
function="host_realm_enable_pauth" />
<testcase name="Generate PAuth Fault by overwriting LR"