feat(cpufeat): enable FEAT_PAuth to FEAT_STATE_CHECKED
FEAT_PAuth is the second to last feature to be a boolean choice - it's
either unconditionally compiled in and must be present in hardware or
it's not compiled in. FEAT_PAuth is architected to be backwards
compatible - a subset of the branch guarding instructions (pacia/autia)
execute as NOPs when PAuth is not present. That subset is used with
`-mbranch-protection=standard` and -march pre-8.3. This patch adds the
necessary logic to also check accesses of the non-backward compatible
registers and allow a fully checked implementation.
Note that a checked support requires -march to be pre 8.3, as otherwise
the compiler will include branch protection instructions that are not
NOPs without PAuth (eg retaa) which cannot be checked.
Change-Id: Id942c20cae9d15d25b3d72b8161333642574ddaa
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/Makefile b/Makefile
index aae3452..fd55f03 100644
--- a/Makefile
+++ b/Makefile
@@ -492,6 +492,12 @@
include ${PLAT_MAKEFILE_FULL}
################################################################################
+# Setup arch_features based on ARM_ARCH_MAJOR, ARM_ARCH_MINOR provided from
+# platform.
+################################################################################
+
+include ${MAKE_HELPERS_DIRECTORY}arch_features.mk
+################################################################################
# Process BRANCH_PROTECTION value and set
# Pointer Authentication and Branch Target Identification flags
################################################################################
@@ -517,30 +523,29 @@
# Turn on branch target identification mechanism
BP_OPTION := bti
ENABLE_BTI := 1
+else ifeq (${BRANCH_PROTECTION},5)
+ # Turn on branch target identification mechanism
+ BP_OPTION := standard
+ ENABLE_BTI := 2
+ ENABLE_PAUTH := 2
else
$(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION})
endif #(BRANCH_PROTECTION)
-ifeq ($(ENABLE_PAUTH),1)
- CTX_INCLUDE_PAUTH_REGS := 1
+ifneq ($(ENABLE_PAUTH),0)
+ CTX_INCLUDE_PAUTH_REGS := ${ENABLE_PAUTH}
endif
ifneq (${BP_OPTION},none)
TF_CFLAGS_aarch64 += -mbranch-protection=${BP_OPTION}
endif #(BP_OPTION)
# Pointer Authentication sources
-ifeq (${ENABLE_PAUTH}, 1)
+ifneq (${ENABLE_PAUTH},0)
# arm/common/aarch64/arm_pauth.c contains a sample platform hook to complete the
# Pauth support. As it's not secure, it must be reimplemented for real platforms
- BL_COMMON_SOURCES += lib/extensions/pauth/pauth_helpers.S
+ BL_COMMON_SOURCES += lib/extensions/pauth/pauth.c
endif
-################################################################################
-# Setup arch_features based on ARM_ARCH_MAJOR, ARM_ARCH_MINOR provided from
-# platform.
-################################################################################
-include ${MAKE_HELPERS_DIRECTORY}arch_features.mk
-
####################################################
# Enable required options for Memory Stack Tagging.
####################################################
@@ -917,13 +922,13 @@
# If pointer authentication is used in the firmware, make sure that all the
# registers associated to it are also saved and restored.
# Not doing it would leak the value of the keys used by EL3 to EL1 and S-EL1.
-ifeq ($(ENABLE_PAUTH),1)
+ifneq ($(ENABLE_PAUTH),0)
ifeq ($(CTX_INCLUDE_PAUTH_REGS),0)
- $(error Pointer Authentication requires CTX_INCLUDE_PAUTH_REGS=1)
+ $(error Pointer Authentication requires CTX_INCLUDE_PAUTH_REGS to be enabled)
endif
endif #(ENABLE_PAUTH)
-ifeq ($(CTX_INCLUDE_PAUTH_REGS),1)
+ifneq ($(CTX_INCLUDE_PAUTH_REGS),0)
ifneq (${ARCH},aarch64)
$(error CTX_INCLUDE_PAUTH_REGS requires AArch64)
endif
diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c
index 4ff73d7..dbe9453 100644
--- a/bl2/bl2_main.c
+++ b/bl2/bl2_main.c
@@ -120,12 +120,12 @@
disable_mmu_icache_secure();
#endif /* !__aarch64__ */
-#if ENABLE_PAUTH
/*
* Disable pointer authentication before running next boot image
*/
- pauth_disable_el1();
-#endif /* ENABLE_PAUTH */
+ if (is_feat_pauth_supported()) {
+ pauth_disable_el1();
+ }
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_CAPTURE_TIMESTAMP(bl_svc, BL2_EXIT, PMF_CACHE_MAINT);
@@ -148,12 +148,12 @@
#endif
console_flush();
-#if ENABLE_PAUTH
/*
* Disable pointer authentication before running next boot image
*/
- pauth_disable_el3();
-#endif /* ENABLE_PAUTH */
+ if (is_feat_pauth_supported()) {
+ pauth_disable_el3();
+ }
bl2_run_next_image(next_bl_ep_info);
#endif /* BL2_RUNS_AT_EL3 */
diff --git a/bl31/aarch64/crash_reporting.S b/bl31/aarch64/crash_reporting.S
index b5bf575..7b61692 100644
--- a/bl31/aarch64/crash_reporting.S
+++ b/bl31/aarch64/crash_reporting.S
@@ -397,8 +397,26 @@
ldr x4, [x0, #REGSZ * 7]
#if ENABLE_PAUTH
+#if ENABLE_PAUTH == 2
+ /* Skip if not present in hardware */
+ is_feat_pauth_present_asm x0, x1
+ beq 1f
+#endif
+ /*
+ * The assembler must see support for xpaci. So turn the compiler
+ * extension on. GCC prior to 10 doesn't understand the PAuth extension
+ * but it does understand armv8.3-a in general. Avoid using 8.3 if
+ * the compiler understands "pauth" so we don't downgrade a higher
+ * -march that was specified on the commandline.
+ */
+#if __GNUC__ < 10
+ .arch armv8.3-a
+#else
+ .arch_extension pauth
+#endif
/* Demangle address */
xpaci x4
+1:
#endif
bl asm_print_hex
bl asm_print_newline
diff --git a/common/backtrace/backtrace.c b/common/backtrace/backtrace.c
index f994ae5..479c4fd 100644
--- a/common/backtrace/backtrace.c
+++ b/common/backtrace/backtrace.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -8,6 +8,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <arch_features.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/console.h>
@@ -41,15 +42,14 @@
{
uintptr_t ret = address;
-#if ENABLE_PAUTH
/*
* When pointer authentication is enabled, the LR value saved on the
* stack contains a PAC. It must be stripped to retrieve the return
* address.
*/
-
- xpaci(ret);
-#endif
+ if (is_feat_pauth_supported()) {
+ ret = xpaci(address);
+ }
return ret;
}
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index b5814bb..2a42269 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -113,12 +113,16 @@
- ``BRANCH_PROTECTION``: Numeric value to enable ARMv8.3 Pointer Authentication
and ARMv8.5 Branch Target Identification support for TF-A BL images themselves.
If enabled, it is needed to use a compiler that supports the option
- ``-mbranch-protection``. Selects the branch protection features to use:
-- 0: Default value turns off all types of branch protection
+ ``-mbranch-protection``. The value of the ``-march`` (via ``ARM_ARCH_MINOR``
+ and ``ARM_ARCH_MAJOR``) option will control which instructions will be
+ emitted (HINT space or not). Selects the branch protection features to use:
+- 0: Default value turns off all types of branch protection (FEAT_STATE_DISABLED)
- 1: Enables all types of branch protection features
- 2: Return address signing to its standard level
- 3: Extend the signing to include leaf functions
- 4: Turn on branch target identification mechanism
+- 5: Enables all types of branch protection features, only if present in
+ hardware (FEAT_STATE_CHECK).
The table below summarizes ``BRANCH_PROTECTION`` values, GCC compilation options
and resulting PAuth/BTI features.
@@ -136,6 +140,8 @@
+-------+--------------+-------+-----+
| 4 | bti | N | Y |
+-------+--------------+-------+-----+
+ | 5 | dynamic | Y | Y |
+ +-------+--------------+-------+-----+
This option defaults to 0.
Note that Pointer Authentication is enabled for Non-secure world
@@ -198,11 +204,13 @@
- ``CTX_INCLUDE_PAUTH_REGS``: Numeric value to enable the Pointer
Authentication for Secure world. This will cause the ARMv8.3-PAuth registers
to be included when saving and restoring the CPU context as part of world
- switch. This flag can take values 0 to 2, to align with ``ENABLE_FEAT``
- mechanism. Default value is 0.
+ switch. Automatically enabled when ``BRANCH_PROTECTION`` is enabled. This flag
+ can take values 0 to 2, to align with ``ENABLE_FEAT`` mechanism. Default value
+ is 0.
Note that Pointer Authentication is enabled for Non-secure world irrespective
- of the value of this flag if the CPU supports it.
+ of the value of this flag if the CPU supports it. Alternatively, when
+ ``BRANCH_PROTECTION`` is enabled, this flag is superseded.
- ``CTX_INCLUDE_SVE_REGS``: Boolean option that, when set to 1, will cause the
SVE registers to be included when saving and restoring the CPU context. Note
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 569182a..9419583 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -238,7 +238,15 @@
/*******************************************************************************
* Strip Pointer Authentication Code
******************************************************************************/
-DEFINE_SYSOP_PARAM_FUNC(xpaci)
+static inline u_register_t xpaci(u_register_t arg)
+{
+ register u_register_t x0 asm("x0") = arg;
+
+ /* `xpaci x0` for compatibility with older compiler and/or older -march */
+ __asm__ (".arch armv8.3-a; xpaci %0\n" : "+r" (x0));
+
+ return x0;
+}
void flush_dcache_range(uintptr_t addr, size_t size);
void flush_dcache_to_popa_range(uintptr_t addr, size_t size);
diff --git a/include/arch/aarch64/asm_macros.S b/include/arch/aarch64/asm_macros.S
index dce07d9..da51bf8 100644
--- a/include/arch/aarch64/asm_macros.S
+++ b/include/arch/aarch64/asm_macros.S
@@ -329,7 +329,7 @@
.endm
/*
- * is_feat_sysreg128_present_asm - Set flags and reg if FEAT_SYSREG128
+ * is_feat_XYZ_present_asm - Set flags and reg if FEAT_XYZ
* is enabled at runtime.
*
* Arguments:
@@ -342,6 +342,15 @@
ands \reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT)
.endm
+ .macro is_feat_pauth_present_asm reg:req, clobber:req
+ mrs \reg, ID_AA64ISAR1_EL1
+ mov_imm \clobber, ((ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) \
+ | (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) \
+ | (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) \
+ | (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT))
+ tst \reg, \clobber
+ .endm
+
.macro call_reset_handler
#if !(defined(IMAGE_BL2) && ENABLE_RME)
/* ---------------------------------------------------------------------
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 7d003b6..7929901 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -379,6 +379,11 @@
mrs x9, pmcr_el0
str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0]
#if CTX_INCLUDE_PAUTH_REGS
+#if CTX_INCLUDE_PAUTH_REGS == 2
+ /* Skip if not present in hardware */
+ is_feat_pauth_present_asm x9, x10
+ beq no_pauth_\@
+#endif
/* ----------------------------------------------------------
* Save the ARMv8.3-PAuth keys as they are not banked
* by exception level
@@ -419,6 +424,7 @@
/* Program instruction key A */
msr APIAKeyLo_EL1, x10
msr APIAKeyHi_EL1, x11
+no_pauth_\@:
#endif /* ENABLE_PAUTH */
#endif /* CTX_INCLUDE_PAUTH_REGS */
.endm /* save_gp_pmcr_pauth_regs */
@@ -460,6 +466,11 @@
*/
func restore_gp_pmcr_pauth_regs
#if CTX_INCLUDE_PAUTH_REGS
+#if CTX_INCLUDE_PAUTH_REGS == 2
+ /* Skip if not present in hardware */
+ is_feat_pauth_present_asm x0, x1
+ beq no_pauth
+#endif
/* Restore the ARMv8.3 PAuth keys */
add x10, sp, #CTX_PAUTH_REGS_OFFSET
@@ -479,6 +490,7 @@
msr APDBKeyHi_EL1, x7
msr APGAKeyLo_EL1, x8
msr APGAKeyHi_EL1, x9
+no_pauth:
#endif /* CTX_INCLUDE_PAUTH_REGS */
/* PMUv3 is presumed to be always present */
diff --git a/lib/el3_runtime/aarch64/context_debug.c b/lib/el3_runtime/aarch64/context_debug.c
index b37bcb7..1ae7f6b 100644
--- a/lib/el3_runtime/aarch64/context_debug.c
+++ b/lib/el3_runtime/aarch64/context_debug.c
@@ -1,11 +1,12 @@
/*
- * Copyright (c) 2023-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
+#include <arch_features.h>
#include <common/debug.h>
#include <context.h>
#include <lib/el3_runtime/context_mgmt.h>
@@ -65,11 +66,11 @@
#else
size_t el1_total = 0U;
#endif /* CTX_INCLUDE_EL2_REGS */
-
-#if CTX_INCLUDE_PAUTH_REGS
size_t pauth_total = 0U;
- PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
-#endif
+
+ if (is_ctx_pauth_supported()) {
+ PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+ }
PRINT_MEM_USAGE_SEPARATOR();
@@ -80,9 +81,9 @@
printf("| EL1 ");
#endif /* CTX_INCLUDE_EL2_REGS */
-#if CTX_INCLUDE_PAUTH_REGS
- printf("| PAUTH ");
-#endif
+ if (is_ctx_pauth_supported()) {
+ printf("| PAUTH ");
+ }
printf("| Other | Total |\n");
@@ -96,11 +97,11 @@
#else
size_t el1_size = 0U;
#endif /* CTX_INCLUDE_EL2_REGS */
-
-#if CTX_INCLUDE_PAUTH_REGS
size_t pauth_size = 0U;
- PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
-#endif
+
+ if (is_ctx_pauth_supported()) {
+ PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+ }
PRINT_MEM_USAGE_SEPARATOR();
@@ -124,12 +125,12 @@
printf("| %8luB ", el1_size);
#endif /* CTX_INCLUDE_EL2_REGS */
-#if CTX_INCLUDE_PAUTH_REGS
- pauth_size = sizeof(ctx->pauth_ctx);
- size_other -= pauth_size;
- pauth_total += pauth_size;
- printf("| %8luB ", pauth_size);
-#endif
+ if (is_ctx_pauth_supported()) {
+ pauth_size = sizeof(ctx->pauth_ctx);
+ size_other -= pauth_size;
+ pauth_total += pauth_size;
+ printf("| %8luB ", pauth_size);
+ }
printf("| %8luB | %8luB |\n", size_other, core_total);
gp_total += gp_size;
@@ -138,15 +139,15 @@
total += core_total;
}
-#if CTX_INCLUDE_PAUTH_REGS
- PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
-#endif
+ if (is_ctx_pauth_supported()) {
+ PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+ }
PRINT_MEM_USAGE_SEPARATOR();
-#if CTX_INCLUDE_PAUTH_REGS
- PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
-#endif
+ if (is_ctx_pauth_supported()) {
+ PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+ }
PRINT_MEM_USAGE_SEPARATOR();
@@ -158,15 +159,15 @@
printf("| %8luB ", el1_total);
#endif /* CTX_INCLUDE_EL2_REGS */
-#if CTX_INCLUDE_PAUTH_REGS
- printf("| %8luB ", pauth_total);
-#endif
+ if (is_ctx_pauth_supported()) {
+ printf("| %8luB ", pauth_total);
+ }
printf("| %8luB | %8luB |\n", other_total, total);
-#if CTX_INCLUDE_PAUTH_REGS
- PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
-#endif
+ if (is_ctx_pauth_supported()) {
+ PRINT_SINGLE_MEM_USAGE_SEP_BLOCK();
+ }
PRINT_MEM_USAGE_SEPARATOR();
printf("\n");
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index 9659e73..d3c2a96 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -356,7 +356,7 @@
endif
# Pointer Authentication sources
-ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3))
+ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3 5))
PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c
endif
diff --git a/plat/qemu/common/common.mk b/plat/qemu/common/common.mk
index da981e5..751511c 100644
--- a/plat/qemu/common/common.mk
+++ b/plat/qemu/common/common.mk
@@ -148,7 +148,7 @@
endif
# Pointer Authentication sources
-ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3))
+ifeq ($(BRANCH_PROTECTION),$(filter $(BRANCH_PROTECTION),1 2 3 5))
PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c
endif