aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorDon Zickus <dzickus@redhat.com>2011-09-30 15:06:19 -0400
committerIngo Molnar <mingo@elte.hu>2011-10-10 00:56:47 -0400
commit1d48922c14b6363f6d5febb12464d804bb5cc53f (patch)
tree2b2745b43b5edcdf1c65d4f0f6c141104468b36b /arch/x86
parent144d31e6f1902a39bc95754d820d356722697850 (diff)
x86, nmi: Split out nmi from traps.c
The nmi stuff is changing a lot and adding more functionality. Split it out from the traps.c file so it doesn't continue to pollute that file. This makes it easier to find and expand all the future nmi related work. No real functional changes here. Signed-off-by: Don Zickus <dzickus@redhat.com> Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1317409584-23662-2-git-send-email-dzickus@redhat.com Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/Makefile2
-rw-r--r--arch/x86/kernel/nmi.c178
-rw-r--r--arch/x86/kernel/traps.c155
3 files changed, 179 insertions, 156 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 82f2912155a..8baca3c4871 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -19,7 +19,7 @@ endif
19 19
20obj-y := process_$(BITS).o signal.o entry_$(BITS).o 20obj-y := process_$(BITS).o signal.o entry_$(BITS).o
21obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o 21obj-y += traps.o irq.o irq_$(BITS).o dumpstack_$(BITS).o
22obj-y += time.o ioport.o ldt.o dumpstack.o 22obj-y += time.o ioport.o ldt.o dumpstack.o nmi.o
23obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o 23obj-y += setup.o x86_init.o i8259.o irqinit.o jump_label.o
24obj-$(CONFIG_IRQ_WORK) += irq_work.o 24obj-$(CONFIG_IRQ_WORK) += irq_work.o
25obj-y += probe_roms.o 25obj-y += probe_roms.o
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
new file mode 100644
index 00000000000..68d758aca8c
--- /dev/null
+++ b/arch/x86/kernel/nmi.c
@@ -0,0 +1,178 @@
1/*
2 * Copyright (C) 1991, 1992 Linus Torvalds
3 * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
4 *
5 * Pentium III FXSR, SSE support
6 * Gareth Hughes <gareth@valinux.com>, May 2000
7 */
8
9/*
10 * Handle hardware traps and faults.
11 */
12#include <linux/spinlock.h>
13#include <linux/kprobes.h>
14#include <linux/kdebug.h>
15#include <linux/nmi.h>
16
17#if defined(CONFIG_EDAC)
18#include <linux/edac.h>
19#endif
20
21#include <linux/atomic.h>
22#include <asm/traps.h>
23#include <asm/mach_traps.h>
24
25static int ignore_nmis;
26
27int unknown_nmi_panic;
28/*
29 * Prevent NMI reason port (0x61) being accessed simultaneously, can
30 * only be used in NMI handler.
31 */
32static DEFINE_RAW_SPINLOCK(nmi_reason_lock);
33
34static int __init setup_unknown_nmi_panic(char *str)
35{
36 unknown_nmi_panic = 1;
37 return 1;
38}
39__setup("unknown_nmi_panic", setup_unknown_nmi_panic);
40
41static notrace __kprobes void
42pci_serr_error(unsigned char reason, struct pt_regs *regs)
43{
44 pr_emerg("NMI: PCI system error (SERR) for reason %02x on CPU %d.\n",
45 reason, smp_processor_id());
46
47 /*
48 * On some machines, PCI SERR line is used to report memory
49 * errors. EDAC makes use of it.
50 */
51#if defined(CONFIG_EDAC)
52 if (edac_handler_set()) {
53 edac_atomic_assert_error();
54 return;
55 }
56#endif
57
58 if (panic_on_unrecovered_nmi)
59 panic("NMI: Not continuing");
60
61 pr_emerg("Dazed and confused, but trying to continue\n");
62
63 /* Clear and disable the PCI SERR error line. */
64 reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_SERR;
65 outb(reason, NMI_REASON_PORT);
66}
67
68static notrace __kprobes void
69io_check_error(unsigned char reason, struct pt_regs *regs)
70{
71 unsigned long i;
72
73 pr_emerg(
74 "NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n",
75 reason, smp_processor_id());
76 show_registers(regs);
77
78 if (panic_on_io_nmi)
79 panic("NMI IOCK error: Not continuing");
80
81 /* Re-enable the IOCK line, wait for a few seconds */
82 reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK;
83 outb(reason, NMI_REASON_PORT);
84
85 i = 20000;
86 while (--i) {
87 touch_nmi_watchdog();
88 udelay(100);
89 }
90
91 reason &= ~NMI_REASON_CLEAR_IOCHK;
92 outb(reason, NMI_REASON_PORT);
93}
94
95static notrace __kprobes void
96unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
97{
98 if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
99 NOTIFY_STOP)
100 return;
101#ifdef CONFIG_MCA
102 /*
103 * Might actually be able to figure out what the guilty party
104 * is:
105 */
106 if (MCA_bus) {
107 mca_handle_nmi();
108 return;
109 }
110#endif
111 pr_emerg("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
112 reason, smp_processor_id());
113
114 pr_emerg("Do you have a strange power saving mode enabled?\n");
115 if (unknown_nmi_panic || panic_on_unrecovered_nmi)
116 panic("NMI: Not continuing");
117
118 pr_emerg("Dazed and confused, but trying to continue\n");
119}
120
121static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
122{
123 unsigned char reason = 0;
124
125 /*
126 * CPU-specific NMI must be processed before non-CPU-specific
127 * NMI, otherwise we may lose it, because the CPU-specific
128 * NMI can not be detected/processed on other CPUs.
129 */
130 if (notify_die(DIE_NMI, "nmi", regs, 0, 2, SIGINT) == NOTIFY_STOP)
131 return;
132
133 /* Non-CPU-specific NMI: NMI sources can be processed on any CPU */
134 raw_spin_lock(&nmi_reason_lock);
135 reason = get_nmi_reason();
136
137 if (reason & NMI_REASON_MASK) {
138 if (reason & NMI_REASON_SERR)
139 pci_serr_error(reason, regs);
140 else if (reason & NMI_REASON_IOCHK)
141 io_check_error(reason, regs);
142#ifdef CONFIG_X86_32
143 /*
144 * Reassert NMI in case it became active
145 * meanwhile as it's edge-triggered:
146 */
147 reassert_nmi();
148#endif
149 raw_spin_unlock(&nmi_reason_lock);
150 return;
151 }
152 raw_spin_unlock(&nmi_reason_lock);
153
154 unknown_nmi_error(reason, regs);
155}
156
157dotraplinkage notrace __kprobes void
158do_nmi(struct pt_regs *regs, long error_code)
159{
160 nmi_enter();
161
162 inc_irq_stat(__nmi_count);
163
164 if (!ignore_nmis)
165 default_do_nmi(regs);
166
167 nmi_exit();
168}
169
170void stop_nmi(void)
171{
172 ignore_nmis++;
173}
174
175void restart_nmi(void)
176{
177 ignore_nmis--;
178}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 6913369c234..a8e3eb83466 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -81,15 +81,6 @@ gate_desc idt_table[NR_VECTORS] __page_aligned_data = { { { { 0, 0 } } }, };
81DECLARE_BITMAP(used_vectors, NR_VECTORS); 81DECLARE_BITMAP(used_vectors, NR_VECTORS);
82EXPORT_SYMBOL_GPL(used_vectors); 82EXPORT_SYMBOL_GPL(used_vectors);
83 83
84static int ignore_nmis;
85
86int unknown_nmi_panic;
87/*
88 * Prevent NMI reason port (0x61) being accessed simultaneously, can
89 * only be used in NMI handler.
90 */
91static DEFINE_RAW_SPINLOCK(nmi_reason_lock);
92
93static inline void conditional_sti(struct pt_regs *regs) 84static inline void conditional_sti(struct pt_regs *regs)
94{ 85{
95 if (regs->flags & X86_EFLAGS_IF) 86 if (regs->flags & X86_EFLAGS_IF)
@@ -307,152 +298,6 @@ gp_in_kernel:
307 die("general protection fault", regs, error_code); 298 die("general protection fault", regs, error_code);
308} 299}
309 300
310static int __init setup_unknown_nmi_panic(char *str)
311{
312 unknown_nmi_panic = 1;
313 return 1;
314}
315__setup("unknown_nmi_panic", setup_unknown_nmi_panic);
316
317static notrace __kprobes void
318pci_serr_error(unsigned char reason, struct pt_regs *regs)
319{
320 pr_emerg("NMI: PCI system error (SERR) for reason %02x on CPU %d.\n",
321 reason, smp_processor_id());
322
323 /*
324 * On some machines, PCI SERR line is used to report memory
325 * errors. EDAC makes use of it.
326 */
327#if defined(CONFIG_EDAC)
328 if (edac_handler_set()) {
329 edac_atomic_assert_error();
330 return;
331 }
332#endif
333
334 if (panic_on_unrecovered_nmi)
335 panic("NMI: Not continuing");
336
337 pr_emerg("Dazed and confused, but trying to continue\n");
338
339 /* Clear and disable the PCI SERR error line. */
340 reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_SERR;
341 outb(reason, NMI_REASON_PORT);
342}
343
344static notrace __kprobes void
345io_check_error(unsigned char reason, struct pt_regs *regs)
346{
347 unsigned long i;
348
349 pr_emerg(
350 "NMI: IOCK error (debug interrupt?) for reason %02x on CPU %d.\n",
351 reason, smp_processor_id());
352 show_registers(regs);
353
354 if (panic_on_io_nmi)
355 panic("NMI IOCK error: Not continuing");
356
357 /* Re-enable the IOCK line, wait for a few seconds */
358 reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK;
359 outb(reason, NMI_REASON_PORT);
360
361 i = 20000;
362 while (--i) {
363 touch_nmi_watchdog();
364 udelay(100);
365 }
366
367 reason &= ~NMI_REASON_CLEAR_IOCHK;
368 outb(reason, NMI_REASON_PORT);
369}
370
371static notrace __kprobes void
372unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
373{
374 if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) ==
375 NOTIFY_STOP)
376 return;
377#ifdef CONFIG_MCA
378 /*
379 * Might actually be able to figure out what the guilty party
380 * is:
381 */
382 if (MCA_bus) {
383 mca_handle_nmi();
384 return;
385 }
386#endif
387 pr_emerg("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n",
388 reason, smp_processor_id());
389
390 pr_emerg("Do you have a strange power saving mode enabled?\n");
391 if (unknown_nmi_panic || panic_on_unrecovered_nmi)
392 panic("NMI: Not continuing");
393
394 pr_emerg("Dazed and confused, but trying to continue\n");
395}
396
397static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
398{
399 unsigned char reason = 0;
400
401 /*
402 * CPU-specific NMI must be processed before non-CPU-specific
403 * NMI, otherwise we may lose it, because the CPU-specific
404 * NMI can not be detected/processed on other CPUs.
405 */
406 if (notify_die(DIE_NMI, "nmi", regs, 0, 2, SIGINT) == NOTIFY_STOP)
407 return;
408
409 /* Non-CPU-specific NMI: NMI sources can be processed on any CPU */
410 raw_spin_lock(&nmi_reason_lock);
411 reason = get_nmi_reason();
412
413 if (reason & NMI_REASON_MASK) {
414 if (reason & NMI_REASON_SERR)
415 pci_serr_error(reason, regs);
416 else if (reason & NMI_REASON_IOCHK)
417 io_check_error(reason, regs);
418#ifdef CONFIG_X86_32
419 /*
420 * Reassert NMI in case it became active
421 * meanwhile as it's edge-triggered:
422 */
423 reassert_nmi();
424#endif
425 raw_spin_unlock(&nmi_reason_lock);
426 return;
427 }
428 raw_spin_unlock(&nmi_reason_lock);
429
430 unknown_nmi_error(reason, regs);
431}
432
433dotraplinkage notrace __kprobes void
434do_nmi(struct pt_regs *regs, long error_code)
435{
436 nmi_enter();
437
438 inc_irq_stat(__nmi_count);
439
440 if (!ignore_nmis)
441 default_do_nmi(regs);
442
443 nmi_exit();
444}
445
446void stop_nmi(void)
447{
448 ignore_nmis++;
449}
450
451void restart_nmi(void)
452{
453 ignore_nmis--;
454}
455
456/* May run on IST stack. */ 301/* May run on IST stack. */
457dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) 302dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code)
458{ 303{