xref: /kernel/linux/linux-6.6/arch/arm64/include/asm/scs.h (revision 62306a36)
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _ASM_SCS_H
3#define _ASM_SCS_H
4
5#ifdef __ASSEMBLY__
6
7#include <asm/asm-offsets.h>
8#include <asm/sysreg.h>
9
10#ifdef CONFIG_SHADOW_CALL_STACK
11	scs_sp	.req	x18
12
13	.macro scs_load_current
14	get_current_task scs_sp
15	ldr	scs_sp, [scs_sp, #TSK_TI_SCS_SP]
16	.endm
17
18	.macro scs_save tsk
19	str	scs_sp, [\tsk, #TSK_TI_SCS_SP]
20	.endm
21#else
22	.macro scs_load_current
23	.endm
24
25	.macro scs_save tsk
26	.endm
27#endif /* CONFIG_SHADOW_CALL_STACK */
28
29
30#else
31
32#include <linux/scs.h>
33#include <asm/cpufeature.h>
34
35#ifdef CONFIG_UNWIND_PATCH_PAC_INTO_SCS
36static inline bool should_patch_pac_into_scs(void)
37{
38	u64 reg;
39
40	/*
41	 * We only enable the shadow call stack dynamically if we are running
42	 * on a system that does not implement PAC or BTI. PAC and SCS provide
43	 * roughly the same level of protection, and BTI relies on the PACIASP
44	 * instructions serving as landing pads, preventing us from patching
45	 * those instructions into something else.
46	 */
47	reg = read_sysreg_s(SYS_ID_AA64ISAR1_EL1);
48	if (SYS_FIELD_GET(ID_AA64ISAR1_EL1, APA, reg) |
49	    SYS_FIELD_GET(ID_AA64ISAR1_EL1, API, reg))
50		return false;
51
52	reg = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
53	if (SYS_FIELD_GET(ID_AA64ISAR2_EL1, APA3, reg))
54		return false;
55
56	if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) {
57		reg = read_sysreg_s(SYS_ID_AA64PFR1_EL1);
58		if (reg & (0xf << ID_AA64PFR1_EL1_BT_SHIFT))
59			return false;
60	}
61	return true;
62}
63
64static inline void dynamic_scs_init(void)
65{
66	if (should_patch_pac_into_scs()) {
67		pr_info("Enabling dynamic shadow call stack\n");
68		static_branch_enable(&dynamic_scs_enabled);
69	}
70}
71#else
72static inline void dynamic_scs_init(void) {}
73#endif
74
75int scs_patch(const u8 eh_frame[], int size);
76asmlinkage void scs_patch_vmlinux(void);
77
78#endif /* __ASSEMBLY __ */
79
80#endif /* _ASM_SCS_H */
81