The following commit has been merged into the x86/fred branch of tip: Commit-ID: 5dd56c94ca2f8834e7689cac0045d312ef3ac9c6 Gitweb: https://git.kernel.org/tip/5dd56c94ca2f8834e7689cac0045d312ef3ac9c6 Author: Xin Li <xin3.li@xxxxxxxxx> AuthorDate: Tue, 05 Dec 2023 02:50:14 -08:00 Committer: Borislav Petkov (AMD) <bp@xxxxxxxxx> CommitterDate: Tue, 30 Jan 2024 18:20:35 +01:00 x86/fred: Add a machine check entry stub for FRED Like #DB, when occurred on different ring level, i.e., from user or kernel context, #MCE needs to be handled on different stack: User #MCE on current task stack, while kernel #MCE on a dedicated stack. This is exactly how FRED event delivery invokes an exception handler: ring 3 event on level 0 stack, i.e., current task stack; ring 0 event on the #MCE dedicated stack specified in the IA32_FRED_STKLVLS MSR. So unlike IDT, the FRED machine check entry stub doesn't do stack switch. Signed-off-by: Xin Li <xin3.li@xxxxxxxxx> Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx> Tested-by: Shan Kang <shan.kang@xxxxxxxxx> Link: https://lore.kernel.org/r/20231205105030.8698-26-xin3.li@xxxxxxxxx --- arch/x86/kernel/cpu/mce/core.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index bc39252..04acdc3 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -46,6 +46,7 @@ #include <linux/hardirq.h> #include <linux/kexec.h> +#include <asm/fred.h> #include <asm/intel-family.h> #include <asm/processor.h> #include <asm/traps.h> @@ -2166,6 +2167,31 @@ DEFINE_IDTENTRY_MCE_USER(exc_machine_check) exc_machine_check_user(regs); local_db_restore(dr7); } + +#ifdef CONFIG_X86_FRED +/* + * When occurred on different ring level, i.e., from user or kernel + * context, #MCE needs to be handled on different stack: User #MCE + * on current task stack, while kernel #MCE on a dedicated stack. + * + * This is exactly how FRED event delivery invokes an exception + * handler: ring 3 event on level 0 stack, i.e., current task stack; + * ring 0 event on the #MCE dedicated stack specified in the + * IA32_FRED_STKLVLS MSR. So unlike IDT, the FRED machine check entry + * stub doesn't do stack switch. + */ +DEFINE_FREDENTRY_MCE(exc_machine_check) +{ + unsigned long dr7; + + dr7 = local_db_save(); + if (user_mode(regs)) + exc_machine_check_user(regs); + else + exc_machine_check_kernel(regs); + local_db_restore(dr7); +} +#endif #else /* 32bit unified entry point */ DEFINE_IDTENTRY_RAW(exc_machine_check)