Add unit tests for Pointer Authentication

Add unit tests to:
    Test access to the key registers.
    Use the pointer authentication instructions.
    Call psci version and check the EL3 pointer authentication keys
    aren't leaked.
    Make a tsp call and check the secure world keys aren't leaked.

Change-Id: Ic7940757e6f9fc905ccef8c035e0c22b47b35cd7
Signed-off-by: Joel Hutton <Joel.Hutton@Arm.com>
diff --git a/tftf/tests/extensions/ptrauth/test_ptrauth.c b/tftf/tests/extensions/ptrauth/test_ptrauth.c
new file mode 100644
index 0000000..a1f41e2
--- /dev/null
+++ b/tftf/tests/extensions/ptrauth/test_ptrauth.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <psci.h>
+#include <smccc.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+#include <tftf.h>
+#include <tsp.h>
+#include <string.h>
+
+/* The length of the array used to hold the pauth keys */
+#define LENGTH_KEYS 10
+
+#ifndef AARCH32
+static void read_pauth_keys(uint64_t *pauth_keys, unsigned int len)
+{
+	assert(len >= LENGTH_KEYS);
+
+	memset(pauth_keys, 0, len * sizeof(uint64_t));
+
+	if (is_armv8_3_pauth_apa_api_present()) {
+		/* read instruction keys a and b (both 128 bit) */
+		pauth_keys[0] = read_apiakeylo_el1();
+		pauth_keys[1] = read_apiakeyhi_el1();
+
+		pauth_keys[2] = read_apibkeylo_el1();
+		pauth_keys[3] = read_apibkeyhi_el1();
+
+		/* read data keys a and b (both 128 bit) */
+		pauth_keys[4] = read_apdakeylo_el1();
+		pauth_keys[5] = read_apdakeyhi_el1();
+
+		pauth_keys[6] = read_apdbkeylo_el1();
+		pauth_keys[7] = read_apdbkeyhi_el1();
+	}
+
+	if (is_armv8_3_pauth_gpa_gpi_present()) {
+		/* read generic key */
+		pauth_keys[8] = read_apgakeylo_el1();
+		pauth_keys[9] = read_apgakeyhi_el1();
+	}
+
+}
+#endif
+
+/*
+ * TF-A is expected to allow access to key registers from lower EL's,
+ * reading the keys excercises this, on failure this will trap to
+ * EL3 and crash.
+ */
+test_result_t test_pauth_reg_access(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+	uint64_t pauth_keys[LENGTH_KEYS];
+	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+	read_pauth_keys(pauth_keys, LENGTH_KEYS);
+	return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/*
+ * Makes a call to psci version, and checks that the EL3 pauth keys are not
+ * leaked when it returns
+ */
+#if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 0)
+__attribute__((target("sign-return-address=all")))
+#endif
+test_result_t test_pauth_leakage(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+	uint64_t pauth_keys_before[LENGTH_KEYS];
+	uint64_t pauth_keys_after[LENGTH_KEYS];
+	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+
+	read_pauth_keys(pauth_keys_before, LENGTH_KEYS);
+
+	tftf_get_psci_version();
+
+	read_pauth_keys(pauth_keys_after, LENGTH_KEYS);
+
+	if (memcmp(pauth_keys_before, pauth_keys_after,
+			LENGTH_KEYS * sizeof(uint64_t)) != 0)
+		return TEST_RESULT_FAIL;
+	return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/* Uses the pauth instructions, this checks the enable PAUTH bit has been set */
+test_result_t test_pauth_instructions(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+	/*
+	 * Pointer authentication instructions (explicit encoding for compilers
+	 * that do not recognize these instructions)
+	 */
+	/* paciasp */
+	__asm__ volatile (".inst 0xD503233F");
+	/* autiasp */
+	__asm__ volatile (".inst 0xD50323BF");
+	/* paciasp */
+	__asm__ volatile (".inst 0xD503233F");
+	/* xpaclri */
+	__asm__ volatile (".inst 0xD50320FF");
+	return TEST_RESULT_SUCCESS;
+#endif
+}
+
+/*
+ * Makes a call to TSP ADD, and checks that the checks that the Secure World
+ * pauth keys are not leaked
+ */
+#if __GNUC__ > 7 || (__GNUC__ == 7 && __GNUC_MINOR__ > 0)
+__attribute__((target("sign-return-address=all")))
+#endif
+test_result_t test_pauth_leakage_tsp(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifndef AARCH32
+	smc_args tsp_svc_params;
+	smc_ret_values tsp_result = {0};
+	uint64_t pauth_keys_before[LENGTH_KEYS];
+	uint64_t pauth_keys_after[LENGTH_KEYS];
+
+	SKIP_TEST_IF_PAUTH_NOT_SUPPORTED();
+	SKIP_TEST_IF_TSP_NOT_PRESENT();
+
+	read_pauth_keys(pauth_keys_before, LENGTH_KEYS);
+
+	/* 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;
+	tsp_result = tftf_smc(&tsp_svc_params);
+
+	/*
+	 * Check the result of the addition-TSP_ADD will add
+	 * the arguments to themselves and return
+	 */
+	if (tsp_result.ret0 != 0 || tsp_result.ret1 != 8 ||
+				tsp_result.ret2 != 12) {
+		tftf_testcase_printf("TSP add returned wrong result:"
+				     "got %d %d %d expected: 0 8 12\n",
+						(unsigned int)tsp_result.ret0,
+						(unsigned int)tsp_result.ret1,
+						(unsigned int)tsp_result.ret2);
+
+		return TEST_RESULT_FAIL;
+	}
+	read_pauth_keys(pauth_keys_after, LENGTH_KEYS);
+
+	if (memcmp(pauth_keys_before, pauth_keys_after,
+			LENGTH_KEYS * sizeof(uint64_t)) != 0)
+		return TEST_RESULT_FAIL;
+	return TEST_RESULT_SUCCESS;
+#endif
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index 38271dc..daf9528 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -10,4 +10,5 @@
 	extensions/sve/test_sve.c					\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_1.c		\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_2.c		\
+	extensions/ptrauth/test_ptrauth.c				\
 )
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index 666d5a0..4c3ad43 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -12,6 +12,10 @@
     <testcase name="AMUv1 non-zero counters" function="test_amu_nonzero_ctr" />
     <testcase name="AMUv1 suspend/resume" function="test_amu_suspend_resume" />
     <testcase name="SVE support" function="test_sve_support" />
+    <testcase name="Access Pointer Authentication Registers" function="test_pauth_reg_access" />
+    <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" />
   </testsuite>
 
   <testsuite name="ARM_ARCH_SVC" description="Arm Architecture Service tests">