aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/crash.c20
-rw-r--r--arch/i386/kernel/nmi.c85
-rw-r--r--arch/i386/kernel/traps.c23
-rw-r--r--arch/i386/oprofile/nmi_int.c47
-rw-r--r--arch/i386/oprofile/nmi_timer_int.c33
-rw-r--r--arch/x86_64/kernel/crash.c20
-rw-r--r--arch/x86_64/kernel/nmi.c102
-rw-r--r--include/asm-i386/nmi.h21
-rw-r--r--include/asm-x86_64/nmi.h21
-rw-r--r--kernel/sysctl.c4
10 files changed, 116 insertions, 260 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index 5b96f038367f..736c76d6b31d 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -22,6 +22,8 @@
22#include <asm/nmi.h> 22#include <asm/nmi.h>
23#include <asm/hw_irq.h> 23#include <asm/hw_irq.h>
24#include <asm/apic.h> 24#include <asm/apic.h>
25#include <asm/kdebug.h>
26
25#include <mach_ipi.h> 27#include <mach_ipi.h>
26 28
27 29
@@ -93,9 +95,18 @@ static void crash_save_self(struct pt_regs *regs)
93#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) 95#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
94static atomic_t waiting_for_crash_ipi; 96static atomic_t waiting_for_crash_ipi;
95 97
96static int crash_nmi_callback(struct pt_regs *regs, int cpu) 98static int crash_nmi_callback(struct notifier_block *self,
99 unsigned long val, void *data)
97{ 100{
101 struct pt_regs *regs;
98 struct pt_regs fixed_regs; 102 struct pt_regs fixed_regs;
103 int cpu;
104
105 if (val != DIE_NMI)
106 return NOTIFY_OK;
107
108 regs = ((struct die_args *)data)->regs;
109 cpu = raw_smp_processor_id();
99 110
100 /* Don't do anything if this handler is invoked on crashing cpu. 111 /* Don't do anything if this handler is invoked on crashing cpu.
101 * Otherwise, system will completely hang. Crashing cpu can get 112 * Otherwise, system will completely hang. Crashing cpu can get
@@ -125,13 +136,18 @@ static void smp_send_nmi_allbutself(void)
125 send_IPI_allbutself(NMI_VECTOR); 136 send_IPI_allbutself(NMI_VECTOR);
126} 137}
127 138
139static struct notifier_block crash_nmi_nb = {
140 .notifier_call = crash_nmi_callback,
141};
142
128static void nmi_shootdown_cpus(void) 143static void nmi_shootdown_cpus(void)
129{ 144{
130 unsigned long msecs; 145 unsigned long msecs;
131 146
132 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 147 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
133 /* Would it be better to replace the trap vector here? */ 148 /* Would it be better to replace the trap vector here? */
134 set_nmi_callback(crash_nmi_callback); 149 if (register_die_notifier(&crash_nmi_nb))
150 return; /* return what? */
135 /* Ensure the new callback function is set before sending 151 /* Ensure the new callback function is set before sending
136 * out the NMI 152 * out the NMI
137 */ 153 */
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index bd96ea4f2942..acd3fdea2a21 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -42,20 +42,6 @@ static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]);
42 */ 42 */
43#define NMI_MAX_COUNTER_BITS 66 43#define NMI_MAX_COUNTER_BITS 66
44 44
45/*
46 * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
47 * - it may be reserved by some other driver, or not
48 * - when not reserved by some other driver, it may be used for
49 * the NMI watchdog, or not
50 *
51 * This is maintained separately from nmi_active because the NMI
52 * watchdog may also be driven from the I/O APIC timer.
53 */
54static DEFINE_SPINLOCK(lapic_nmi_owner_lock);
55static unsigned int lapic_nmi_owner;
56#define LAPIC_NMI_WATCHDOG (1<<0)
57#define LAPIC_NMI_RESERVED (1<<1)
58
59/* nmi_active: 45/* nmi_active:
60 * >0: the lapic NMI watchdog is active, but can be disabled 46 * >0: the lapic NMI watchdog is active, but can be disabled
61 * <0: the lapic NMI watchdog has not been set up, and cannot 47 * <0: the lapic NMI watchdog has not been set up, and cannot
@@ -325,33 +311,6 @@ static void enable_lapic_nmi_watchdog(void)
325 touch_nmi_watchdog(); 311 touch_nmi_watchdog();
326} 312}
327 313
328int reserve_lapic_nmi(void)
329{
330 unsigned int old_owner;
331
332 spin_lock(&lapic_nmi_owner_lock);
333 old_owner = lapic_nmi_owner;
334 lapic_nmi_owner |= LAPIC_NMI_RESERVED;
335 spin_unlock(&lapic_nmi_owner_lock);
336 if (old_owner & LAPIC_NMI_RESERVED)
337 return -EBUSY;
338 if (old_owner & LAPIC_NMI_WATCHDOG)
339 disable_lapic_nmi_watchdog();
340 return 0;
341}
342
343void release_lapic_nmi(void)
344{
345 unsigned int new_owner;
346
347 spin_lock(&lapic_nmi_owner_lock);
348 new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
349 lapic_nmi_owner = new_owner;
350 spin_unlock(&lapic_nmi_owner_lock);
351 if (new_owner & LAPIC_NMI_WATCHDOG)
352 enable_lapic_nmi_watchdog();
353}
354
355void disable_timer_nmi_watchdog(void) 314void disable_timer_nmi_watchdog(void)
356{ 315{
357 BUG_ON(nmi_watchdog != NMI_IO_APIC); 316 BUG_ON(nmi_watchdog != NMI_IO_APIC);
@@ -866,6 +825,15 @@ done:
866 return rc; 825 return rc;
867} 826}
868 827
828int do_nmi_callback(struct pt_regs * regs, int cpu)
829{
830#ifdef CONFIG_SYSCTL
831 if (unknown_nmi_panic)
832 return unknown_nmi_panic_callback(regs, cpu);
833#endif
834 return 0;
835}
836
869#ifdef CONFIG_SYSCTL 837#ifdef CONFIG_SYSCTL
870 838
871static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) 839static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
@@ -873,37 +841,8 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
873 unsigned char reason = get_nmi_reason(); 841 unsigned char reason = get_nmi_reason();
874 char buf[64]; 842 char buf[64];
875 843
876 if (!(reason & 0xc0)) { 844 sprintf(buf, "NMI received for unknown reason %02x\n", reason);
877 sprintf(buf, "NMI received for unknown reason %02x\n", reason); 845 die_nmi(regs, buf);
878 die_nmi(regs, buf);
879 }
880 return 0;
881}
882
883/*
884 * proc handler for /proc/sys/kernel/unknown_nmi_panic
885 */
886int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file,
887 void __user *buffer, size_t *length, loff_t *ppos)
888{
889 int old_state;
890
891 old_state = unknown_nmi_panic;
892 proc_dointvec(table, write, file, buffer, length, ppos);
893 if (!!old_state == !!unknown_nmi_panic)
894 return 0;
895
896 if (unknown_nmi_panic) {
897 if (reserve_lapic_nmi() < 0) {
898 unknown_nmi_panic = 0;
899 return -EBUSY;
900 } else {
901 set_nmi_callback(unknown_nmi_panic_callback);
902 }
903 } else {
904 release_lapic_nmi();
905 unset_nmi_callback();
906 }
907 return 0; 846 return 0;
908} 847}
909 848
@@ -917,7 +856,5 @@ EXPORT_SYMBOL(reserve_perfctr_nmi);
917EXPORT_SYMBOL(release_perfctr_nmi); 856EXPORT_SYMBOL(release_perfctr_nmi);
918EXPORT_SYMBOL(reserve_evntsel_nmi); 857EXPORT_SYMBOL(reserve_evntsel_nmi);
919EXPORT_SYMBOL(release_evntsel_nmi); 858EXPORT_SYMBOL(release_evntsel_nmi);
920EXPORT_SYMBOL(reserve_lapic_nmi);
921EXPORT_SYMBOL(release_lapic_nmi);
922EXPORT_SYMBOL(disable_timer_nmi_watchdog); 859EXPORT_SYMBOL(disable_timer_nmi_watchdog);
923EXPORT_SYMBOL(enable_timer_nmi_watchdog); 860EXPORT_SYMBOL(enable_timer_nmi_watchdog);
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 282f0bd40dfd..7db664d0b25c 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -706,13 +706,6 @@ void die_nmi (struct pt_regs *regs, const char *msg)
706 do_exit(SIGSEGV); 706 do_exit(SIGSEGV);
707} 707}
708 708
709static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
710{
711 return 0;
712}
713
714static nmi_callback_t nmi_callback = dummy_nmi_callback;
715
716static void default_do_nmi(struct pt_regs * regs) 709static void default_do_nmi(struct pt_regs * regs)
717{ 710{
718 unsigned char reason = 0; 711 unsigned char reason = 0;
@@ -732,9 +725,10 @@ static void default_do_nmi(struct pt_regs * regs)
732 */ 725 */
733 if (nmi_watchdog_tick(regs, reason)) 726 if (nmi_watchdog_tick(regs, reason))
734 return; 727 return;
728 if (!do_nmi_callback(regs, smp_processor_id()))
735#endif 729#endif
736 if (!rcu_dereference(nmi_callback)(regs, smp_processor_id()))
737 unknown_nmi_error(reason, regs); 730 unknown_nmi_error(reason, regs);
731
738 return; 732 return;
739 } 733 }
740 if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) 734 if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
@@ -765,19 +759,6 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code)
765 nmi_exit(); 759 nmi_exit();
766} 760}
767 761
768void set_nmi_callback(nmi_callback_t callback)
769{
770 vmalloc_sync_all();
771 rcu_assign_pointer(nmi_callback, callback);
772}
773EXPORT_SYMBOL_GPL(set_nmi_callback);
774
775void unset_nmi_callback(void)
776{
777 nmi_callback = dummy_nmi_callback;
778}
779EXPORT_SYMBOL_GPL(unset_nmi_callback);
780
781#ifdef CONFIG_KPROBES 762#ifdef CONFIG_KPROBES
782fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) 763fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code)
783{ 764{
diff --git a/arch/i386/oprofile/nmi_int.c b/arch/i386/oprofile/nmi_int.c
index 8710ca081b1e..b3610188bcf0 100644
--- a/arch/i386/oprofile/nmi_int.c
+++ b/arch/i386/oprofile/nmi_int.c
@@ -17,14 +17,15 @@
17#include <asm/nmi.h> 17#include <asm/nmi.h>
18#include <asm/msr.h> 18#include <asm/msr.h>
19#include <asm/apic.h> 19#include <asm/apic.h>
20#include <asm/kdebug.h>
20 21
21#include "op_counter.h" 22#include "op_counter.h"
22#include "op_x86_model.h" 23#include "op_x86_model.h"
23 24
24static struct op_x86_model_spec const * model; 25static struct op_x86_model_spec const * model;
25static struct op_msrs cpu_msrs[NR_CPUS]; 26static struct op_msrs cpu_msrs[NR_CPUS];
26static unsigned long saved_lvtpc[NR_CPUS]; 27static unsigned long saved_lvtpc[NR_CPUS];
27 28
28static int nmi_start(void); 29static int nmi_start(void);
29static void nmi_stop(void); 30static void nmi_stop(void);
30 31
@@ -82,13 +83,24 @@ static void exit_driverfs(void)
82#define exit_driverfs() do { } while (0) 83#define exit_driverfs() do { } while (0)
83#endif /* CONFIG_PM */ 84#endif /* CONFIG_PM */
84 85
85 86int profile_exceptions_notify(struct notifier_block *self,
86static int nmi_callback(struct pt_regs * regs, int cpu) 87 unsigned long val, void *data)
87{ 88{
88 return model->check_ctrs(regs, &cpu_msrs[cpu]); 89 struct die_args *args = (struct die_args *)data;
90 int ret = NOTIFY_DONE;
91 int cpu = smp_processor_id();
92
93 switch(val) {
94 case DIE_NMI:
95 if (model->check_ctrs(args->regs, &cpu_msrs[cpu]))
96 ret = NOTIFY_STOP;
97 break;
98 default:
99 break;
100 }
101 return ret;
89} 102}
90 103
91
92static void nmi_cpu_save_registers(struct op_msrs * msrs) 104static void nmi_cpu_save_registers(struct op_msrs * msrs)
93{ 105{
94 unsigned int const nr_ctrs = model->num_counters; 106 unsigned int const nr_ctrs = model->num_counters;
@@ -174,27 +186,29 @@ static void nmi_cpu_setup(void * dummy)
174 apic_write(APIC_LVTPC, APIC_DM_NMI); 186 apic_write(APIC_LVTPC, APIC_DM_NMI);
175} 187}
176 188
189static struct notifier_block profile_exceptions_nb = {
190 .notifier_call = profile_exceptions_notify,
191 .next = NULL,
192 .priority = 0
193};
177 194
178static int nmi_setup(void) 195static int nmi_setup(void)
179{ 196{
197 int err=0;
198
180 if (!allocate_msrs()) 199 if (!allocate_msrs())
181 return -ENOMEM; 200 return -ENOMEM;
182 201
183 /* We walk a thin line between law and rape here. 202 if ((err = register_die_notifier(&profile_exceptions_nb))){
184 * We need to be careful to install our NMI handler
185 * without actually triggering any NMIs as this will
186 * break the core code horrifically.
187 */
188 if (reserve_lapic_nmi() < 0) {
189 free_msrs(); 203 free_msrs();
190 return -EBUSY; 204 return err;
191 } 205 }
206
192 /* We need to serialize save and setup for HT because the subset 207 /* We need to serialize save and setup for HT because the subset
193 * of msrs are distinct for save and setup operations 208 * of msrs are distinct for save and setup operations
194 */ 209 */
195 on_each_cpu(nmi_save_registers, NULL, 0, 1); 210 on_each_cpu(nmi_save_registers, NULL, 0, 1);
196 on_each_cpu(nmi_cpu_setup, NULL, 0, 1); 211 on_each_cpu(nmi_cpu_setup, NULL, 0, 1);
197 set_nmi_callback(nmi_callback);
198 nmi_enabled = 1; 212 nmi_enabled = 1;
199 return 0; 213 return 0;
200} 214}
@@ -250,8 +264,7 @@ static void nmi_shutdown(void)
250{ 264{
251 nmi_enabled = 0; 265 nmi_enabled = 0;
252 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1); 266 on_each_cpu(nmi_cpu_shutdown, NULL, 0, 1);
253 unset_nmi_callback(); 267 unregister_die_notifier(&profile_exceptions_nb);
254 release_lapic_nmi();
255 free_msrs(); 268 free_msrs();
256} 269}
257 270
diff --git a/arch/i386/oprofile/nmi_timer_int.c b/arch/i386/oprofile/nmi_timer_int.c
index a33a73bb502d..93ca48f804ac 100644
--- a/arch/i386/oprofile/nmi_timer_int.c
+++ b/arch/i386/oprofile/nmi_timer_int.c
@@ -17,32 +17,49 @@
17#include <asm/nmi.h> 17#include <asm/nmi.h>
18#include <asm/apic.h> 18#include <asm/apic.h>
19#include <asm/ptrace.h> 19#include <asm/ptrace.h>
20#include <asm/kdebug.h>
20 21
21static int nmi_timer_callback(struct pt_regs * regs, int cpu) 22int profile_timer_exceptions_notify(struct notifier_block *self,
23 unsigned long val, void *data)
22{ 24{
23 oprofile_add_sample(regs, 0); 25 struct die_args *args = (struct die_args *)data;
24 return 1; 26 int ret = NOTIFY_DONE;
27
28 switch(val) {
29 case DIE_NMI:
30 oprofile_add_sample(args->regs, 0);
31 ret = NOTIFY_STOP;
32 break;
33 default:
34 break;
35 }
36 return ret;
25} 37}
26 38
39static struct notifier_block profile_timer_exceptions_nb = {
40 .notifier_call = profile_timer_exceptions_notify,
41 .next = NULL,
42 .priority = 0
43};
44
27static int timer_start(void) 45static int timer_start(void)
28{ 46{
29 disable_timer_nmi_watchdog(); 47 if (register_die_notifier(&profile_timer_exceptions_nb))
30 set_nmi_callback(nmi_timer_callback); 48 return 1;
31 return 0; 49 return 0;
32} 50}
33 51
34 52
35static void timer_stop(void) 53static void timer_stop(void)
36{ 54{
37 enable_timer_nmi_watchdog(); 55 unregister_die_notifier(&profile_timer_exceptions_nb);
38 unset_nmi_callback();
39 synchronize_sched(); /* Allow already-started NMIs to complete. */ 56 synchronize_sched(); /* Allow already-started NMIs to complete. */
40} 57}
41 58
42 59
43int __init op_nmi_timer_init(struct oprofile_operations * ops) 60int __init op_nmi_timer_init(struct oprofile_operations * ops)
44{ 61{
45 if (atomic_read(&nmi_active) <= 0) 62 if ((nmi_watchdog != NMI_IO_APIC) || (atomic_read(&nmi_active) <= 0))
46 return -ENODEV; 63 return -ENODEV;
47 64
48 ops->start = timer_start; 65 ops->start = timer_start;
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
index d8d5750d6106..44c8af65325e 100644
--- a/arch/x86_64/kernel/crash.c
+++ b/arch/x86_64/kernel/crash.c
@@ -23,6 +23,7 @@
23#include <asm/nmi.h> 23#include <asm/nmi.h>
24#include <asm/hw_irq.h> 24#include <asm/hw_irq.h>
25#include <asm/mach_apic.h> 25#include <asm/mach_apic.h>
26#include <asm/kdebug.h>
26 27
27/* This keeps a track of which one is crashing cpu. */ 28/* This keeps a track of which one is crashing cpu. */
28static int crashing_cpu; 29static int crashing_cpu;
@@ -95,8 +96,18 @@ static void crash_save_self(struct pt_regs *regs)
95#ifdef CONFIG_SMP 96#ifdef CONFIG_SMP
96static atomic_t waiting_for_crash_ipi; 97static atomic_t waiting_for_crash_ipi;
97 98
98static int crash_nmi_callback(struct pt_regs *regs, int cpu) 99static int crash_nmi_callback(struct notifier_block *self,
100 unsigned long val, void *data)
99{ 101{
102 struct pt_regs *regs;
103 int cpu;
104
105 if (val != DIE_NMI)
106 return NOTIFY_OK;
107
108 regs = ((struct die_args *)data)->regs;
109 cpu = raw_smp_processor_id();
110
100 /* 111 /*
101 * Don't do anything if this handler is invoked on crashing cpu. 112 * Don't do anything if this handler is invoked on crashing cpu.
102 * Otherwise, system will completely hang. Crashing cpu can get 113 * Otherwise, system will completely hang. Crashing cpu can get
@@ -127,12 +138,17 @@ static void smp_send_nmi_allbutself(void)
127 * cpu hotplug shouldn't matter. 138 * cpu hotplug shouldn't matter.
128 */ 139 */
129 140
141static struct notifier_block crash_nmi_nb = {
142 .notifier_call = crash_nmi_callback,
143};
144
130static void nmi_shootdown_cpus(void) 145static void nmi_shootdown_cpus(void)
131{ 146{
132 unsigned long msecs; 147 unsigned long msecs;
133 148
134 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1); 149 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
135 set_nmi_callback(crash_nmi_callback); 150 if (register_die_notifier(&crash_nmi_nb))
151 return; /* return what? */
136 152
137 /* 153 /*
138 * Ensure the new callback function is set before sending 154 * Ensure the new callback function is set before sending
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index f6b881b23a70..9d175dcf3a2d 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -41,20 +41,6 @@ static DEFINE_PER_CPU(unsigned, evntsel_nmi_owner[2]);
41 */ 41 */
42#define NMI_MAX_COUNTER_BITS 66 42#define NMI_MAX_COUNTER_BITS 66
43 43
44/*
45 * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
46 * - it may be reserved by some other driver, or not
47 * - when not reserved by some other driver, it may be used for
48 * the NMI watchdog, or not
49 *
50 * This is maintained separately from nmi_active because the NMI
51 * watchdog may also be driven from the I/O APIC timer.
52 */
53static DEFINE_SPINLOCK(lapic_nmi_owner_lock);
54static unsigned int lapic_nmi_owner;
55#define LAPIC_NMI_WATCHDOG (1<<0)
56#define LAPIC_NMI_RESERVED (1<<1)
57
58/* nmi_active: 44/* nmi_active:
59 * >0: the lapic NMI watchdog is active, but can be disabled 45 * >0: the lapic NMI watchdog is active, but can be disabled
60 * <0: the lapic NMI watchdog has not been set up, and cannot 46 * <0: the lapic NMI watchdog has not been set up, and cannot
@@ -321,33 +307,6 @@ static void enable_lapic_nmi_watchdog(void)
321 touch_nmi_watchdog(); 307 touch_nmi_watchdog();
322} 308}
323 309
324int reserve_lapic_nmi(void)
325{
326 unsigned int old_owner;
327
328 spin_lock(&lapic_nmi_owner_lock);
329 old_owner = lapic_nmi_owner;
330 lapic_nmi_owner |= LAPIC_NMI_RESERVED;
331 spin_unlock(&lapic_nmi_owner_lock);
332 if (old_owner & LAPIC_NMI_RESERVED)
333 return -EBUSY;
334 if (old_owner & LAPIC_NMI_WATCHDOG)
335 disable_lapic_nmi_watchdog();
336 return 0;
337}
338
339void release_lapic_nmi(void)
340{
341 unsigned int new_owner;
342
343 spin_lock(&lapic_nmi_owner_lock);
344 new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED;
345 lapic_nmi_owner = new_owner;
346 spin_unlock(&lapic_nmi_owner_lock);
347 if (new_owner & LAPIC_NMI_WATCHDOG)
348 enable_lapic_nmi_watchdog();
349}
350
351void disable_timer_nmi_watchdog(void) 310void disable_timer_nmi_watchdog(void)
352{ 311{
353 BUG_ON(nmi_watchdog != NMI_IO_APIC); 312 BUG_ON(nmi_watchdog != NMI_IO_APIC);
@@ -762,13 +721,6 @@ done:
762 return rc; 721 return rc;
763} 722}
764 723
765static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu)
766{
767 return 0;
768}
769
770static nmi_callback_t nmi_callback = dummy_nmi_callback;
771
772asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) 724asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
773{ 725{
774 nmi_enter(); 726 nmi_enter();
@@ -779,21 +731,12 @@ asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
779 731
780int do_nmi_callback(struct pt_regs * regs, int cpu) 732int do_nmi_callback(struct pt_regs * regs, int cpu)
781{ 733{
782 return rcu_dereference(nmi_callback)(regs, cpu); 734#ifdef CONFIG_SYSCTL
783} 735 if (unknown_nmi_panic)
784 736 return unknown_nmi_panic_callback(regs, cpu);
785void set_nmi_callback(nmi_callback_t callback) 737#endif
786{ 738 return 0;
787 vmalloc_sync_all();
788 rcu_assign_pointer(nmi_callback, callback);
789}
790EXPORT_SYMBOL_GPL(set_nmi_callback);
791
792void unset_nmi_callback(void)
793{
794 nmi_callback = dummy_nmi_callback;
795} 739}
796EXPORT_SYMBOL_GPL(unset_nmi_callback);
797 740
798#ifdef CONFIG_SYSCTL 741#ifdef CONFIG_SYSCTL
799 742
@@ -802,37 +745,8 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
802 unsigned char reason = get_nmi_reason(); 745 unsigned char reason = get_nmi_reason();
803 char buf[64]; 746 char buf[64];
804 747
805 if (!(reason & 0xc0)) { 748 sprintf(buf, "NMI received for unknown reason %02x\n", reason);
806 sprintf(buf, "NMI received for unknown reason %02x\n", reason); 749 die_nmi(buf,regs);
807 die_nmi(buf,regs);
808 }
809 return 0;
810}
811
812/*
813 * proc handler for /proc/sys/kernel/unknown_nmi_panic
814 */
815int proc_unknown_nmi_panic(struct ctl_table *table, int write, struct file *file,
816 void __user *buffer, size_t *length, loff_t *ppos)
817{
818 int old_state;
819
820 old_state = unknown_nmi_panic;
821 proc_dointvec(table, write, file, buffer, length, ppos);
822 if (!!old_state == !!unknown_nmi_panic)
823 return 0;
824
825 if (unknown_nmi_panic) {
826 if (reserve_lapic_nmi() < 0) {
827 unknown_nmi_panic = 0;
828 return -EBUSY;
829 } else {
830 set_nmi_callback(unknown_nmi_panic_callback);
831 }
832 } else {
833 release_lapic_nmi();
834 unset_nmi_callback();
835 }
836 return 0; 750 return 0;
837} 751}
838 752
@@ -846,8 +760,6 @@ EXPORT_SYMBOL(reserve_perfctr_nmi);
846EXPORT_SYMBOL(release_perfctr_nmi); 760EXPORT_SYMBOL(release_perfctr_nmi);
847EXPORT_SYMBOL(reserve_evntsel_nmi); 761EXPORT_SYMBOL(reserve_evntsel_nmi);
848EXPORT_SYMBOL(release_evntsel_nmi); 762EXPORT_SYMBOL(release_evntsel_nmi);
849EXPORT_SYMBOL(reserve_lapic_nmi);
850EXPORT_SYMBOL(release_lapic_nmi);
851EXPORT_SYMBOL(disable_timer_nmi_watchdog); 763EXPORT_SYMBOL(disable_timer_nmi_watchdog);
852EXPORT_SYMBOL(enable_timer_nmi_watchdog); 764EXPORT_SYMBOL(enable_timer_nmi_watchdog);
853EXPORT_SYMBOL(touch_nmi_watchdog); 765EXPORT_SYMBOL(touch_nmi_watchdog);
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index da0e0b4e9139..34d6bf063b6e 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -6,24 +6,13 @@
6 6
7#include <linux/pm.h> 7#include <linux/pm.h>
8 8
9struct pt_regs;
10
11typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
12
13/**
14 * set_nmi_callback
15 *
16 * Set a handler for an NMI. Only one handler may be
17 * set. Return 1 if the NMI was handled.
18 */
19void set_nmi_callback(nmi_callback_t callback);
20
21/** 9/**
22 * unset_nmi_callback 10 * do_nmi_callback
23 * 11 *
24 * Remove the handler previously set. 12 * Check to see if a callback exists and execute it. Return 1
13 * if the handler exists and was handled successfully.
25 */ 14 */
26void unset_nmi_callback(void); 15int do_nmi_callback(struct pt_regs *regs, int cpu);
27 16
28extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); 17extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
29extern int avail_to_resrv_perfctr_nmi(unsigned int); 18extern int avail_to_resrv_perfctr_nmi(unsigned int);
@@ -33,8 +22,6 @@ extern int reserve_evntsel_nmi(unsigned int);
33extern void release_evntsel_nmi(unsigned int); 22extern void release_evntsel_nmi(unsigned int);
34 23
35extern void setup_apic_nmi_watchdog (void *); 24extern void setup_apic_nmi_watchdog (void *);
36extern int reserve_lapic_nmi(void);
37extern void release_lapic_nmi(void);
38extern void disable_timer_nmi_watchdog(void); 25extern void disable_timer_nmi_watchdog(void);
39extern void enable_timer_nmi_watchdog(void); 26extern void enable_timer_nmi_watchdog(void);
40extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); 27extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index 8f02a2a416e6..8818c39d34e0 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -7,25 +7,6 @@
7#include <linux/pm.h> 7#include <linux/pm.h>
8#include <asm/io.h> 8#include <asm/io.h>
9 9
10struct pt_regs;
11
12typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu);
13
14/**
15 * set_nmi_callback
16 *
17 * Set a handler for an NMI. Only one handler may be
18 * set. Return 1 if the NMI was handled.
19 */
20void set_nmi_callback(nmi_callback_t callback);
21
22/**
23 * unset_nmi_callback
24 *
25 * Remove the handler previously set.
26 */
27void unset_nmi_callback(void);
28
29/** 10/**
30 * do_nmi_callback 11 * do_nmi_callback
31 * 12 *
@@ -72,8 +53,6 @@ extern int reserve_evntsel_nmi(unsigned int);
72extern void release_evntsel_nmi(unsigned int); 53extern void release_evntsel_nmi(unsigned int);
73 54
74extern void setup_apic_nmi_watchdog (void *); 55extern void setup_apic_nmi_watchdog (void *);
75extern int reserve_lapic_nmi(void);
76extern void release_lapic_nmi(void);
77extern void disable_timer_nmi_watchdog(void); 56extern void disable_timer_nmi_watchdog(void);
78extern void enable_timer_nmi_watchdog(void); 57extern void enable_timer_nmi_watchdog(void);
79extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); 58extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 362a0cc37138..83f168361624 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,8 +76,6 @@ extern int compat_log;
76 76
77#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) 77#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
78int unknown_nmi_panic; 78int unknown_nmi_panic;
79extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *,
80 void __user *, size_t *, loff_t *);
81#endif 79#endif
82 80
83/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ 81/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
@@ -628,7 +626,7 @@ static ctl_table kern_table[] = {
628 .data = &unknown_nmi_panic, 626 .data = &unknown_nmi_panic,
629 .maxlen = sizeof (int), 627 .maxlen = sizeof (int),
630 .mode = 0644, 628 .mode = 0644,
631 .proc_handler = &proc_unknown_nmi_panic, 629 .proc_handler = &proc_dointvec,
632 }, 630 },
633#endif 631#endif
634#if defined(CONFIG_X86) 632#if defined(CONFIG_X86)