Add tests for MTE support

TF-A now has support for the new Memory Tagging Extension in ARMv8.5,
see commit 91624b7fed52 ("Merge changes from topic "jc/mte_enable"
into integration").

This patch creates and enables tests to ensure that the extension is
being properly enabled and that no undesired leakages occur.

Change-Id: I7708fb23a12e2f35a97533f296aaa53db776ddd2
Signed-off-by: Justin Chadwell <justin.chadwell@arm.com>
Signed-off-by: Sandrine Bailleux <sandrine.bailleux@arm.com>
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 141f00c..77cf7fd 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -109,6 +109,15 @@
 		}								\
 	} while (0)
 
+#define SKIP_TEST_IF_MTE_SUPPORT_LESS_THAN(n)					\
+	do {									\
+		if (get_armv8_5_mte_support() < (n)) {				\
+			tftf_testcase_printf(					\
+				"Memory Tagging Extension not supported\n");	\
+			return TEST_RESULT_SKIPPED;				\
+		}								\
+	} while (0)
+
 #define SKIP_TEST_IF_MM_VERSION_LESS_THAN(major, minor)				\
 	do {									\
 		smc_args version_smc = { MM_VERSION_AARCH32 };			\
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index a62f13c..1d5cc11 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -222,6 +222,13 @@
 
 #define SSBS_UNAVAILABLE	ULL(0)	/* No architectural SSBS support */
 
+#define ID_AA64PFR1_EL1_MTE_SHIFT	U(8)
+#define ID_AA64PFR1_EL1_MTE_MASK	ULL(0xf)
+
+#define MTE_UNIMPLEMENTED	ULL(0)
+#define MTE_IMPLEMENTED_EL0	ULL(1)	/* MTE is only implemented at EL0 */
+#define MTE_IMPLEMENTED_ELX	ULL(2)	/* MTE is implemented at all ELs */
+
 /* ID_PFR1_EL1 definitions */
 #define ID_PFR1_VIRTEXT_SHIFT	U(12)
 #define ID_PFR1_VIRTEXT_MASK	U(0xf)
@@ -278,6 +285,7 @@
 
 /* SCR definitions */
 #define SCR_RES1_BITS		((U(1) << 4) | (U(1) << 5))
+#define SCR_ATA_BIT		(U(1) << 26)
 #define SCR_FIEN_BIT		(U(1) << 21)
 #define SCR_API_BIT		(U(1) << 17)
 #define SCR_APK_BIT		(U(1) << 16)
@@ -903,4 +911,12 @@
  ******************************************************************************/
 #define SSBS			S3_3_C4_C2_6
 
+/*******************************************************************************
+ * Armv8.5 - Memory Tagging Extension Registers
+ ******************************************************************************/
+#define TFSRE0_EL1		S3_0_C5_C6_1
+#define TFSR_EL1		S3_0_C5_C6_0
+#define RGSR_EL1		S3_0_C1_C0_5
+#define GCR_EL1			S3_0_C1_C0_6
+
 #endif /* ARCH_H */
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 20240ec..86c0763 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -62,4 +62,10 @@
 		ID_AA64MMFR2_EL1_ST_MASK) == 1U;
 }
 
+static inline unsigned int get_armv8_5_mte_support(void)
+{
+	return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_MTE_SHIFT) &
+		ID_AA64PFR1_EL1_MTE_MASK);
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index 9d1ebb8..d16960a 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -469,6 +469,12 @@
 DEFINE_RENAME_SYSREG_RW_FUNCS(apgakeyhi_el1, APGAKeyHi_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(apgakeylo_el1, APGAKeyLo_EL1)
 
+/* MTE registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(tfsre0_el1, TFSRE0_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(rgsr_el1, RGSR_EL1)
+DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1)
+
 #define IS_IN_EL(x) \
 	(GET_EL(read_CurrentEl()) == MODE_EL##x)
 
diff --git a/tftf/tests/extensions/mte/test_mte.c b/tftf/tests/extensions/mte/test_mte.c
new file mode 100644
index 0000000..13da667
--- /dev/null
+++ b/tftf/tests/extensions/mte/test_mte.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <tftf.h>
+#include <tftf_lib.h>
+#include <tsp.h>
+#include <test_helpers.h>
+
+test_result_t test_mte_instructions(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef AARCH64
+	SKIP_TEST_IF_MTE_SUPPORT_LESS_THAN(MTE_IMPLEMENTED_EL0);
+
+	/* irg */
+	__asm__ volatile (".inst 0xD29BD5A9");
+	__asm__ volatile (".inst 0x9ADF1129");
+	/* addg */
+	__asm__ volatile (".inst 0x91800129");
+	/* subg */
+	__asm__ volatile (".inst 0xD1800129");
+
+	return TEST_RESULT_SUCCESS;
+#endif /* AARCH64 */
+}
+
+test_result_t test_mte_leakage(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef AARCH64
+	smc_args tsp_svc_params;
+	int gcr_el1;
+
+	SKIP_TEST_IF_MTE_SUPPORT_LESS_THAN(MTE_IMPLEMENTED_ELX);
+	SKIP_TEST_IF_TSP_NOT_PRESENT();
+
+	/* We only test gcr_el1 as writes to other MTE registers are ignored */
+	write_gcr_el1(0xdd);
+
+	/* Standard SMC to ADD two numbers */
+	tsp_svc_params.fid = TSP_STD_FID(TSP_ADD);
+	tsp_svc_params.arg1 = 4;
+	tsp_svc_params.arg2 = 6;
+	tftf_smc(&tsp_svc_params);
+
+	gcr_el1 = read_gcr_el1();
+	if (gcr_el1 != 0xdd) {
+		printf("gcr_el1 has changed to %d\n", gcr_el1);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+#endif /* AARCH64 */
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index cb4c1f9..9102b35 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -6,6 +6,7 @@
 
 TESTS_SOURCES	+=	$(addprefix tftf/tests/,			\
 	extensions/amu/test_amu.c					\
+	extensions/mte/test_mte.c					\
 	extensions/sve/sve_operations.S					\
 	extensions/sve/test_sve.c					\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_1.c		\
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index e641437..158cb04 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -16,6 +16,8 @@
     <testcase name="Use Pointer Authentication Instructions" function="test_pauth_instructions" />
     <testcase name="Check for Pointer Authentication key leakage from EL3" function="test_pauth_leakage" />
     <testcase name="Check for Pointer Authentication key leakage from TSP" function="test_pauth_leakage_tsp" />
+    <testcase name="Use MTE Instructions" function="test_mte_instructions" />
+    <testcase name="Check for MTE register leakage" function="test_mte_leakage" />
   </testsuite>
 
   <testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests">