TF-A Tests: Enable PAuth on warm boot path

This patch provides the following features and makes
modifications listed below:
- `plat_init_apiakey()` function is replaced with `init_apkey()`
  which returns 128-bit value and uses Generic timer physical counter
  value to increase the randomness of the generated key.
  The new function can be used for generation of all ARMv8.3-PAuth keys.
- Source file `pauth.c` moved from `plat/common/aarch64`
  to `lib/extensions/pauth/aarch64` folder which contains PAuth specific
  code.
- Individual APIAKey key generation for each CPU on every warm boot.
- Per-CPU storage of APIAKey added in `tftf_suspend_context` structure.
- APIAKey key is saved/restored in arch context on entry/exit from
  suspended state.
- Added `pauth_init_enable()` function which generates, programs
  and enables APIAKey in EL1/EL2.
- Changes in documentation related to ARMv8.3-PAuth support.

Signed-off-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
Change-Id: I964b8f964bb541cbb0b2f772cb0b07aed055fe36
diff --git a/Makefile b/Makefile
index bd179b9..c200119 100644
--- a/Makefile
+++ b/Makefile
@@ -224,7 +224,7 @@
 TFTF_LDFLAGS		+= ${COMMON_LDFLAGS}
 
 ifeq (${ENABLE_PAUTH},1)
-TFTF_CFLAGS		+=	-msign-return-address=non-leaf
+TFTF_CFLAGS		+= -mbranch-protection=pac-ret
 endif
 
 NS_BL1U_SOURCES		+= ${PLAT_SOURCES} ${LIBC_SRCS}
diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst
index 6a5abb7..9759c98 100644
--- a/docs/porting-guide.rst
+++ b/docs/porting-guide.rst
@@ -361,20 +361,6 @@
 Common implementation of this function is provided in
 ``plat/common/aarch64/platform_mp_stack.S``.
 
-Function : plat_init_apiakey
-````````````````````````````
-
-::
-
-    Argument : void
-    Return   : uint64_t *
-
-This function returns a pointer to an array with the values used to set the
-``APIAKey{Hi,Lo}_EL1`` registers.
-
-This function is only needed if ARMv8.3 pointer authentication is used by
-building with ``ENABLE_PAUTH=1``.
-
 Function : tftf_platform_end()
 ``````````````````````````````
 
diff --git a/docs/user-guide.rst b/docs/user-guide.rst
index ef12c90..2e6f7ba 100644
--- a/docs/user-guide.rst
+++ b/docs/user-guide.rst
@@ -401,7 +401,7 @@
 -  ``ENABLE_PAUTH``: Boolean option to enable ARMv8.3 Pointer Authentication
    (``ARMv8.3-PAuth``) support in the Trusted Firmware-A Test Framework itself.
    If enabled, it is needed to use a compiler that supports the option
-   ``-msign-return-address``. It defaults to 0.
+   ``-mbranch-protection`` (GCC 9 and later). It defaults to 0.
 
 -  ``NEW_TEST_SESSION``: Choose whether a new test session should be started
    every time or whether the framework should determine whether a previous
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 5891c7a..20240ec 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -51,7 +51,7 @@
 static inline bool is_armv8_3_pauth_gpa_gpi_present(void)
 {
 	uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) |
-		(ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT);
+			(ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT);
 
 	return (read_id_aa64isar1_el1() & mask) != 0U;
 }
diff --git a/include/lib/extensions/pauth.h b/include/lib/extensions/pauth.h
new file mode 100644
index 0000000..a4da009
--- /dev/null
+++ b/include/lib/extensions/pauth.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PAUTH_H
+#define PAUTH_H
+
+#include <stdint.h>
+
+#ifdef __aarch64__
+/* Initialize 128-bit ARMv8.3-PAuth key */
+uint128_t init_apkey(void);
+
+/* Program APIAKey_EL1 key and enable ARMv8.3-PAuth */
+void pauth_init_enable(void);
+#endif	/* __aarch64__ */
+
+#endif /* PAUTH_H */
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index b30c41e..f3536ba 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -67,9 +67,6 @@
 /* Gets a handle for the initialised IO entity */
 void plat_get_nvm_handle(uintptr_t *handle);
 
