test(tftf): test PAuth in Realm

- Enable PAuth in Realm RL1 by default.
- Check if PAuth keys are accessible in Realm RL1.
- Check if Realm PAuth keys are preserved across RMM entry/exit.
- Check if NS PAuth keys are preserved across RMM entry/exit.
- Generate PAuth fault by cloberring LR.

Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: I85d8e03ec604c96117555e7aa866453cb2745cfe
diff --git a/realm/aarch64/realm_entrypoint.S b/realm/aarch64/realm_entrypoint.S
index 28a37de..e0638f0 100644
--- a/realm/aarch64/realm_entrypoint.S
+++ b/realm/aarch64/realm_entrypoint.S
@@ -49,9 +49,14 @@
 	mov	x1, REALM_MAX_LOAD_IMG_SIZE
 	add	x1, x1, x0
 	bl	fixup_gdt_reloc
+#if ENABLE_PAUTH
+	bl	pauth_init_enable
+#endif
 
+loop:
 	/* And jump to the C entrypoint. */
-	b	realm_payload_main
+	bl	realm_payload_main
+	b	loop
 endfunc realm_entrypoint
 
 /* Initialize architectural state. */
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index 61d4493..4bd260c 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -12,6 +12,9 @@
 bool test_pmuv3_event_works_realm(void);
 bool test_pmuv3_rmm_preserves(void);
 bool test_pmuv3_overflow_interrupt(void);
+bool test_realm_pauth_set_cmd(void);
+bool test_realm_pauth_check_cmd(void);
+bool test_realm_pauth_fault(void);
 bool test_realm_sve_rdvl(void);
 bool test_realm_sve_read_id_registers(void);
 bool test_realm_sve_probe_vl(void);
diff --git a/realm/realm.mk b/realm/realm.mk
index 047dff8..77499d0 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -28,6 +28,7 @@
 	aarch64/realm_exceptions.S					\
 	realm_debug.c							\
 	realm_interrupt.c						\
+	realm_pauth.c							\
 	realm_payload_main.c						\
 	realm_pmuv3.c							\
 	realm_rsi.c							\
@@ -52,6 +53,12 @@
 
 REALM_LINKERFILE:=	realm/realm.ld.S
 
+# ARMv8.3 Pointer Authentication support files
+REALM_SOURCES +=	lib/extensions/pauth/aarch64/pauth.c            \
+			lib/extensions/pauth/aarch64/pauth_helpers.S
+
+REALM_INCLUDES +=	-Iinclude/lib/extensions
+
 REALM_DEFINES:=
 $(eval $(call add_define,REALM_DEFINES,ARM_ARCH_MAJOR))
 $(eval $(call add_define,REALM_DEFINES,ARM_ARCH_MINOR))
diff --git a/realm/realm_pauth.c b/realm/realm_pauth.c
new file mode 100644
index 0000000..0a5a022
--- /dev/null
+++ b/realm/realm_pauth.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdio.h>
+#include <arch_features.h>
+#include <debug.h>
+#include <pauth.h>
+#include <realm_rsi.h>
+#include <sync.h>
+
+static volatile bool set_cmd_done;
+
+static bool exception_handler(void)
+{
+	u_register_t lr = read_elr_el1();
+
+	/* Disable PAuth to avoid further PAuth faults. */
+	pauth_disable();
+
+	/* Check for PAuth exception. */
+	/* Note- PAuth decode instruction clobbers PAC Fields[63:56] in case of error. */
+	if (lr & (0xFFULL << 56U)) {
+		rsi_exit_to_host(HOST_CALL_EXIT_SUCCESS_CMD);
+	}
+
+	rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+
+	/* Does not return. */
+	return false;
+}
+
+void dummy_func(void)
+{
+	realm_printf("Realm: shouldn't reach here.\n");
+	rsi_exit_to_host(HOST_CALL_EXIT_FAILED_CMD);
+}
+
+bool test_realm_pauth_fault(void)
+{
+	u_register_t ptr = (u_register_t)dummy_func;
+
+	if (!is_armv8_3_pauth_present()) {
+		return false;
+	}
+
+	register_custom_sync_exception_handler(exception_handler);
+	realm_printf("Realm: overwrite LR to generate fault.\n");
+	__asm__("mov	x17, x30;	"
+		"mov	x30, %0;	"	/* overwite LR. */
+		"isb;			"
+		"autiasp;		"
+		"ret;			"	/* fault on return.  */
+		:
+		: "r"(ptr));
+
+	/* Does not return. */
+	return false;
+}
+
+/*
+ * 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.
+ */
+bool test_realm_pauth_set_cmd(void)
+{
+	if (!is_armv8_3_pauth_present()) {
+		return false;
+	}
+	pauth_test_lib_test_intrs();
+	pauth_test_lib_fill_regs_and_template();
+	set_cmd_done = true;
+	return true;
+}
+
+bool test_realm_pauth_check_cmd(void)
+{
+	if (!is_armv8_3_pauth_present() || !set_cmd_done) {
+		return false;
+	}
+	return pauth_test_lib_compare_template();
+}
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index d99037a..e867546 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -7,10 +7,12 @@
 
 #include <stdio.h>
 
+#include <arch_features.h>
 #include <debug.h>
 #include <fpu.h>
 #include <host_realm_helper.h>
 #include <host_shared_data.h>
+#include <pauth.h>
 #include "realm_def.h"
 #include <realm_rsi.h>
 #include <realm_tests.h>
@@ -62,7 +64,6 @@
 	bool test_succeed = false;
 
 	realm_set_shared_structure((host_shared_data_t *)rsi_get_ns_buffer());
-
 	if (realm_get_shared_structure() != NULL) {
 		uint8_t cmd = realm_shared_data_get_realm_cmd();
 
@@ -71,6 +72,15 @@
 			realm_sleep_cmd();
 			test_succeed = true;
 			break;
+		case REALM_PAUTH_SET_CMD:
+			test_succeed = test_realm_pauth_set_cmd();
+			break;
+		case REALM_PAUTH_CHECK_CMD:
+			test_succeed = test_realm_pauth_check_cmd();
+			break;
+		case REALM_PAUTH_FAULT:
+			test_succeed = test_realm_pauth_fault();
+			break;
 		case REALM_GET_RSI_VERSION:
 			realm_get_rsi_version();
 			test_succeed = true;