Enable SVE for Non-secure world

This patch adds a new build option, ENABLE_SVE_FOR_NS, which when set
to one EL3 will check to see if the Scalable Vector Extension (SVE) is
implemented when entering and exiting the Non-secure world.

If SVE is implemented, EL3 will do the following:

- Entry to Non-secure world: SIMD, FP and SVE functionality is enabled.

- Exit from Non-secure world: SIMD, FP and SVE functionality is
  disabled. As SIMD and FP registers are part of the SVE Z-registers
  then any use of SIMD / FP functionality would corrupt the SVE
  registers.

The build option default is 1. The SVE functionality is only supported
on AArch64 and so the build option is set to zero when the target
archiecture is AArch32.

This build option is not compatible with the CTX_INCLUDE_FPREGS - an
assert will be raised on platforms where SVE is implemented and both
ENABLE_SVE_FOR_NS and CTX_INCLUDE_FPREGS are set to 1.

Also note this change prevents secure world use of FP&SIMD registers on
SVE-enabled platforms. Existing Secure-EL1 Payloads will not work on
such platforms unless ENABLE_SVE_FOR_NS is set to 0.

Additionally, on the first entry into the Non-secure world the SVE
functionality is enabled and the SVE Z-register length is set to the
maximum size allowed by the architecture. This includes the use case
where EL2 is implemented but not used.

Change-Id: Ie2d733ddaba0b9bef1d7c9765503155188fe7dae
Signed-off-by: David Cunado <david.cunado@arm.com>
diff --git a/lib/extensions/sve/sve.c b/lib/extensions/sve/sve.c
new file mode 100644
index 0000000..14e51bd
--- /dev/null
+++ b/lib/extensions/sve/sve.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <pubsub.h>
+#include <sve.h>
+
+static void *disable_sve_hook(const void *arg)
+{
+	uint64_t features;
+
+	features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+	if ((features & ID_AA64PFR0_SVE_MASK) == 1) {
+		uint64_t cptr;
+
+		/*
+		 * Disable SVE, SIMD and FP access for the Secure world.
+		 * As the SIMD/FP registers are part of the SVE Z-registers, any
+		 * use of SIMD/FP functionality will corrupt the SVE registers.
+		 * Therefore it is necessary to prevent use of SIMD/FP support
+		 * in the Secure world as well as SVE functionality.
+		 */
+		cptr = read_cptr_el3();
+		cptr = (cptr | TFP_BIT) & ~(CPTR_EZ_BIT);
+		write_cptr_el3(cptr);
+
+		/*
+		 * No explicit ISB required here as ERET to switch to Secure
+		 * world covers it
+		 */
+	}
+	return 0;
+}
+
+static void *enable_sve_hook(const void *arg)
+{
+	uint64_t features;
+
+	features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+	if ((features & ID_AA64PFR0_SVE_MASK) == 1) {
+		uint64_t cptr;
+
+		/*
+		 * Enable SVE, SIMD and FP access for the Non-secure world.
+		 */
+		cptr = read_cptr_el3();
+		cptr = (cptr | CPTR_EZ_BIT) & ~(TFP_BIT);
+		write_cptr_el3(cptr);
+
+		/*
+		 * No explicit ISB required here as ERET to switch to Non-secure
+		 * world covers it
+		 */
+	}
+	return 0;
+}
+
+void sve_enable(int el2_unused)
+{
+	uint64_t features;
+
+	features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT;
+	if ((features & ID_AA64PFR0_SVE_MASK) == 1) {
+		uint64_t cptr;
+#if CTX_INCLUDE_FPREGS
+		/*
+		 * CTX_INCLUDE_FPREGS is not supported on SVE enabled systems.
+		 */
+		assert(0);
+#endif
+		/*
+		 * Update CPTR_EL3 to enable access to SVE functionality for the
+		 * Non-secure world.
+		 * NOTE - assumed that CPTR_EL3.TFP is set to allow access to
+		 * the SIMD, floating-point and SVE support.
+		 *
+		 * CPTR_EL3.EZ: Set to 1 to enable access to SVE  functionality
+		 *  in the Non-secure world.
+		 */
+		cptr = read_cptr_el3();
+		cptr |= CPTR_EZ_BIT;
+		write_cptr_el3(cptr);
+
+		/*
+		 * Need explicit ISB here to guarantee that update to ZCR_ELx
+		 * and CPTR_EL2.TZ do not result in trap to EL3.
+		 */
+		isb();
+
+		/*
+		 * Ensure lower ELs have access to full vector length.
+		 */
+		write_zcr_el3(ZCR_EL3_LEN_MASK);
+
+		if (el2_unused) {
+			/*
+			 * Update CPTR_EL2 to enable access to SVE functionality
+			 * for Non-secure world, EL2 and Non-secure EL1 and EL0.
+			 * NOTE - assumed that CPTR_EL2.TFP is set to allow
+			 * access to the SIMD, floating-point and SVE support.
+			 *
+			 * CPTR_EL2.TZ: Set to 0 to enable access to SVE support
+			 *  for EL2 and Non-secure EL1 and EL0.
+			 */
+			cptr = read_cptr_el2();
+			cptr &= ~(CPTR_EL2_TZ_BIT);
+			write_cptr_el2(cptr);
+
+			/*
+			 * Ensure lower ELs have access to full vector length.
+			 */
+			write_zcr_el2(ZCR_EL2_LEN_MASK);
+		}
+		/*
+		 * No explicit ISB required here as ERET to switch to
+		 * Non-secure world covers it.
+		 */
+	}
+}
+
+SUBSCRIBE_TO_EVENT(cm_exited_normal_world, disable_sve_hook);
+SUBSCRIBE_TO_EVENT(cm_entering_normal_world, enable_sve_hook);