diff options
| -rw-r--r-- | include/linux/kdb.h | 1 | ||||
| -rw-r--r-- | include/linux/kgdb.h | 1 | ||||
| -rw-r--r-- | kernel/debug/debug_core.c | 32 | ||||
| -rw-r--r-- | kernel/debug/debug_core.h | 3 | ||||
| -rw-r--r-- | kernel/debug/kdb/kdb_debugger.c | 5 | ||||
| -rw-r--r-- | kernel/debug/kdb/kdb_main.c | 3 |
6 files changed, 42 insertions, 3 deletions
diff --git a/include/linux/kdb.h b/include/linux/kdb.h index 7f6fe6e015bc..290db1269c4c 100644 --- a/include/linux/kdb.h +++ b/include/linux/kdb.h | |||
| @@ -109,6 +109,7 @@ typedef enum { | |||
| 109 | KDB_REASON_RECURSE, /* Recursive entry to kdb; | 109 | KDB_REASON_RECURSE, /* Recursive entry to kdb; |
| 110 | * regs probably valid */ | 110 | * regs probably valid */ |
| 111 | KDB_REASON_SSTEP, /* Single Step trap. - regs valid */ | 111 | KDB_REASON_SSTEP, /* Single Step trap. - regs valid */ |
| 112 | KDB_REASON_SYSTEM_NMI, /* In NMI due to SYSTEM cmd; regs valid */ | ||
| 112 | } kdb_reason_t; | 113 | } kdb_reason_t; |
| 113 | 114 | ||
| 114 | extern int kdb_trap_printk; | 115 | extern int kdb_trap_printk; |
diff --git a/include/linux/kgdb.h b/include/linux/kgdb.h index c6e091bf39a5..dfb4f2ffdaa2 100644 --- a/include/linux/kgdb.h +++ b/include/linux/kgdb.h | |||
| @@ -310,6 +310,7 @@ extern int | |||
| 310 | kgdb_handle_exception(int ex_vector, int signo, int err_code, | 310 | kgdb_handle_exception(int ex_vector, int signo, int err_code, |
| 311 | struct pt_regs *regs); | 311 | struct pt_regs *regs); |
| 312 | extern int kgdb_nmicallback(int cpu, void *regs); | 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 | extern void gdbstub_exit(int status); | 314 | extern void gdbstub_exit(int status); |
| 314 | 315 | ||
| 315 | extern int kgdb_single_step; | 316 | extern int kgdb_single_step; |
diff --git a/kernel/debug/debug_core.c b/kernel/debug/debug_core.c index 0506d447aed2..7d2f35e5df2f 100644 --- a/kernel/debug/debug_core.c +++ b/kernel/debug/debug_core.c | |||
| @@ -575,8 +575,12 @@ return_normal: | |||
| 575 | raw_spin_lock(&dbg_slave_lock); | 575 | raw_spin_lock(&dbg_slave_lock); |
| 576 | 576 | ||
| 577 | #ifdef CONFIG_SMP | 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 | /* Signal the other CPUs to enter kgdb_wait() */ | 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 | kgdb_roundup_cpus(flags); | 584 | kgdb_roundup_cpus(flags); |
| 581 | #endif | 585 | #endif |
| 582 | 586 | ||
| @@ -678,11 +682,11 @@ kgdb_handle_exception(int evector, int signo, int ecode, struct pt_regs *regs) | |||
| 678 | if (arch_kgdb_ops.enable_nmi) | 682 | if (arch_kgdb_ops.enable_nmi) |
| 679 | arch_kgdb_ops.enable_nmi(0); | 683 | arch_kgdb_ops.enable_nmi(0); |
| 680 | 684 | ||
| 685 | memset(ks, 0, sizeof(struct kgdb_state)); | ||
| 681 | ks->cpu = raw_smp_processor_id(); | 686 | ks->cpu = raw_smp_processor_id(); |
| 682 | ks->ex_vector = evector; | 687 | ks->ex_vector = evector; |
| 683 | ks->signo = signo; | 688 | ks->signo = signo; |
| 684 | ks->err_code = ecode; | 689 | ks->err_code = ecode; |
| 685 | ks->kgdb_usethreadid = 0; | ||
| 686 | ks->linux_regs = regs; | 690 | ks->linux_regs = regs; |
| 687 | 691 | ||
| 688 | if (kgdb_reenter_check(ks)) | 692 | if (kgdb_reenter_check(ks)) |
| @@ -732,6 +736,30 @@ int kgdb_nmicallback(int cpu, void *regs) | |||
| 732 | return 1; | 736 | return 1; |
| 733 | } | 737 | } |
| 734 | 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); | ||
| 757 | return 0; | ||
| 758 | } | ||
| 759 | #endif | ||
| 760 | return 1; | ||
| 761 | } | ||
| 762 | |||
| 735 | static void kgdb_console_write(struct console *co, const char *s, | 763 | static void kgdb_console_write(struct console *co, const char *s, |
| 736 | unsigned count) | 764 | unsigned count) |
| 737 | { | 765 | { |
diff --git a/kernel/debug/debug_core.h b/kernel/debug/debug_core.h index 2235967e78b0..572aa4f5677c 100644 --- a/kernel/debug/debug_core.h +++ b/kernel/debug/debug_core.h | |||
| @@ -26,6 +26,7 @@ struct kgdb_state { | |||
| 26 | unsigned long threadid; | 26 | unsigned long threadid; |
| 27 | long kgdb_usethreadid; | 27 | long kgdb_usethreadid; |
| 28 | struct pt_regs *linux_regs; | 28 | struct pt_regs *linux_regs; |
| 29 | atomic_t *send_ready; | ||
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | /* Exception state values */ | 32 | /* Exception state values */ |
| @@ -74,11 +75,13 @@ extern int kdb_stub(struct kgdb_state *ks); | |||
| 74 | extern int kdb_parse(const char *cmdstr); | 75 | extern int kdb_parse(const char *cmdstr); |
| 75 | extern int kdb_common_init_state(struct kgdb_state *ks); | 76 | extern int kdb_common_init_state(struct kgdb_state *ks); |
| 76 | extern int kdb_common_deinit_state(void); | 77 | extern int kdb_common_deinit_state(void); |
| 78 | #define KGDB_KDB_REASON_SYSTEM_NMI KDB_REASON_SYSTEM_NMI | ||
| 77 | #else /* ! CONFIG_KGDB_KDB */ | 79 | #else /* ! CONFIG_KGDB_KDB */ |
| 78 | static inline int kdb_stub(struct kgdb_state *ks) | 80 | static inline int kdb_stub(struct kgdb_state *ks) |
| 79 | { | 81 | { |
| 80 | return DBG_PASS_EVENT; | 82 | return DBG_PASS_EVENT; |
| 81 | } | 83 | } |
| 84 | #define KGDB_KDB_REASON_SYSTEM_NMI 0 | ||
| 82 | #endif /* CONFIG_KGDB_KDB */ | 85 | #endif /* CONFIG_KGDB_KDB */ |
| 83 | 86 | ||
| 84 | #endif /* _DEBUG_CORE_H_ */ | 87 | #endif /* _DEBUG_CORE_H_ */ |
diff --git a/kernel/debug/kdb/kdb_debugger.c b/kernel/debug/kdb/kdb_debugger.c index 328d18ef31e4..8859ca34dcfe 100644 --- a/kernel/debug/kdb/kdb_debugger.c +++ b/kernel/debug/kdb/kdb_debugger.c | |||
| @@ -69,7 +69,10 @@ int kdb_stub(struct kgdb_state *ks) | |||
| 69 | if (atomic_read(&kgdb_setting_breakpoint)) | 69 | if (atomic_read(&kgdb_setting_breakpoint)) |
| 70 | reason = KDB_REASON_KEYBOARD; | 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 | reason = KDB_REASON_NMI; | 76 | reason = KDB_REASON_NMI; |
| 74 | 77 | ||
| 75 | for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { | 78 | for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) { |
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index 00eb8f7fbf41..0b097c8a1e50 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c | |||
| @@ -1200,6 +1200,9 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs, | |||
| 1200 | instruction_pointer(regs)); | 1200 | instruction_pointer(regs)); |
| 1201 | kdb_dumpregs(regs); | 1201 | kdb_dumpregs(regs); |
| 1202 | break; | 1202 | break; |
| 1203 | case KDB_REASON_SYSTEM_NMI: | ||
| 1204 | kdb_printf("due to System NonMaskable Interrupt\n"); | ||
| 1205 | break; | ||
| 1203 | case KDB_REASON_NMI: | 1206 | case KDB_REASON_NMI: |
| 1204 | kdb_printf("due to NonMaskable Interrupt @ " | 1207 | kdb_printf("due to NonMaskable Interrupt @ " |
| 1205 | kdb_machreg_fmt "\n", | 1208 | kdb_machreg_fmt "\n", |
