aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/traps.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:59:11 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-07 11:59:11 -0500
commit4522d58275f124105819723e24e912c8e5bf3cdd (patch)
treeb92c29014fadffe049c1925676037f0092b8d112 /arch/i386/kernel/traps.c
parent6cf24f031bc97cb5a7c9df3b6e73c45b628b2b28 (diff)
parent64a26a731235b59c9d73bbe82c1f896d57400d37 (diff)
Merge branch 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6
* 'for-linus' of git://one.firstfloor.org/home/andi/git/linux-2.6: (156 commits) [PATCH] x86-64: Export smp_call_function_single [PATCH] i386: Clean up smp_tune_scheduling() [PATCH] unwinder: move .eh_frame to RODATA [PATCH] unwinder: fully support linker generated .eh_frame_hdr section [PATCH] x86-64: don't use set_irq_regs() [PATCH] x86-64: check vector in setup_ioapic_dest to verify if need setup_IO_APIC_irq [PATCH] x86-64: Make ix86 default to HIGHMEM4G instead of NOHIGHMEM [PATCH] i386: replace kmalloc+memset with kzalloc [PATCH] x86-64: remove remaining pc98 code [PATCH] x86-64: remove unused variable [PATCH] x86-64: Fix constraints in atomic_add_return() [PATCH] x86-64: fix asm constraints in i386 atomic_add_return [PATCH] x86-64: Correct documentation for bzImage protocol v2.05 [PATCH] x86-64: replace kmalloc+memset with kzalloc in MTRR code [PATCH] x86-64: Fix numaq build error [PATCH] x86-64: include/asm-x86_64/cpufeature.h isn't a userspace header [PATCH] unwinder: Add debugging output to the Dwarf2 unwinder [PATCH] x86-64: Clarify error message in GART code [PATCH] x86-64: Fix interrupt race in idle callback (3rd try) [PATCH] x86-64: Remove unwind stack pointer alignment forcing again ... Fixed conflict in include/linux/uaccess.h manually Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/traps.c')
-rw-r--r--arch/i386/kernel/traps.c118
1 files changed, 52 insertions, 66 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 3124f1b04d67..68de48e498ca 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -29,6 +29,7 @@
29#include <linux/kexec.h> 29#include <linux/kexec.h>
30#include <linux/unwind.h> 30#include <linux/unwind.h>
31#include <linux/uaccess.h> 31#include <linux/uaccess.h>
32#include <linux/nmi.h>
32 33
33#ifdef CONFIG_EISA 34#ifdef CONFIG_EISA
34#include <linux/ioport.h> 35#include <linux/ioport.h>
@@ -61,9 +62,6 @@ int panic_on_unrecovered_nmi;
61 62
62asmlinkage int system_call(void); 63asmlinkage int system_call(void);
63 64
64struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
65 { 0, 0 }, { 0, 0 } };
66
67/* Do we ignore FPU interrupts ? */ 65/* Do we ignore FPU interrupts ? */
68char ignore_fpu_irq = 0; 66char ignore_fpu_irq = 0;
69 67
@@ -94,7 +92,7 @@ asmlinkage void alignment_check(void);
94asmlinkage void spurious_interrupt_bug(void); 92asmlinkage void spurious_interrupt_bug(void);
95asmlinkage void machine_check(void); 93asmlinkage void machine_check(void);
96 94
97static int kstack_depth_to_print = 24; 95int kstack_depth_to_print = 24;
98#ifdef CONFIG_STACK_UNWIND 96#ifdef CONFIG_STACK_UNWIND
99static int call_trace = 1; 97static int call_trace = 1;
100#else 98#else
@@ -163,16 +161,25 @@ dump_trace_unwind(struct unwind_frame_info *info, void *data)
163{ 161{
164 struct ops_and_data *oad = (struct ops_and_data *)data; 162 struct ops_and_data *oad = (struct ops_and_data *)data;
165 int n = 0; 163 int n = 0;
164 unsigned long sp = UNW_SP(info);
166 165
166 if (arch_unw_user_mode(info))
167 return -1;
167 while (unwind(info) == 0 && UNW_PC(info)) { 168 while (unwind(info) == 0 && UNW_PC(info)) {
168 n++; 169 n++;
169 oad->ops->address(oad->data, UNW_PC(info)); 170 oad->ops->address(oad->data, UNW_PC(info));
170 if (arch_unw_user_mode(info)) 171 if (arch_unw_user_mode(info))
171 break; 172 break;
173 if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
174 && sp > UNW_SP(info))
175 break;
176 sp = UNW_SP(info);
172 } 177 }
173 return n; 178 return n;
174} 179}
175 180
181#define MSG(msg) ops->warning(data, msg)
182
176void dump_trace(struct task_struct *task, struct pt_regs *regs, 183void dump_trace(struct task_struct *task, struct pt_regs *regs,
177 unsigned long *stack, 184 unsigned long *stack,
178 struct stacktrace_ops *ops, void *data) 185 struct stacktrace_ops *ops, void *data)
@@ -191,29 +198,31 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
191 if (unwind_init_frame_info(&info, task, regs) == 0) 198 if (unwind_init_frame_info(&info, task, regs) == 0)
192 unw_ret = dump_trace_unwind(&info, &oad); 199 unw_ret = dump_trace_unwind(&info, &oad);
193 } else if (task == current) 200 } else if (task == current)
194 unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); 201 unw_ret = unwind_init_running(&info, dump_trace_unwind,
202 &oad);
195 else { 203 else {
196 if (unwind_init_blocked(&info, task) == 0) 204 if (unwind_init_blocked(&info, task) == 0)
197 unw_ret = dump_trace_unwind(&info, &oad); 205 unw_ret = dump_trace_unwind(&info, &oad);
198 } 206 }
199 if (unw_ret > 0) { 207 if (unw_ret > 0) {
200 if (call_trace == 1 && !arch_unw_user_mode(&info)) { 208 if (call_trace == 1 && !arch_unw_user_mode(&info)) {
201 ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", 209 ops->warning_symbol(data,
210 "DWARF2 unwinder stuck at %s",
202 UNW_PC(&info)); 211 UNW_PC(&info));
203 if (UNW_SP(&info) >= PAGE_OFFSET) { 212 if (UNW_SP(&info) >= PAGE_OFFSET) {
204 ops->warning(data, "Leftover inexact backtrace:\n"); 213 MSG("Leftover inexact backtrace:");
205 stack = (void *)UNW_SP(&info); 214 stack = (void *)UNW_SP(&info);
206 if (!stack) 215 if (!stack)
207 return; 216 return;
208 ebp = UNW_FP(&info); 217 ebp = UNW_FP(&info);
209 } else 218 } else
210 ops->warning(data, "Full inexact backtrace again:\n"); 219 MSG("Full inexact backtrace again:");
211 } else if (call_trace >= 1) 220 } else if (call_trace >= 1)
212 return; 221 return;
213 else 222 else
214 ops->warning(data, "Full inexact backtrace again:\n"); 223 MSG("Full inexact backtrace again:");
215 } else 224 } else
216 ops->warning(data, "Inexact backtrace:\n"); 225 MSG("Inexact backtrace:");
217 } 226 }
218 if (!stack) { 227 if (!stack) {
219 unsigned long dummy; 228 unsigned long dummy;
@@ -247,6 +256,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
247 stack = (unsigned long*)context->previous_esp; 256 stack = (unsigned long*)context->previous_esp;
248 if (!stack) 257 if (!stack)
249 break; 258 break;
259 touch_nmi_watchdog();
250 } 260 }
251} 261}
252EXPORT_SYMBOL(dump_trace); 262EXPORT_SYMBOL(dump_trace);
@@ -379,7 +389,7 @@ void show_registers(struct pt_regs *regs)
379 * time of the fault.. 389 * time of the fault..
380 */ 390 */
381 if (in_kernel) { 391 if (in_kernel) {
382 u8 __user *eip; 392 u8 *eip;
383 int code_bytes = 64; 393 int code_bytes = 64;
384 unsigned char c; 394 unsigned char c;
385 395
@@ -388,18 +398,20 @@ void show_registers(struct pt_regs *regs)
388 398
389 printk(KERN_EMERG "Code: "); 399 printk(KERN_EMERG "Code: ");
390 400
391 eip = (u8 __user *)regs->eip - 43; 401 eip = (u8 *)regs->eip - 43;
392 if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { 402 if (eip < (u8 *)PAGE_OFFSET ||
403 probe_kernel_address(eip, c)) {
393 /* try starting at EIP */ 404 /* try starting at EIP */
394 eip = (u8 __user *)regs->eip; 405 eip = (u8 *)regs->eip;
395 code_bytes = 32; 406 code_bytes = 32;
396 } 407 }
397 for (i = 0; i < code_bytes; i++, eip++) { 408 for (i = 0; i < code_bytes; i++, eip++) {
398 if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { 409 if (eip < (u8 *)PAGE_OFFSET ||
410 probe_kernel_address(eip, c)) {
399 printk(" Bad EIP value."); 411 printk(" Bad EIP value.");
400 break; 412 break;
401 } 413 }
402 if (eip == (u8 __user *)regs->eip) 414 if (eip == (u8 *)regs->eip)
403 printk("<%02x> ", c); 415 printk("<%02x> ", c);
404 else 416 else
405 printk("%02x ", c); 417 printk("%02x ", c);
@@ -415,7 +427,7 @@ static void handle_BUG(struct pt_regs *regs)
415 427
416 if (eip < PAGE_OFFSET) 428 if (eip < PAGE_OFFSET)
417 return; 429 return;
418 if (probe_kernel_address((unsigned short __user *)eip, ud2)) 430 if (probe_kernel_address((unsigned short *)eip, ud2))
419 return; 431 return;
420 if (ud2 != 0x0b0f) 432 if (ud2 != 0x0b0f)
421 return; 433 return;
@@ -428,11 +440,11 @@ static void handle_BUG(struct pt_regs *regs)
428 char *file; 440 char *file;
429 char c; 441 char c;
430 442
431 if (probe_kernel_address((unsigned short __user *)(eip + 2), 443 if (probe_kernel_address((unsigned short *)(eip + 2), line))
432 line))
433 break; 444 break;
434 if (__get_user(file, (char * __user *)(eip + 4)) || 445 if (probe_kernel_address((char **)(eip + 4), file) ||
435 (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) 446 (unsigned long)file < PAGE_OFFSET ||
447 probe_kernel_address(file, c))
436 file = "<bad filename>"; 448 file = "<bad filename>";
437 449
438 printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); 450 printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
@@ -707,8 +719,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
707{ 719{
708 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " 720 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
709 "CPU %d.\n", reason, smp_processor_id()); 721 "CPU %d.\n", reason, smp_processor_id());
710 printk(KERN_EMERG "You probably have a hardware problem with your RAM " 722 printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
711 "chips\n");
712 if (panic_on_unrecovered_nmi) 723 if (panic_on_unrecovered_nmi)
713 panic("NMI: Not continuing"); 724 panic("NMI: Not continuing");
714 725
@@ -773,7 +784,6 @@ void __kprobes die_nmi(struct pt_regs *regs, const char *msg)
773 printk(" on CPU%d, eip %08lx, registers:\n", 784 printk(" on CPU%d, eip %08lx, registers:\n",
774 smp_processor_id(), regs->eip); 785 smp_processor_id(), regs->eip);
775 show_registers(regs); 786 show_registers(regs);
776 printk(KERN_EMERG "console shuts up ...\n");
777 console_silent(); 787 console_silent();
778 spin_unlock(&nmi_print_lock); 788 spin_unlock(&nmi_print_lock);
779 bust_spinlocks(0); 789 bust_spinlocks(0);
@@ -1088,49 +1098,24 @@ fastcall void do_spurious_interrupt_bug(struct pt_regs * regs,
1088#endif 1098#endif
1089} 1099}
1090 1100
1091fastcall void setup_x86_bogus_stack(unsigned char * stk) 1101fastcall unsigned long patch_espfix_desc(unsigned long uesp,
1092{ 1102 unsigned long kesp)
1093 unsigned long *switch16_ptr, *switch32_ptr;
1094 struct pt_regs *regs;
1095 unsigned long stack_top, stack_bot;
1096 unsigned short iret_frame16_off;
1097 int cpu = smp_processor_id();
1098 /* reserve the space on 32bit stack for the magic switch16 pointer */
1099 memmove(stk, stk + 8, sizeof(struct pt_regs));
1100 switch16_ptr = (unsigned long *)(stk + sizeof(struct pt_regs));
1101 regs = (struct pt_regs *)stk;
1102 /* now the switch32 on 16bit stack */
1103 stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu);
1104 stack_top = stack_bot + CPU_16BIT_STACK_SIZE;
1105 switch32_ptr = (unsigned long *)(stack_top - 8);
1106 iret_frame16_off = CPU_16BIT_STACK_SIZE - 8 - 20;
1107 /* copy iret frame on 16bit stack */
1108 memcpy((void *)(stack_bot + iret_frame16_off), &regs->eip, 20);
1109 /* fill in the switch pointers */
1110 switch16_ptr[0] = (regs->esp & 0xffff0000) | iret_frame16_off;
1111 switch16_ptr[1] = __ESPFIX_SS;
1112 switch32_ptr[0] = (unsigned long)stk + sizeof(struct pt_regs) +
1113 8 - CPU_16BIT_STACK_SIZE;
1114 switch32_ptr[1] = __KERNEL_DS;
1115}
1116
1117fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp)
1118{ 1103{
1119 unsigned long *switch32_ptr;
1120 unsigned char *stack16, *stack32;
1121 unsigned long stack_top, stack_bot;
1122 int len;
1123 int cpu = smp_processor_id(); 1104 int cpu = smp_processor_id();
1124 stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu); 1105 struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
1125 stack_top = stack_bot + CPU_16BIT_STACK_SIZE; 1106 struct desc_struct *gdt = (struct desc_struct *)cpu_gdt_descr->address;
1126 switch32_ptr = (unsigned long *)(stack_top - 8); 1107 unsigned long base = (kesp - uesp) & -THREAD_SIZE;
1127 /* copy the data from 16bit stack to 32bit stack */ 1108 unsigned long new_kesp = kesp - base;
1128 len = CPU_16BIT_STACK_SIZE - 8 - sp; 1109 unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT;
1129 stack16 = (unsigned char *)(stack_bot + sp); 1110 __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS];
1130 stack32 = (unsigned char *) 1111 /* Set up base for espfix segment */
1131 (switch32_ptr[0] + CPU_16BIT_STACK_SIZE - 8 - len); 1112 desc &= 0x00f0ff0000000000ULL;
1132 memcpy(stack32, stack16, len); 1113 desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) |
1133 return stack32; 1114 ((((__u64)base) << 32) & 0xff00000000000000ULL) |
1115 ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) |
1116 (lim_pages & 0xffff);
1117 *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc;
1118 return new_kesp;
1134} 1119}
1135 1120
1136/* 1121/*
@@ -1143,7 +1128,7 @@ fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp)
1143 * Must be called with kernel preemption disabled (in this case, 1128 * Must be called with kernel preemption disabled (in this case,
1144 * local interrupts are disabled at the call-site in entry.S). 1129 * local interrupts are disabled at the call-site in entry.S).
1145 */ 1130 */
1146asmlinkage void math_state_restore(struct pt_regs regs) 1131asmlinkage void math_state_restore(void)
1147{ 1132{
1148 struct thread_info *thread = current_thread_info(); 1133 struct thread_info *thread = current_thread_info();
1149 struct task_struct *tsk = thread->task; 1134 struct task_struct *tsk = thread->task;
@@ -1153,6 +1138,7 @@ asmlinkage void math_state_restore(struct pt_regs regs)
1153 init_fpu(tsk); 1138 init_fpu(tsk);
1154 restore_fpu(tsk); 1139 restore_fpu(tsk);
1155 thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ 1140 thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */
1141 tsk->fpu_counter++;
1156} 1142}
1157 1143
1158#ifndef CONFIG_MATH_EMULATION 1144#ifndef CONFIG_MATH_EMULATION