feat(fpu): add helper routines to read, write, compare FPU registers

Add helper routines to read, write, write_rand and compare FPU state
and FPU control/status registers.

These helper routines can be called by testcases running in NS-EL2,
R-EL1, S-EL1 payload. The caller has to pass memory to read/write FPU
registers.

Signed-off-by: Arunachalam Ganapathy <arunachalam.ganapathy@arm.com>
Change-Id: I10ae5487c9f58e46434c1bd5b42fd458ec755045
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;
 }