-/* Initialize and get a pointer to a uint64_t[2] array with a 128-key */
-uint64_t *plat_init_apiakey(void);
-
 /*
  * Returns the platform topology description array. The size of this
  * array should be PLATFORM_NUM_AFFS - PLATFORM_CORE_COUNT + 1.
diff --git a/lib/extensions/pauth/aarch64/pauth.c b/lib/extensions/pauth/aarch64/pauth.c
new file mode 100644
index 0000000..03de468
--- /dev/null
+++ b/lib/extensions/pauth/aarch64/pauth.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <cdefs.h>
+#include <stdint.h>
+
+/*
+ * This is only a toy implementation to generate a seemingly random
+ * 128-bit key from sp, x30 and cntpct_el0 values.
+ */
+uint128_t init_apkey(void)
+{
+	uint64_t return_addr = (uint64_t)__builtin_return_address(0U);
+	uint64_t frame_addr = (uint64_t)__builtin_frame_address(0U);
+
+	uint64_t cntpct = read_cntpct_el0();
+
+	uint64_t key_lo = (return_addr << 13) ^ frame_addr ^ cntpct;
+	uint64_t key_hi = (frame_addr << 15) ^ return_addr ^ cntpct;
+
+	return ((uint128_t)(key_hi) << 64) | key_lo;
+}
diff --git a/lib/extensions/pauth/aarch64/pauth_helpers.S b/lib/extensions/pauth/aarch64/pauth_helpers.S
new file mode 100644
index 0000000..e15cac9
--- /dev/null
+++ b/lib/extensions/pauth/aarch64/pauth_helpers.S
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.global	pauth_init_enable
+
+/* -----------------------------------------------------------
+ * Program APIAKey_EL1 key and enable Pointer Authentication
+ * of instruction addresses in the current translation regime
+ * for the calling CPU.
+ * -----------------------------------------------------------
+ */
+func pauth_init_enable
+	stp	x29, x30, [sp, #-16]!
+
+	/* Initialize platform key */
+	bl	init_apkey
+
+	/*
+	 * Program instruction key A used by
+	 * the Trusted Firmware Test Framework
+	 */
+	msr	APIAKeyLo_EL1, x0
+	msr	APIAKeyHi_EL1, x1
+
+	/* Detect Current Exception level */
+	mrs	x0, CurrentEL
+	cmp	x0, #(MODE_EL1 << MODE_EL_SHIFT)
+	b.eq	enable_el1
+
+	/* Enable EL2 pointer authentication */
+	mrs	x0, sctlr_el2
+	orr	x0, x0, #SCTLR_EnIA_BIT
+	msr	sctlr_el2, x0
+	b	enable_exit
+
+	/* Enable EL1 pointer authentication */
+enable_el1:
+	mrs	x0, sctlr_el1
+	orr	x0, x0, #SCTLR_EnIA_BIT
+	msr	sctlr_el1, x0
+
+enable_exit:
+	isb
+
+	ldp	x29, x30, [sp], #16
+	ret
+endfunc pauth_init_enable
diff --git a/lib/power_management/hotplug/hotplug.c b/lib/power_management/hotplug/hotplug.c
index 37bfc06..76fa287 100644
--- a/lib/power_management/hotplug/hotplug.c
+++ b/lib/power_management/hotplug/hotplug.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,7 @@
 #include <drivers/arm/arm_gic.h>
 #include <drivers/console.h>
 #include <irq.h>
+#include <pauth.h>
 #include <platform.h>
 #include <platform_def.h>
 #include <power_management.h>
@@ -288,6 +289,16 @@
 {
 	/* Initialise the CPU */
 	tftf_arch_setup();
+
+#if ENABLE_PAUTH
+	/*
+	 * Program APIAKey_EL1 key and enable ARMv8.3-PAuth here as this
+	 * function doesn't return, and RETAA instuction won't be executed,
+	 * what would cause translation fault otherwise.
+	 */
+	pauth_init_enable();
+#endif /* ENABLE_PAUTH */
+
 	arm_gic_setup_local();
 
 	/* Enable the SGI used by the timer management framework */
diff --git a/lib/power_management/suspend/aarch64/asm_tftf_suspend.S b/lib/power_management/suspend/aarch64/asm_tftf_suspend.S
index 692bade..09950b5 100644
--- a/lib/power_management/suspend/aarch64/asm_tftf_suspend.S
+++ b/lib/power_management/suspend/aarch64/asm_tftf_suspend.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2019, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -54,6 +54,11 @@
 endfunc __tftf_suspend
 
 func __tftf_save_arch_context
+#if ENABLE_PAUTH
+	mrs     x1, APIAKeyLo_EL1
+	mrs     x2, APIAKeyHi_EL1
+	stp	x1, x2, [x0, #SUSPEND_CTX_APIAKEY_OFFSET]
+#endif
 	JUMP_EL1_OR_EL2 x1, 1f, 2f, dead
 1:	mrs	x1, mair_el1
 	mrs	x2, cpacr_el1
@@ -61,9 +66,9 @@
 	mrs	x4, tcr_el1
 	mrs	x5, vbar_el1
 	mrs	x6, sctlr_el1
-	stp	x1, x2, [x0]
-	stp	x3, x4, [x0, #16]
-	stp	x5, x6, [x0, #32]
+	stp	x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET]
+	stp	x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET]
+	stp	x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET]
 	ret
 
 2:	mrs	x1, mair_el2
@@ -72,9 +77,9 @@
 	mrs	x4, tcr_el2
 	mrs	x5, vbar_el2
 	mrs	x6, sctlr_el2
-	stp	x1, x2, [x0]
-	stp	x3, x4, [x0, #16]
-	stp	x5, x6, [x0, #32]
+	stp	x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET]
+	stp	x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET]
+	stp	x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET]
 	ret
 endfunc __tftf_save_arch_context
 
@@ -86,9 +91,9 @@
 	JUMP_EL1_OR_EL2 x1, 1f, 2f, dead
 1:	/* Invalidate local tlb entries before turning on MMU */
 	tlbi	vmalle1
-	ldp	x1, x2, [x0]
-	ldp	x3, x4, [x0, #16]
-	ldp	x5, x6, [x0, #32]
+	ldp	x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET]
+	ldp	x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET]
+	ldp	x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET]
 	msr	mair_el1, x1
 	msr	cpacr_el1, x2
 	msr	ttbr0_el1, x3
