Commit 8daaa5f8261bffd2f6217a960f9182d0503a5c44

Authored by Mike Travis
Committed by Ingo Molnar
1 parent 8a1f4653f2

kdb: Add support for external NMI handler to call KGDB/KDB

This patch adds a kgdb_nmicallin() interface that can be used by
external NMI handlers to call the KGDB/KDB handler.  The primary
need for this is for those types of NMI interrupts where all the
CPUs have already received the NMI signal.  Therefore no
send_IPI(NMI) is required, and in fact it will cause a 2nd
unhandled NMI to occur. This generates the "Dazed and Confuzed"
messages.

Since all the CPUs are getting the NMI at roughly the same time,
it's not guaranteed that the first CPU that hits the NMI handler
will manage to enter KGDB and set the dbg_master_lock before the
slaves start entering. The new argument "send_ready" was added
for KGDB to signal the NMI handler to release the slave CPUs for
entry into KGDB.

Signed-off-by: Mike Travis <travis@sgi.com>
Acked-by: Jason Wessel <jason.wessel@windriver.com>
Reviewed-by: Dimitri Sivanich <sivanich@sgi.com>
Reviewed-by: Hedi Berriche <hedi@sgi.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
Link: http://lkml.kernel.org/r/20131002151417.928886849@asylum.americas.sgi.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>

Showing 6 changed files with 42 additions and 3 deletions Side-by-side Diff

... ... @@ -109,6 +109,7 @@
109 109 KDB_REASON_RECURSE, /* Recursive entry to kdb;
110 110 * regs probably valid */
111 111 KDB_REASON_SSTEP, /* Single Step trap. - regs valid */
  112 + KDB_REASON_SYSTEM_NMI, /* In NMI due to SYSTEM cmd; regs valid */
112 113 } kdb_reason_t;
113 114  
114 115 extern int kdb_trap_printk;
include/linux/kgdb.h
... ... @@ -310,6 +310,7 @@
310 310 kgdb_handle_exception(int ex_vector, int signo, int err_code,
311 311 struct pt_regs *regs);
312 312 extern int kgdb_nmicallback(int cpu, void *regs);
  313 +extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *snd_rdy);
313 314 extern void gdbstub_exit(int status);
314 315  
315 316 extern int kgdb_single_step;
kernel/debug/debug_core.c
... ... @@ -575,8 +575,12 @@
575 575 raw_spin_lock(&dbg_slave_lock);
576 576  
577 577 #ifdef CONFIG_SMP
  578 + /* If send_ready set, slaves are already waiting */
  579 + if (ks->send_ready)
  580 + atomic_set(ks->send_ready, 1);
  581 +
578 582 /* Signal the other CPUs to enter kgdb_wait() */
579   - if ((!kgdb_single_step) && kgdb_do_roundup)
  583 + else if ((!kgdb_single_step) && kgdb_do_roundup)
580 584 kgdb_roundup_cpus(flags);
581 585 #endif
582 586  
583 587  
... ... @@ -678,11 +682,11 @@
678 682 if (arch_kgdb_ops.enable_nmi)
679 683 arch_kgdb_ops.enable_nmi(0);
680 684  
  685 + memset(ks, 0, sizeof(struct kgdb_state));
681 686 ks->cpu = raw_smp_processor_id();
682 687 ks->ex_vector = evector;
683 688 ks->signo = signo;
684 689 ks->err_code = ecode;
685   - ks->kgdb_usethreadid = 0;
686 690 ks->linux_regs = regs;
687 691  
688 692 if (kgdb_reenter_check(ks))
... ... @@ -726,6 +730,30 @@
726 730 if (kgdb_info[ks->cpu].enter_kgdb == 0 &&
727 731 raw_spin_is_locked(&dbg_master_lock)) {
728 732 kgdb_cpu_enter(ks, regs, DCPU_IS_SLAVE);
  733 + return 0;
  734 + }
  735 +#endif
  736 + return 1;
  737 +}
  738 +
  739 +int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *send_ready)
  740 +{
  741 +#ifdef CONFIG_SMP
  742 + if (!kgdb_io_ready(0) || !send_ready)
  743 + return 1;
  744 +
  745 + if (kgdb_info[cpu].enter_kgdb == 0) {
  746 + struct kgdb_state kgdb_var;
  747 + struct kgdb_state *ks = &kgdb_var;
  748 +
  749 + memset(ks, 0, sizeof(struct kgdb_state));
  750 + ks->cpu = cpu;
  751 + ks->ex_vector = trapnr;
  752 + ks->signo = SIGTRAP;
  753 + ks->err_code = KGDB_KDB_REASON_SYSTEM_NMI;
  754 + ks->linux_regs = regs;
  755 + ks->send_ready = send_ready;
  756 + kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
729 757 return 0;
730 758 }
731 759 #endif
kernel/debug/debug_core.h
... ... @@ -26,6 +26,7 @@
26 26 unsigned long threadid;
27 27 long kgdb_usethreadid;
28 28 struct pt_regs *linux_regs;
  29 + atomic_t *send_ready;
29 30 };
30 31  
31 32 /* Exception state values */
32 33  
... ... @@ -74,11 +75,13 @@
74 75 extern int kdb_parse(const char *cmdstr);
75 76 extern int kdb_common_init_state(struct kgdb_state *ks);
76 77 extern int kdb_common_deinit_state(void);
  78 +#define KGDB_KDB_REASON_SYSTEM_NMI KDB_REASON_SYSTEM_NMI
77 79 #else /* ! CONFIG_KGDB_KDB */
78 80 static inline int kdb_stub(struct kgdb_state *ks)
79 81 {
80 82 return DBG_PASS_EVENT;
81 83 }
  84 +#define KGDB_KDB_REASON_SYSTEM_NMI 0
82 85 #endif /* CONFIG_KGDB_KDB */
83 86  
84 87 #endif /* _DEBUG_CORE_H_ */
kernel/debug/kdb/kdb_debugger.c
... ... @@ -69,7 +69,10 @@
69 69 if (atomic_read(&kgdb_setting_breakpoint))
70 70 reason = KDB_REASON_KEYBOARD;
71 71  
72   - if (in_nmi())
  72 + if (ks->err_code == KDB_REASON_SYSTEM_NMI && ks->signo == SIGTRAP)
  73 + reason = KDB_REASON_SYSTEM_NMI;
  74 +
  75 + else if (in_nmi())
73 76 reason = KDB_REASON_NMI;
74 77  
75 78 for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {
kernel/debug/kdb/kdb_main.c
... ... @@ -1200,6 +1200,9 @@
1200 1200 instruction_pointer(regs));
1201 1201 kdb_dumpregs(regs);
1202 1202 break;
  1203 + case KDB_REASON_SYSTEM_NMI:
  1204 + kdb_printf("due to System NonMaskable Interrupt\n");
  1205 + break;
1203 1206 case KDB_REASON_NMI:
1204 1207 kdb_printf("due to NonMaskable Interrupt @ "
1205 1208 kdb_machreg_fmt "\n",