162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_SCS_H
362306a36Sopenharmony_ci#define _ASM_SCS_H
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#ifdef __ASSEMBLY__
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <asm/asm-offsets.h>
862306a36Sopenharmony_ci#include <asm/sysreg.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifdef CONFIG_SHADOW_CALL_STACK
1162306a36Sopenharmony_ci	scs_sp	.req	x18
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci	.macro scs_load_current
1462306a36Sopenharmony_ci	get_current_task scs_sp
1562306a36Sopenharmony_ci	ldr	scs_sp, [scs_sp, #TSK_TI_SCS_SP]
1662306a36Sopenharmony_ci	.endm
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	.macro scs_save tsk
1962306a36Sopenharmony_ci	str	scs_sp, [\tsk, #TSK_TI_SCS_SP]
2062306a36Sopenharmony_ci	.endm
2162306a36Sopenharmony_ci#else
2262306a36Sopenharmony_ci	.macro scs_load_current
2362306a36Sopenharmony_ci	.endm
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	.macro scs_save tsk
2662306a36Sopenharmony_ci	.endm
2762306a36Sopenharmony_ci#endif /* CONFIG_SHADOW_CALL_STACK */
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#else
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <linux/scs.h>
3362306a36Sopenharmony_ci#include <asm/cpufeature.h>
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#ifdef CONFIG_UNWIND_PATCH_PAC_INTO_SCS
3662306a36Sopenharmony_cistatic inline bool should_patch_pac_into_scs(void)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	u64 reg;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	/*
4162306a36Sopenharmony_ci	 * We only enable the shadow call stack dynamically if we are running
4262306a36Sopenharmony_ci	 * on a system that does not implement PAC or BTI. PAC and SCS provide
4362306a36Sopenharmony_ci	 * roughly the same level of protection, and BTI relies on the PACIASP
4462306a36Sopenharmony_ci	 * instructions serving as landing pads, preventing us from patching
4562306a36Sopenharmony_ci	 * those instructions into something else.
4662306a36Sopenharmony_ci	 */
4762306a36Sopenharmony_ci	reg = read_sysreg_s(SYS_ID_AA64ISAR1_EL1);
4862306a36Sopenharmony_ci	if (SYS_FIELD_GET(ID_AA64ISAR1_EL1, APA, reg) |
4962306a36Sopenharmony_ci	    SYS_FIELD_GET(ID_AA64ISAR1_EL1, API, reg))
5062306a36Sopenharmony_ci		return false;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	reg = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
5362306a36Sopenharmony_ci	if (SYS_FIELD_GET(ID_AA64ISAR2_EL1, APA3, reg))
5462306a36Sopenharmony_ci		return false;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_ARM64_BTI_KERNEL)) {
5762306a36Sopenharmony_ci		reg = read_sysreg_s(SYS_ID_AA64PFR1_EL1);
5862306a36Sopenharmony_ci		if (reg & (0xf << ID_AA64PFR1_EL1_BT_SHIFT))
5962306a36Sopenharmony_ci			return false;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci	return true;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline void dynamic_scs_init(void)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	if (should_patch_pac_into_scs()) {
6762306a36Sopenharmony_ci		pr_info("Enabling dynamic shadow call stack\n");
6862306a36Sopenharmony_ci		static_branch_enable(&dynamic_scs_enabled);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci#else
7262306a36Sopenharmony_cistatic inline void dynamic_scs_init(void) {}
7362306a36Sopenharmony_ci#endif
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ciint scs_patch(const u8 eh_frame[], int size);
7662306a36Sopenharmony_ciasmlinkage void scs_patch_vmlinux(void);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#endif /* __ASSEMBLY __ */
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#endif /* _ASM_SCS_H */
81