summaryrefslogtreecommitdiff
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2020-02-25 23:33:29 +0100
committerThomas Gleixner <tglx@linutronix.de>2020-06-11 15:15:00 +0200
commit4c0dcd8350a03cb65f645a039f2772be880ee74a (patch)
treec4d232c3383abba5950c28850b905980ab6bdc28 /arch/x86/kernel/traps.c
parentf08e32ec3cfcf9e6d3640007de590c225ab2e201 (diff)
x86/entry: Implement user mode C entry points for #DB and #MCE
The MCE entry point uses the same mechanism as the IST entry point for now. For #DB split the inner workings and just keep the nmi_enter/exit() magic in the IST variant. Fixup the ASM code to emit the proper noist_##cfunc call. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Acked-by: Andy Lutomirski <luto@kernel.org> Link: https://lkml.kernel.org/r/20200505135315.177564104@linutronix.de
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c70
1 files changed, 54 insertions, 16 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 569408a681b6..4f248c5d5cab 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -775,20 +775,12 @@ static __always_inline void debug_exit(unsigned long dr7)
*
* May run on IST stack.
*/
-DEFINE_IDTENTRY_DEBUG(exc_debug)
+static noinstr void handle_debug(struct pt_regs *regs, unsigned long dr6)
{
struct task_struct *tsk = current;
- unsigned long dr6, dr7;
int user_icebp = 0;
int si_code;
- debug_enter(&dr6, &dr7);
-
- if (user_mode(regs))
- idtentry_enter(regs);
- else
- nmi_enter();
-
/*
* The SDM says "The processor clears the BTF flag when it
* generates a debug exception." Clear TIF_BLOCKSTEP to keep
@@ -800,7 +792,7 @@ DEFINE_IDTENTRY_DEBUG(exc_debug)
is_sysenter_singlestep(regs))) {
dr6 &= ~DR_STEP;
if (!dr6)
- goto exit;
+ return;
/*
* else we might have gotten a single-step trap and hit a
* watchpoint at the same time, in which case we should fall
@@ -821,12 +813,12 @@ DEFINE_IDTENTRY_DEBUG(exc_debug)
#ifdef CONFIG_KPROBES
if (kprobe_debug_handler(regs))
- goto exit;
+ return;
#endif
if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, 0,
SIGTRAP) == NOTIFY_STOP)
- goto exit;
+ return;
/*
* Let others (NMI) know that the debug stack is in use
@@ -842,7 +834,7 @@ DEFINE_IDTENTRY_DEBUG(exc_debug)
X86_TRAP_DB);
cond_local_irq_disable(regs);
debug_stack_usage_dec();
- goto exit;
+ return;
}
if (WARN_ON_ONCE((dr6 & DR_STEP) && !user_mode(regs))) {
@@ -861,14 +853,60 @@ DEFINE_IDTENTRY_DEBUG(exc_debug)
send_sigtrap(regs, 0, si_code);
cond_local_irq_disable(regs);
debug_stack_usage_dec();
+}
+
+static __always_inline void exc_debug_kernel(struct pt_regs *regs,
+ unsigned long dr6)
+{
+ nmi_enter();
+ handle_debug(regs, dr6);
+ nmi_exit();
+}
+
+static __always_inline void exc_debug_user(struct pt_regs *regs,
+ unsigned long dr6)
+{
+ idtentry_enter(regs);
+ handle_debug(regs, dr6);
+ idtentry_exit(regs);
+}
+
+#ifdef CONFIG_X86_64
+/* IST stack entry */
+DEFINE_IDTENTRY_DEBUG(exc_debug)
+{
+ unsigned long dr6, dr7;
+
+ debug_enter(&dr6, &dr7);
+ exc_debug_kernel(regs, dr6);
+ debug_exit(dr7);
+}
+
+/* User entry, runs on regular task stack */
+DEFINE_IDTENTRY_DEBUG_USER(exc_debug)
+{
+ unsigned long dr6, dr7;
+
+ debug_enter(&dr6, &dr7);
+ exc_debug_user(regs, dr6);
+ debug_exit(dr7);
+}
+#else
+/* 32 bit does not have separate entry points. */
+DEFINE_IDTENTRY_DEBUG(exc_debug)
+{
+ unsigned long dr6, dr7;
+
+ debug_enter(&dr6, &dr7);
-exit:
if (user_mode(regs))
- idtentry_exit(regs);
+ exc_debug_user(regs, dr6);
else
- nmi_exit();
+ exc_debug_kernel(regs, dr6);
+
debug_exit(dr7);
}
+#endif
/*
* Note that we play around with the 'TS' bit in an attempt to get