diff options
-rw-r--r-- | arch/x86/kernel/kgdb.c | 18 | ||||
-rw-r--r-- | arch/x86/kernel/traps_32.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 2 | ||||
-rw-r--r-- | include/asm-x86/kdebug.h | 1 |
4 files changed, 20 insertions, 3 deletions
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c index 37194d6374d8..5d7a21119bf8 100644 --- a/arch/x86/kernel/kgdb.c +++ b/arch/x86/kernel/kgdb.c @@ -41,6 +41,7 @@ #include <linux/kgdb.h> #include <linux/init.h> #include <linux/smp.h> +#include <linux/nmi.h> #include <asm/apicdef.h> #include <asm/system.h> @@ -290,6 +291,8 @@ single_step_cont(struct pt_regs *regs, struct die_args *args) return NOTIFY_STOP; } +static int was_in_debug_nmi[NR_CPUS]; + static int __kgdb_notify(struct die_args *args, unsigned long cmd) { struct pt_regs *regs = args->regs; @@ -299,15 +302,24 @@ static int __kgdb_notify(struct die_args *args, unsigned long cmd) if (atomic_read(&kgdb_active) != -1) { /* KGDB CPU roundup */ kgdb_nmicallback(raw_smp_processor_id(), regs); + was_in_debug_nmi[raw_smp_processor_id()] = 1; + touch_nmi_watchdog(); return NOTIFY_STOP; } return NOTIFY_DONE; case DIE_NMI_IPI: if (atomic_read(&kgdb_active) != -1) { - /* KGDB CPU roundup: */ - if (kgdb_nmicallback(raw_smp_processor_id(), regs)) - return NOTIFY_DONE; + /* KGDB CPU roundup */ + kgdb_nmicallback(raw_smp_processor_id(), regs); + was_in_debug_nmi[raw_smp_processor_id()] = 1; + touch_nmi_watchdog(); + } + return NOTIFY_DONE; + + case DIE_NMIUNKNOWN: + if (was_in_debug_nmi[raw_smp_processor_id()]) { + was_in_debug_nmi[raw_smp_processor_id()] = 0; return NOTIFY_STOP; } return NOTIFY_DONE; diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index b22c01e05a18..c5421f30d678 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -708,6 +708,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs) static __kprobes void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) { + if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) + return; #ifdef CONFIG_MCA /* Might actually be able to figure out what the guilty party * is. */ diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 045466681911..055b1650c69d 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c @@ -806,6 +806,8 @@ io_check_error(unsigned char reason, struct pt_regs * regs) static __kprobes void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) { + if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) + return; printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", reason); printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h index 99dcbafa1511..35231240ebdc 100644 --- a/include/asm-x86/kdebug.h +++ b/include/asm-x86/kdebug.h @@ -20,6 +20,7 @@ enum die_val { DIE_CALL, DIE_NMI_IPI, DIE_PAGE_FAULT, + DIE_NMIUNKNOWN, }; extern void printk_address(unsigned long address, int reliable); |