@@ -101,13 +106,13 @@
 	msr	sctlr_el1, x6
 	/* Ensure the MMU enable takes effect immediately */
 	isb
-	b restore_callee_regs
+	b	restore_callee_regs
 
 	/* Invalidate local tlb entries before turning on MMU */
 2:	tlbi	alle2
-	ldp	x1, x2, [x0]
-	ldp	x3, x4, [x0, #16]
-	ldp	x5, x6, [x0, #32]
+	ldp	x1, x2, [x0, #SUSPEND_CTX_MAIR_OFFSET]
+	ldp	x3, x4, [x0, #SUSPEND_CTX_TTBR0_OFFSET]
+	ldp	x5, x6, [x0, #SUSPEND_CTX_VBAR_OFFSET]
 	msr	mair_el2, x1
 	msr	hcr_el2, x2
 	msr	ttbr0_el2, x3
@@ -122,6 +127,11 @@
 	isb
 
 restore_callee_regs:
+#if ENABLE_PAUTH
+	ldp	x1, x2, [x0, #SUSPEND_CTX_APIAKEY_OFFSET]
+	msr     APIAKeyLo_EL1, x1
+	msr     APIAKeyHi_EL1, x2
+#endif
 	ldr	x2, [x0, #SUSPEND_CTX_SP_OFFSET]
 	mov	sp, x2
 	ldr	w1, [x0, #SUSPEND_CTX_SAVE_SYSTEM_CTX_OFFSET]
diff --git a/lib/power_management/suspend/suspend_private.h b/lib/power_management/suspend/suspend_private.h
index b67bbab..bc2f3a6 100644
--- a/lib/power_management/suspend/suspend_private.h
+++ b/lib/power_management/suspend/suspend_private.h
@@ -9,11 +9,21 @@
 
 /*
  * Number of system registers we need to save/restore across a CPU suspend:
- * MAIR, CPACR_EL1/HCR_EL2, TTBR0, TCR, VBAR and SCTLR.
+ * MAIR, CPACR_EL1/HCR_EL2, TTBR0, TCR, VBAR, SCTLR,
+ * APIAKeyLo_EL1 and APIAKeyHi_EL1 (if enabled).
  */
+#if ENABLE_PAUTH
+#define NR_CTX_REGS 8
+#else
 #define NR_CTX_REGS 6
+#endif
 
 /* Offsets of the fields in the context structure. Needed by asm code. */
+#define	SUSPEND_CTX_MAIR_OFFSET		0
+#define	SUSPEND_CTX_TTBR0_OFFSET	16
+#define	SUSPEND_CTX_VBAR_OFFSET		32
+#define	SUSPEND_CTX_APIAKEY_OFFSET	48
+
 #define SUSPEND_CTX_SP_OFFSET (8 * NR_CTX_REGS)
 #define SUSPEND_CTX_SAVE_SYSTEM_CTX_OFFSET (SUSPEND_CTX_SP_OFFSET + 8)
 
diff --git a/plat/arm/fvp/platform.mk b/plat/arm/fvp/platform.mk
index 9fb84c2..bf4075d 100644
--- a/plat/arm/fvp/platform.mk
+++ b/plat/arm/fvp/platform.mk
@@ -24,7 +24,9 @@
 FIRMWARE_UPDATE := 1
 
 ifeq (${ARCH},aarch64)
-PLAT_SOURCES	+=	plat/common/aarch64/pauth.c
+# ARMv8.3 Pointer Authentication support files
+PLAT_SOURCES	+=	lib/extensions/pauth/aarch64/pauth.c		\
+			lib/extensions/pauth/aarch64/pauth_helpers.S
 endif
 
 include plat/arm/common/arm_common.mk
diff --git a/tftf/framework/main.c b/tftf/framework/main.c
index e84e450..a2e84b7 100644
--- a/tftf/framework/main.c
+++ b/tftf/framework/main.c
@@ -12,6 +12,7 @@
 #include <irq.h>
 #include <mmio.h>
 #include <nvm.h>
+#include <pauth.h>
 #include <plat_topology.h>
 #include <platform.h>
 #include <platform_def.h>
@@ -528,19 +529,12 @@
 #if ENABLE_PAUTH
 	assert(is_armv8_3_pauth_apa_api_present());
 
-	uint64_t *apiakey = plat_init_apiakey();
-
-	write_apiakeylo_el1(apiakey[0]);
-	write_apiakeyhi_el1(apiakey[1]);
-
-	if (IS_IN_EL2()) {
-		write_sctlr_el2(read_sctlr_el2() | SCTLR_EnIA_BIT);
-	} else {
-		assert(IS_IN_EL1());
-		write_sctlr_el1(read_sctlr_el1() | SCTLR_EnIA_BIT);
-	}
-
-	isb();
+	/*
+	 * Program APIAKey_EL1 key and enable ARMv8.3-PAuth here as this
+	 * function doesn't return, and RETAA instuction won't be executed,
+	 * what would cause translation fault otherwise.
+	 */
+	pauth_init_enable();
 #endif /* ENABLE_PAUTH */
 
 	tftf_platform_setup();