diff options
Diffstat (limited to 'arch/i386/kernel/crash.c')
-rw-r--r-- | arch/i386/kernel/crash.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c index a021681d21f8..8bdb4b6af0ff 100644 --- a/arch/i386/kernel/crash.c +++ b/arch/i386/kernel/crash.c | |||
@@ -100,12 +100,31 @@ static void crash_get_current_regs(struct pt_regs *regs) | |||
100 | regs->eip = (unsigned long)current_text_addr(); | 100 | regs->eip = (unsigned long)current_text_addr(); |
101 | } | 101 | } |
102 | 102 | ||
103 | static void crash_save_self(void) | 103 | /* CPU does not save ss and esp on stack if execution is already |
104 | * running in kernel mode at the time of NMI occurrence. This code | ||
105 | * fixes it. | ||
106 | */ | ||
107 | static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs) | ||
108 | { | ||
109 | memcpy(newregs, oldregs, sizeof(*newregs)); | ||
110 | newregs->esp = (unsigned long)&(oldregs->esp); | ||
111 | __asm__ __volatile__("xorl %eax, %eax;"); | ||
112 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss)); | ||
113 | } | ||
114 | |||
115 | /* We may have saved_regs from where the error came from | ||
116 | * or it is NULL if via a direct panic(). | ||
117 | */ | ||
118 | static void crash_save_self(struct pt_regs *saved_regs) | ||
104 | { | 119 | { |
105 | struct pt_regs regs; | 120 | struct pt_regs regs; |
106 | int cpu; | 121 | int cpu; |
107 | cpu = smp_processor_id(); | 122 | cpu = smp_processor_id(); |
108 | crash_get_current_regs(®s); | 123 | |
124 | if (saved_regs) | ||
125 | crash_setup_regs(®s, saved_regs); | ||
126 | else | ||
127 | crash_get_current_regs(®s); | ||
109 | crash_save_this_cpu(®s, cpu); | 128 | crash_save_this_cpu(®s, cpu); |
110 | } | 129 | } |
111 | 130 | ||
@@ -124,15 +143,8 @@ static int crash_nmi_callback(struct pt_regs *regs, int cpu) | |||
124 | return 1; | 143 | return 1; |
125 | local_irq_disable(); | 144 | local_irq_disable(); |
126 | 145 | ||
127 | /* CPU does not save ss and esp on stack if execution is already | ||
128 | * running in kernel mode at the time of NMI occurrence. This code | ||
129 | * fixes it. | ||
130 | */ | ||
131 | if (!user_mode(regs)) { | 146 | if (!user_mode(regs)) { |
132 | memcpy(&fixed_regs, regs, sizeof(*regs)); | 147 | crash_setup_regs(&fixed_regs, regs); |
133 | fixed_regs.esp = (unsigned long)&(regs->esp); | ||
134 | __asm__ __volatile__("xorl %eax, %eax;"); | ||
135 | __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(fixed_regs.xss)); | ||
136 | regs = &fixed_regs; | 148 | regs = &fixed_regs; |
137 | } | 149 | } |
138 | crash_save_this_cpu(regs, cpu); | 150 | crash_save_this_cpu(regs, cpu); |
@@ -184,7 +196,7 @@ static void nmi_shootdown_cpus(void) | |||
184 | } | 196 | } |
185 | #endif | 197 | #endif |
186 | 198 | ||
187 | void machine_crash_shutdown(void) | 199 | void machine_crash_shutdown(struct pt_regs *regs) |
188 | { | 200 | { |
189 | /* This function is only called after the system | 201 | /* This function is only called after the system |
190 | * has paniced or is otherwise in a critical state. | 202 | * has paniced or is otherwise in a critical state. |
@@ -204,5 +216,5 @@ void machine_crash_shutdown(void) | |||
204 | #if defined(CONFIG_X86_IO_APIC) | 216 | #if defined(CONFIG_X86_IO_APIC) |
205 | disable_IO_APIC(); | 217 | disable_IO_APIC(); |
206 | #endif | 218 | #endif |
207 | crash_save_self(); | 219 | crash_save_self(regs); |
208 | } | 220 | } |