From: Zheng Chuan <zhengchuan@huawei.com> hulk inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8918 ------------------------------------------ Background: ESB (Error Synchronization Barrier) is used to synchronize SEI (SError Interrupt) at exception boundaries in firmware-first RAS model. However, ESB has performance impact and may not be needed on all platforms. Design: Add a boot parameter 'arm64_sync_sei' to dynamically control ESB insertion: - Default is disabled (arm64_sync_sei = false) to minimize impact - When enabled via 'arm64_sync_sei', ESB is inserted at: - Exception entry from EL0 - Exception return to EL0 (before ERET) - Uses alternative patching: fills NOP when disabled, keeps ESB when enabled - Checks for ARM64_HAS_RAS_EXTN capability before enabling Signed-off-by: Zheng Chuan <zhengchuan@huawei.com> Signed-off-by: Wupeng Ma <mawupeng1@huawei.com> --- .../admin-guide/kernel-parameters.txt | 8 ++++ arch/arm64/include/asm/setup.h | 9 ++++ arch/arm64/kernel/Makefile | 1 + arch/arm64/kernel/arm64_sync_sei.c | 45 +++++++++++++++++++ arch/arm64/kernel/entry.S | 9 ++++ 5 files changed, 72 insertions(+) create mode 100644 arch/arm64/kernel/arm64_sync_sei.c diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index a437aafa2946..cb4c720de67c 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -435,6 +435,14 @@ arm64.nosve [ARM64] Unconditionally disable Scalable Vector Extension support + arm64_sync_sei [ARM64] Enable ESB (Error Synchronization Barrier) to + synchronize SEI (SError Interrupt) at exception boundaries + in firmware-first RAS model. This option has performance + impact and is disabled by default. When enabled via + arm64_sync_sei, ESB is inserted at exception entry from + EL0 and exception return to EL0 (before ERET). Requires + ARM64_HAS_RAS_EXTN capability. + ataflop= [HW,M68k] atarimouse= [HW,MOUSE] Atari Mouse diff --git a/arch/arm64/include/asm/setup.h b/arch/arm64/include/asm/setup.h index 2e4d7da74fb8..a9039c35c813 100644 --- a/arch/arm64/include/asm/setup.h +++ b/arch/arm64/include/asm/setup.h @@ -44,4 +44,13 @@ static inline bool arch_parse_debug_rodata(char *arg) } #define arch_parse_debug_rodata arch_parse_debug_rodata +#ifdef CONFIG_ARM64_SYNC_SEI +bool arm64_sync_sei_enabled(void); +#else +static inline bool arm64_sync_sei_enabled(void) +{ + return false; +} +#endif + #endif diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 300bfcb8a890..5fed5f7d6868 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -81,6 +81,7 @@ obj-$(CONFIG_COMPAT_VDSO) += vdso32-wrap.o obj-$(CONFIG_ARM64_ILP32) += vdso-ilp32/ obj-$(CONFIG_FAST_SYSCALL) += xcall/ obj-$(CONFIG_UNWIND_PATCH_PAC_INTO_SCS) += patch-scs.o +obj-$(CONFIG_ARM64_SYNC_SEI) += arm64_sync_sei.o obj-$(CONFIG_IPI_AS_NMI) += ipi_nmi.o obj-$(CONFIG_HISI_VIRTCCA_GUEST) += virtcca_cvm_guest.o virtcca_cvm_tsi.o obj-$(CONFIG_HISI_VIRTCCA_HOST) += virtcca_cvm_host.o diff --git a/arch/arm64/kernel/arm64_sync_sei.c b/arch/arm64/kernel/arm64_sync_sei.c new file mode 100644 index 000000000000..d5592e53383d --- /dev/null +++ b/arch/arm64/kernel/arm64_sync_sei.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/kstrtox.h> +#include <asm/alternative.h> +#include <asm/cpufeature.h> +#include <asm/insn.h> +#include <asm/cache.h> + +static bool arm64_sync_sei __read_mostly; + +static int __init arm64_sync_sei_setup(char *str) +{ + arm64_sync_sei = true; + + pr_info("Enable RAS Extension Support with ESB to synchronize SEI\n"); + return 0; +} +early_param("arm64_sync_sei", arm64_sync_sei_setup); + +/* + * alternative_cb callback: Patch ESB instruction to synchronize SEI + * Called during boot to patch entry.S code + */ +void noinstr arm64_sync_sei_cb(struct alt_instr *alt, __le32 *origptr, + __le32 *updptr, int nr_inst) +{ + int i; + + if (arm64_sync_sei && cpus_have_cap(ARM64_HAS_RAS_EXTN)) + return; + + /* mark as invalid since ras extension is not supported */ + arm64_sync_sei = false; + + /* Keep as NOP */ + for (i = 0; i < nr_inst; i++) + updptr[i] = cpu_to_le32(aarch64_insn_gen_nop()); +} + +bool arm64_sync_sei_enabled(void) +{ + return arm64_sync_sei; +} diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index f9f358f41682..7e699f9f5b86 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -29,13 +29,21 @@ #include <asm/asm-uaccess.h> #include <asm/unistd.h> +#ifdef CONFIG_ARM64_SYNC_SEI +/* External symbols from ras_sync_serror.c */ +.extern arm64_sync_sei_cb +#endif + .macro sync_sei #ifdef CONFIG_ARM64_SYNC_SEI /* Use ESB to synchronize SEI at the entry and exit of exception */ +alternative_cb ARM64_ALWAYS_SYSTEM, arm64_sync_sei_cb esb +alternative_cb_end .endm .macro sei_restore_sp_el0, tmp1:req, tmp2:req +alternative_cb ARM64_ALWAYS_SYSTEM, arm64_sync_sei_cb /* * It must restore SP_EL0 from per-cpu variable __entry_task, since TF * firmware clobbers the SP_EL0 before SEI is delegated back. @@ -47,6 +55,7 @@ ldr_this_cpu \tmp2, __entry_task, \tmp1 msr sp_el0, \tmp2 .Lskip_sp_el0_restore: +alternative_cb_end #endif /* CONFIG_ARM64_SYNC_SEI */ .endm -- 2.43.0