diff options
-rw-r--r-- | arch/i386/kernel/alternative.c | 15 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/mcheck/mce.c | 14 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 17 | ||||
-rw-r--r-- | arch/x86_64/kernel/mce.c | 14 | ||||
-rw-r--r-- | arch/x86_64/kernel/nmi.c | 17 | ||||
-rw-r--r-- | include/asm-i386/mce.h | 4 | ||||
-rw-r--r-- | include/asm-i386/nmi.h | 2 | ||||
-rw-r--r-- | include/asm-x86_64/mce.h | 3 | ||||
-rw-r--r-- | include/asm-x86_64/nmi.h | 2 |
9 files changed, 86 insertions, 2 deletions
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c index 206ea2ca63cc..c3750c2c4113 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <asm/alternative.h> | 8 | #include <asm/alternative.h> |
9 | #include <asm/sections.h> | 9 | #include <asm/sections.h> |
10 | #include <asm/pgtable.h> | 10 | #include <asm/pgtable.h> |
11 | #include <asm/mce.h> | ||
12 | #include <asm/nmi.h> | ||
11 | 13 | ||
12 | #ifdef CONFIG_HOTPLUG_CPU | 14 | #ifdef CONFIG_HOTPLUG_CPU |
13 | static int smp_alt_once; | 15 | static int smp_alt_once; |
@@ -373,6 +375,14 @@ void __init alternative_instructions(void) | |||
373 | { | 375 | { |
374 | unsigned long flags; | 376 | unsigned long flags; |
375 | 377 | ||
378 | /* The patching is not fully atomic, so try to avoid local interruptions | ||
379 | that might execute the to be patched code. | ||
380 | Other CPUs are not running. */ | ||
381 | stop_nmi(); | ||
382 | #ifdef CONFIG_MCE | ||
383 | stop_mce(); | ||
384 | #endif | ||
385 | |||
376 | local_irq_save(flags); | 386 | local_irq_save(flags); |
377 | apply_alternatives(__alt_instructions, __alt_instructions_end); | 387 | apply_alternatives(__alt_instructions, __alt_instructions_end); |
378 | 388 | ||
@@ -405,6 +415,11 @@ void __init alternative_instructions(void) | |||
405 | #endif | 415 | #endif |
406 | apply_paravirt(__parainstructions, __parainstructions_end); | 416 | apply_paravirt(__parainstructions, __parainstructions_end); |
407 | local_irq_restore(flags); | 417 | local_irq_restore(flags); |
418 | |||
419 | restart_nmi(); | ||
420 | #ifdef CONFIG_MCE | ||
421 | restart_mce(); | ||
422 | #endif | ||
408 | } | 423 | } |
409 | 424 | ||
410 | /* | 425 | /* |
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c index 56cd485b127c..34c781eddee4 100644 --- a/arch/i386/kernel/cpu/mcheck/mce.c +++ b/arch/i386/kernel/cpu/mcheck/mce.c | |||
@@ -60,6 +60,20 @@ void mcheck_init(struct cpuinfo_x86 *c) | |||
60 | } | 60 | } |
61 | } | 61 | } |
62 | 62 | ||
63 | static unsigned long old_cr4 __initdata; | ||
64 | |||
65 | void __init stop_mce(void) | ||
66 | { | ||
67 | old_cr4 = read_cr4(); | ||
68 | clear_in_cr4(X86_CR4_MCE); | ||
69 | } | ||
70 | |||
71 | void __init restart_mce(void) | ||
72 | { | ||
73 | if (old_cr4 & X86_CR4_MCE) | ||
74 | set_in_cr4(X86_CR4_MCE); | ||
75 | } | ||
76 | |||
63 | static int __init mcheck_disable(char *str) | 77 | static int __init mcheck_disable(char *str) |
64 | { | 78 | { |
65 | mce_disabled = 1; | 79 | mce_disabled = 1; |
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 438949da3b63..cfffe3dd9e83 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -775,6 +775,8 @@ static __kprobes void default_do_nmi(struct pt_regs * regs) | |||
775 | reassert_nmi(); | 775 | reassert_nmi(); |
776 | } | 776 | } |
777 | 777 | ||
778 | static int ignore_nmis; | ||
779 | |||
778 | fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) | 780 | fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) |
779 | { | 781 | { |
780 | int cpu; | 782 | int cpu; |
@@ -785,11 +787,24 @@ fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) | |||
785 | 787 | ||
786 | ++nmi_count(cpu); | 788 | ++nmi_count(cpu); |
787 | 789 | ||
788 | default_do_nmi(regs); | 790 | if (!ignore_nmis) |
791 | default_do_nmi(regs); | ||
789 | 792 | ||
790 | nmi_exit(); | 793 | nmi_exit(); |
791 | } | 794 | } |
792 | 795 | ||
796 | void stop_nmi(void) | ||
797 | { | ||
798 | acpi_nmi_disable(); | ||
799 | ignore_nmis++; | ||
800 | } | ||
801 | |||
802 | void restart_nmi(void) | ||
803 | { | ||
804 | ignore_nmis--; | ||
805 | acpi_nmi_enable(); | ||
806 | } | ||
807 | |||
793 | #ifdef CONFIG_KPROBES | 808 | #ifdef CONFIG_KPROBES |
794 | fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) | 809 | fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) |
795 | { | 810 | { |
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 4d8450ee3635..a66d607f5b92 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c | |||
@@ -667,6 +667,20 @@ static struct miscdevice mce_log_device = { | |||
667 | &mce_chrdev_ops, | 667 | &mce_chrdev_ops, |
668 | }; | 668 | }; |
669 | 669 | ||
670 | static unsigned long old_cr4 __initdata; | ||
671 | |||
672 | void __init stop_mce(void) | ||
673 | { | ||
674 | old_cr4 = read_cr4(); | ||
675 | clear_in_cr4(X86_CR4_MCE); | ||
676 | } | ||
677 | |||
678 | void __init restart_mce(void) | ||
679 | { | ||
680 | if (old_cr4 & X86_CR4_MCE) | ||
681 | set_in_cr4(X86_CR4_MCE); | ||
682 | } | ||
683 | |||
670 | /* | 684 | /* |
671 | * Old style boot options parsing. Only for compatibility. | 685 | * Old style boot options parsing. Only for compatibility. |
672 | */ | 686 | */ |
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index edbbc59b7523..cb8ee9d02f86 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c | |||
@@ -384,11 +384,14 @@ int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |||
384 | return rc; | 384 | return rc; |
385 | } | 385 | } |
386 | 386 | ||
387 | static unsigned ignore_nmis; | ||
388 | |||
387 | asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) | 389 | asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) |
388 | { | 390 | { |
389 | nmi_enter(); | 391 | nmi_enter(); |
390 | add_pda(__nmi_count,1); | 392 | add_pda(__nmi_count,1); |
391 | default_do_nmi(regs); | 393 | if (!ignore_nmis) |
394 | default_do_nmi(regs); | ||
392 | nmi_exit(); | 395 | nmi_exit(); |
393 | } | 396 | } |
394 | 397 | ||
@@ -401,6 +404,18 @@ int do_nmi_callback(struct pt_regs * regs, int cpu) | |||
401 | return 0; | 404 | return 0; |
402 | } | 405 | } |
403 | 406 | ||
407 | void stop_nmi(void) | ||
408 | { | ||
409 | acpi_nmi_disable(); | ||
410 | ignore_nmis++; | ||
411 | } | ||
412 | |||
413 | void restart_nmi(void) | ||
414 | { | ||
415 | ignore_nmis--; | ||
416 | acpi_nmi_enable(); | ||
417 | } | ||
418 | |||
404 | #ifdef CONFIG_SYSCTL | 419 | #ifdef CONFIG_SYSCTL |
405 | 420 | ||
406 | static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) | 421 | static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) |
diff --git a/include/asm-i386/mce.h b/include/asm-i386/mce.h index b0a02ee34ffd..d56d89742e8f 100644 --- a/include/asm-i386/mce.h +++ b/include/asm-i386/mce.h | |||
@@ -5,3 +5,7 @@ extern void mcheck_init(struct cpuinfo_x86 *c); | |||
5 | #endif | 5 | #endif |
6 | 6 | ||
7 | extern int mce_disabled; | 7 | extern int mce_disabled; |
8 | |||
9 | extern void stop_mce(void); | ||
10 | extern void restart_mce(void); | ||
11 | |||
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h index fb1e133efd9f..ff30c98f87b0 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h | |||
@@ -57,5 +57,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz); | |||
57 | int lapic_watchdog_ok(void); | 57 | int lapic_watchdog_ok(void); |
58 | void disable_lapic_nmi_watchdog(void); | 58 | void disable_lapic_nmi_watchdog(void); |
59 | void enable_lapic_nmi_watchdog(void); | 59 | void enable_lapic_nmi_watchdog(void); |
60 | void stop_nmi(void); | ||
61 | void restart_nmi(void); | ||
60 | 62 | ||
61 | #endif /* ASM_NMI_H */ | 63 | #endif /* ASM_NMI_H */ |
diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h index 556be5563e30..7bc030a1996d 100644 --- a/include/asm-x86_64/mce.h +++ b/include/asm-x86_64/mce.h | |||
@@ -107,6 +107,9 @@ extern void do_machine_check(struct pt_regs *, long); | |||
107 | 107 | ||
108 | extern int mce_notify_user(void); | 108 | extern int mce_notify_user(void); |
109 | 109 | ||
110 | extern void stop_mce(void); | ||
111 | extern void restart_mce(void); | ||
112 | |||
110 | #endif | 113 | #endif |
111 | 114 | ||
112 | #endif | 115 | #endif |
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index d0a7f53b1497..5fb3c0de5ccc 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h | |||
@@ -88,5 +88,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz); | |||
88 | int lapic_watchdog_ok(void); | 88 | int lapic_watchdog_ok(void); |
89 | void disable_lapic_nmi_watchdog(void); | 89 | void disable_lapic_nmi_watchdog(void); |
90 | void enable_lapic_nmi_watchdog(void); | 90 | void enable_lapic_nmi_watchdog(void); |
91 | void stop_nmi(void); | ||
92 | void restart_nmi(void); | ||
91 | 93 | ||
92 | #endif /* ASM_NMI_H */ | 94 | #endif /* ASM_NMI_H */ |