Skip to content

Commit adb334d

Browse files
author
Ingo Molnar
committed
Merge branch 'WIP.x86/entry' into x86/entry, to merge the latest generic code and resolve conflicts
Pick up and resolve the NMI entry code changes from the locking tree, and also pick up the latest two fixes from tip:core/entry. Signed-off-by: Ingo Molnar <mingo@kernel.org>
2 parents f3020b8 + f87032a commit adb334d

File tree

14 files changed

+319
-216
lines changed

14 files changed

+319
-216
lines changed

arch/x86/entry/common.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,40 @@ SYSCALL_DEFINE0(ni_syscall)
198198
return -ENOSYS;
199199
}
200200

201+
noinstr bool idtentry_enter_nmi(struct pt_regs *regs)
202+
{
203+
bool irq_state = lockdep_hardirqs_enabled();
204+
205+
__nmi_enter();
206+
lockdep_hardirqs_off(CALLER_ADDR0);
207+
lockdep_hardirq_enter();
208+
rcu_nmi_enter();
209+
210+
instrumentation_begin();
211+
trace_hardirqs_off_finish();
212+
ftrace_nmi_enter();
213+
instrumentation_end();
214+
215+
return irq_state;
216+
}
217+
218+
noinstr void idtentry_exit_nmi(struct pt_regs *regs, bool restore)
219+
{
220+
instrumentation_begin();
221+
ftrace_nmi_exit();
222+
if (restore) {
223+
trace_hardirqs_on_prepare();
224+
lockdep_hardirqs_on_prepare(CALLER_ADDR0);
225+
}
226+
instrumentation_end();
227+
228+
rcu_nmi_exit();
229+
lockdep_hardirq_exit();
230+
if (restore)
231+
lockdep_hardirqs_on(CALLER_ADDR0);
232+
__nmi_exit();
233+
}
234+
201235
#ifdef CONFIG_XEN_PV
202236
#ifndef CONFIG_PREEMPTION
203237
/*

arch/x86/include/asm/idtentry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
#include <asm/irq_stack.h>
1313

14+
bool idtentry_enter_nmi(struct pt_regs *regs);
15+
void idtentry_exit_nmi(struct pt_regs *regs, bool irq_state);
16+
1417
/**
1518
* DECLARE_IDTENTRY - Declare functions for simple IDT entry points
1619
* No error code pushed by hardware

arch/x86/kernel/nmi.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,6 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
330330
__this_cpu_write(last_nmi_rip, regs->ip);
331331

332332
instrumentation_begin();
333-
trace_hardirqs_off_finish();
334333

335334
handled = nmi_handle(NMI_LOCAL, regs);
336335
__this_cpu_add(nmi_stats.normal, handled);
@@ -417,8 +416,6 @@ static noinstr void default_do_nmi(struct pt_regs *regs)
417416
unknown_nmi_error(reason, regs);
418417

419418
out:
420-
if (regs->flags & X86_EFLAGS_IF)
421-
trace_hardirqs_on_prepare();
422419
instrumentation_end();
423420
}
424421

@@ -478,6 +475,8 @@ static DEFINE_PER_CPU(unsigned long, nmi_dr7);
478475

479476
DEFINE_IDTENTRY_RAW(exc_nmi)
480477
{
478+
bool irq_state;
479+
481480
if (IS_ENABLED(CONFIG_SMP) && arch_cpu_is_offline(smp_processor_id()))
482481
return;
483482

@@ -491,14 +490,14 @@ DEFINE_IDTENTRY_RAW(exc_nmi)
491490

492491
this_cpu_write(nmi_dr7, local_db_save());
493492

494-
nmi_enter();
493+
irq_state = idtentry_enter_nmi(regs);
495494

496495
inc_irq_stat(__nmi_count);
497496

498497
if (!ignore_nmis)
499498
default_do_nmi(regs);
500499

501-
nmi_exit();
500+
idtentry_exit_nmi(regs, irq_state);
502501

503502
local_db_restore(this_cpu_read(nmi_dr7));
504503

arch/x86/kernel/traps.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ DEFINE_IDTENTRY_DF(exc_double_fault)
405405
}
406406
#endif
407407

408-
nmi_enter();
408+
idtentry_enter_nmi(regs);
409409
instrumentation_begin();
410410
notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
411411

@@ -651,15 +651,12 @@ DEFINE_IDTENTRY_RAW(exc_int3)
651651
instrumentation_end();
652652
irqentry_exit_to_user_mode(regs);
653653
} else {
654-
nmi_enter();
654+
bool irq_state = idtentry_enter_nmi(regs);
655655
instrumentation_begin();
656-
trace_hardirqs_off_finish();
657656
if (!do_int3(regs))
658657
die("int3", regs, 0);
659-
if (regs->flags & X86_EFLAGS_IF)
660-
trace_hardirqs_on_prepare();
661658
instrumentation_end();
662-
nmi_exit();
659+
idtentry_exit_nmi(regs, irq_state);
663660
}
664661
}
665662

@@ -867,9 +864,8 @@ static void handle_debug(struct pt_regs *regs, unsigned long dr6, bool user)
867864
static __always_inline void exc_debug_kernel(struct pt_regs *regs,
868865
unsigned long dr6)
869866
{
870-
nmi_enter();
867+
bool irq_state = idtentry_enter_nmi(regs);
871868
instrumentation_begin();
872-
trace_hardirqs_off_finish();
873869

874870
/*
875871
* If something gets miswired and we end up here for a user mode
@@ -886,10 +882,8 @@ static __always_inline void exc_debug_kernel(struct pt_regs *regs,
886882

887883
handle_debug(regs, dr6, false);
888884

889-
if (regs->flags & X86_EFLAGS_IF)
890-
trace_hardirqs_on_prepare();
891885
instrumentation_end();
892-
nmi_exit();
886+
idtentry_exit_nmi(regs, irq_state);
893887
}
894888

895889
static __always_inline void exc_debug_user(struct pt_regs *regs,
@@ -905,6 +899,7 @@ static __always_inline void exc_debug_user(struct pt_regs *regs,
905899
instrumentation_begin();
906900

907901
handle_debug(regs, dr6, true);
902+
908903
instrumentation_end();
909904
irqentry_exit_to_user_mode(regs);
910905
}

include/linux/hardirq.h

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,32 +111,42 @@ extern void rcu_nmi_exit(void);
111111
/*
112112
* nmi_enter() can nest up to 15 times; see NMI_BITS.
113113
*/
114-
#define nmi_enter() \
114+
#define __nmi_enter() \
115115
do { \
116+
lockdep_off(); \
116117
arch_nmi_enter(); \
117118
printk_nmi_enter(); \
118-
lockdep_off(); \
119119
BUG_ON(in_nmi() == NMI_MASK); \
120120
__preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \
121-
rcu_nmi_enter(); \
121+
} while (0)
122+
123+
#define nmi_enter() \
124+
do { \
125+
__nmi_enter(); \
122126
lockdep_hardirq_enter(); \
127+
rcu_nmi_enter(); \
123128
instrumentation_begin(); \
124129
ftrace_nmi_enter(); \
125130
instrumentation_end(); \
126131
} while (0)
127132

133+
#define __nmi_exit() \
134+
do { \
135+
BUG_ON(!in_nmi()); \
136+
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
137+
printk_nmi_exit(); \
138+
arch_nmi_exit(); \
139+
lockdep_on(); \
140+
} while (0)
141+
128142
#define nmi_exit() \
129143
do { \
130144
instrumentation_begin(); \
131145
ftrace_nmi_exit(); \
132146
instrumentation_end(); \
133-
lockdep_hardirq_exit(); \
134147
rcu_nmi_exit(); \
135-
BUG_ON(!in_nmi()); \
136-
__preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
137-
lockdep_on(); \
138-
printk_nmi_exit(); \
139-
arch_nmi_exit(); \
148+
lockdep_hardirq_exit(); \
149+
__nmi_exit(); \
140150
} while (0)
141151

142152
#endif /* LINUX_HARDIRQ_H */

0 commit comments

Comments
 (0)