Skip to content

Commit 8daaa5f

Browse files
Mike Travisingomolnar
authored andcommitted
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>
1 parent 8a1f465 commit 8daaa5f

6 files changed

Lines changed: 42 additions & 3 deletions

File tree

include/linux/kdb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ typedef enum {
109109
KDB_REASON_RECURSE, /* Recursive entry to kdb;
110110
* regs probably valid */
111111
KDB_REASON_SSTEP, /* Single Step trap. - regs valid */
112+
KDB_REASON_SYSTEM_NMI, /* In NMI due to SYSTEM cmd; regs valid */
112113
} kdb_reason_t;
113114

114115
extern int kdb_trap_printk;

include/linux/kgdb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ extern int
310310
kgdb_handle_exception(int ex_vector, int signo, int err_code,
311311
struct pt_regs *regs);
312312
extern int kgdb_nmicallback(int cpu, void *regs);
313+
extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *snd_rdy);
313314
extern void gdbstub_exit(int status);
314315

315316
extern int kgdb_single_step;

kernel/debug/debug_core.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,12 @@ static int kgdb_cpu_enter(struct kgdb_state *ks, struct pt_regs *regs,
575575
raw_spin_lock(&dbg_slave_lock);
576576

577577
#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+
578582
/* 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)
580584
kgdb_roundup_cpus(flags);
581585
#endif
582586

@@ -678,11 +682,11 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs)
678682
if (arch_kgdb_ops.enable_nmi)
679683
arch_kgdb_ops.enable_nmi(0);
680684

685+
memset(ks, 0, sizeof(struct kgdb_state));
681686
ks->cpu = raw_smp_processor_id();
682687
ks->ex_vector = evector;
683688
ks->signo = signo;
684689
ks->err_code = ecode;
685-
ks->kgdb_usethreadid = 0;
686690
ks->linux_regs = regs;
687691

688692
if (kgdb_reenter_check(ks))
@@ -732,6 +736,30 @@ int kgdb_nmicallback(int cpu, void *regs)
732736
return 1;
733737
}
734738

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);
757+
return 0;
758+
}
759+
#endif
760+
return 1;
761+
}
762+
735763
static void kgdb_console_write(struct console *co, const char *s,
736764
unsigned count)
737765
{

kernel/debug/debug_core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ struct kgdb_state {
2626
unsigned long threadid;
2727
long kgdb_usethreadid;
2828
struct pt_regs *linux_regs;
29+
atomic_t *send_ready;
2930
};
3031

3132
/* Exception state values */
@@ -74,11 +75,13 @@ extern int kdb_stub(struct kgdb_state *ks);
7475
extern int kdb_parse(const char *cmdstr);
7576
extern int kdb_common_init_state(struct kgdb_state *ks);
7677
extern int kdb_common_deinit_state(void);
78+
#define KGDB_KDB_REASON_SYSTEM_NMI KDB_REASON_SYSTEM_NMI
7779
#else /* ! CONFIG_KGDB_KDB */
7880
static inline int kdb_stub(struct kgdb_state *ks)
7981
{
8082
return DBG_PASS_EVENT;
8183
}
84+
#define KGDB_KDB_REASON_SYSTEM_NMI 0
8285
#endif /* CONFIG_KGDB_KDB */
8386

8487
#endif /* _DEBUG_CORE_H_ */

kernel/debug/kdb/kdb_debugger.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ int kdb_stub(struct kgdb_state *ks)
6969
if (atomic_read(&kgdb_setting_breakpoint))
7070
reason = KDB_REASON_KEYBOARD;
7171

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())
7376
reason = KDB_REASON_NMI;
7477

7578
for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {

kernel/debug/kdb/kdb_main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,9 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
12001200
instruction_pointer(regs));
12011201
kdb_dumpregs(regs);
12021202
break;
1203+
case KDB_REASON_SYSTEM_NMI:
1204+
kdb_printf("due to System NonMaskable Interrupt\n");
1205+
break;
12031206
case KDB_REASON_NMI:
12041207
kdb_printf("due to NonMaskable Interrupt @ "
12051208
kdb_machreg_fmt "\n",

0 commit comments

Comments
 (0)