aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/crash.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/crash.c')
-rw-r--r--arch/x86/kernel/crash.c86
1 files changed, 25 insertions, 61 deletions
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 268553817909..c689d19e35ab 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -26,37 +26,21 @@
26#include <linux/kdebug.h> 26#include <linux/kdebug.h>
27#include <asm/smp.h> 27#include <asm/smp.h>
28#include <asm/reboot.h> 28#include <asm/reboot.h>
29#include <asm/virtext.h>
29 30
30#include <mach_ipi.h> 31#include <mach_ipi.h>
31 32
32/* This keeps a track of which one is crashing cpu. */
33static int crashing_cpu;
34 33
35#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC) 34#if defined(CONFIG_SMP) && defined(CONFIG_X86_LOCAL_APIC)
36static atomic_t waiting_for_crash_ipi;
37 35
38static int crash_nmi_callback(struct notifier_block *self, 36static void kdump_nmi_callback(int cpu, struct die_args *args)
39 unsigned long val, void *data)
40{ 37{
41 struct pt_regs *regs; 38 struct pt_regs *regs;
42#ifdef CONFIG_X86_32 39#ifdef CONFIG_X86_32
43 struct pt_regs fixed_regs; 40 struct pt_regs fixed_regs;
44#endif 41#endif
45 int cpu;
46 42
47 if (val != DIE_NMI_IPI) 43 regs = args->regs;
48 return NOTIFY_OK;
49
50 regs = ((struct die_args *)data)->regs;
51 cpu = raw_smp_processor_id();
52
53 /* Don't do anything if this handler is invoked on crashing cpu.
54 * Otherwise, system will completely hang. Crashing cpu can get
55 * an NMI if system was initially booted with nmi_watchdog parameter.
56 */
57 if (cpu == crashing_cpu)
58 return NOTIFY_STOP;
59 local_irq_disable();
60 44
61#ifdef CONFIG_X86_32 45#ifdef CONFIG_X86_32
62 if (!user_mode_vm(regs)) { 46 if (!user_mode_vm(regs)) {
@@ -65,54 +49,28 @@ static int crash_nmi_callback(struct notifier_block *self,
65 } 49 }
66#endif 50#endif
67 crash_save_cpu(regs, cpu); 51 crash_save_cpu(regs, cpu);
68 disable_local_APIC();
69 atomic_dec(&waiting_for_crash_ipi);
70 /* Assume hlt works */
71 halt();
72 for (;;)
73 cpu_relax();
74 52
75 return 1; 53 /* Disable VMX or SVM if needed.
76} 54 *
55 * We need to disable virtualization on all CPUs.
56 * Having VMX or SVM enabled on any CPU may break rebooting
57 * after the kdump kernel has finished its task.
58 */
59 cpu_emergency_vmxoff();
60 cpu_emergency_svm_disable();
77 61
78static void smp_send_nmi_allbutself(void) 62 disable_local_APIC();
79{
80 cpumask_t mask = cpu_online_map;
81 cpu_clear(safe_smp_processor_id(), mask);
82 if (!cpus_empty(mask))
83 send_IPI_mask(mask, NMI_VECTOR);
84} 63}
85 64
86static struct notifier_block crash_nmi_nb = { 65static void kdump_nmi_shootdown_cpus(void)
87 .notifier_call = crash_nmi_callback,
88};
89
90static void nmi_shootdown_cpus(void)
91{ 66{
92 unsigned long msecs; 67 nmi_shootdown_cpus(kdump_nmi_callback);
93
94 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
95 /* Would it be better to replace the trap vector here? */
96 if (register_die_notifier(&crash_nmi_nb))
97 return; /* return what? */
98 /* Ensure the new callback function is set before sending
99 * out the NMI
100 */
101 wmb();
102
103 smp_send_nmi_allbutself();
104
105 msecs = 1000; /* Wait at most a second for the other cpus to stop */
106 while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
107 mdelay(1);
108 msecs--;
109 }
110 68
111 /* Leave the nmi callback set */
112 disable_local_APIC(); 69 disable_local_APIC();
113} 70}
71
114#else 72#else
115static void nmi_shootdown_cpus(void) 73static void kdump_nmi_shootdown_cpus(void)
116{ 74{
117 /* There are no cpus to shootdown */ 75 /* There are no cpus to shootdown */
118} 76}
@@ -131,9 +89,15 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
131 /* The kernel is broken so disable interrupts */ 89 /* The kernel is broken so disable interrupts */
132 local_irq_disable(); 90 local_irq_disable();
133 91
134 /* Make a note of crashing cpu. Will be used in NMI callback.*/ 92 kdump_nmi_shootdown_cpus();
135 crashing_cpu = safe_smp_processor_id(); 93
136 nmi_shootdown_cpus(); 94 /* Booting kdump kernel with VMX or SVM enabled won't work,
95 * because (among other limitations) we can't disable paging
96 * with the virt flags.
97 */
98 cpu_emergency_vmxoff();
99 cpu_emergency_svm_disable();
100
137 lapic_shutdown(); 101 lapic_shutdown();
138#if defined(CONFIG_X86_IO_APIC) 102#if defined(CONFIG_X86_IO_APIC)
139 disable_IO_APIC(); 103 disable_IO_APIC();