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 206ea2ca63c..c3750c2c411 100644 --- a/arch/i386/kernel/alternative.c +++ b/arch/i386/kernel/alternative.c @@ -8,6 +8,8 @@ #include <asm/alternative.h> #include <asm/sections.h> #include <asm/pgtable.h> +#include <asm/mce.h> +#include <asm/nmi.h> #ifdef CONFIG_HOTPLUG_CPU static int smp_alt_once; @@ -373,6 +375,14 @@ void __init alternative_instructions(void) { unsigned long flags; + /* The patching is not fully atomic, so try to avoid local interruptions + that might execute the to be patched code. + Other CPUs are not running. */ + stop_nmi(); +#ifdef CONFIG_MCE + stop_mce(); +#endif + local_irq_save(flags); apply_alternatives(__alt_instructions, __alt_instructions_end); @@ -405,6 +415,11 @@ void __init alternative_instructions(void) #endif apply_paravirt(__parainstructions, __parainstructions_end); local_irq_restore(flags); + + restart_nmi(); +#ifdef CONFIG_MCE + restart_mce(); +#endif } /* diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c index 56cd485b127..34c781eddee 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) } } +static unsigned long old_cr4 __initdata; + +void __init stop_mce(void) +{ + old_cr4 = read_cr4(); + clear_in_cr4(X86_CR4_MCE); +} + +void __init restart_mce(void) +{ + if (old_cr4 & X86_CR4_MCE) + set_in_cr4(X86_CR4_MCE); +} + static int __init mcheck_disable(char *str) { mce_disabled = 1; diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 438949da3b6..cfffe3dd9e8 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) reassert_nmi(); } +static int ignore_nmis; + fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) { int cpu; @@ -785,11 +787,24 @@ fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) ++nmi_count(cpu); - default_do_nmi(regs); + if (!ignore_nmis) + default_do_nmi(regs); nmi_exit(); } +void stop_nmi(void) +{ + acpi_nmi_disable(); + ignore_nmis++; +} + +void restart_nmi(void) +{ + ignore_nmis--; + acpi_nmi_enable(); +} + #ifdef CONFIG_KPROBES fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) { diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 4d8450ee363..a66d607f5b9 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 = { &mce_chrdev_ops, }; +static unsigned long old_cr4 __initdata; + +void __init stop_mce(void) +{ + old_cr4 = read_cr4(); + clear_in_cr4(X86_CR4_MCE); +} + +void __init restart_mce(void) +{ + if (old_cr4 & X86_CR4_MCE) + set_in_cr4(X86_CR4_MCE); +} + /* * Old style boot options parsing. Only for compatibility. */ diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index edbbc59b752..cb8ee9d02f8 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) return rc; } +static unsigned ignore_nmis; + asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) { nmi_enter(); add_pda(__nmi_count,1); - default_do_nmi(regs); + if (!ignore_nmis) + default_do_nmi(regs); nmi_exit(); } @@ -401,6 +404,18 @@ int do_nmi_callback(struct pt_regs * regs, int cpu) return 0; } +void stop_nmi(void) +{ + acpi_nmi_disable(); + ignore_nmis++; +} + +void restart_nmi(void) +{ + ignore_nmis--; + acpi_nmi_enable(); +} + #ifdef CONFIG_SYSCTL 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 b0a02ee34ff..d56d89742e8 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); #endif extern int mce_disabled; + +extern void stop_mce(void); +extern void restart_mce(void); + diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h index fb1e133efd9..ff30c98f87b 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h @@ -57,5 +57,7 @@ unsigned lapic_adjust_nmi_hz(unsigned hz); int lapic_watchdog_ok(void); void disable_lapic_nmi_watchdog(void); void enable_lapic_nmi_watchdog(void); +void stop_nmi(void); +void restart_nmi(void); #endif /* ASM_NMI_H */ diff --git a/include/asm-x86_64/mce.h b/include/asm-x86_64/mce.h index 556be5563e3..7bc030a1996 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); extern int mce_notify_user(void); +extern void stop_mce(void); +extern void restart_mce(void); + #endif #endif diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index d0a7f53b149..5fb3c0de5cc 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); int lapic_watchdog_ok(void); void disable_lapic_nmi_watchdog(void); void enable_lapic_nmi_watchdog(void); +void stop_nmi(void); +void restart_nmi(void); #endif /* ASM_NMI_H */ |