diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 05:17:01 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2007-10-11 05:17:01 -0400 |
commit | 9a163ed8e0552fdcffe405d2ea7134819a81456e (patch) | |
tree | b322fd2afbb812ba7ddfd22f3734aaab007c2aa5 /arch/x86/kernel/traps_32.c | |
parent | f7627e2513987bb5d4e8cb13c4e0a478352141ac (diff) |
i386: move kernel
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/traps_32.c')
-rw-r--r-- | arch/x86/kernel/traps_32.c | 1250 |
1 files changed, 1250 insertions, 0 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c new file mode 100644 index 000000000000..47b0bef335bd --- /dev/null +++ b/arch/x86/kernel/traps_32.c | |||
@@ -0,0 +1,1250 @@ | |||
1 | /* | ||
2 | * linux/arch/i386/traps.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * | ||
6 | * Pentium III FXSR, SSE support | ||
7 | * Gareth Hughes <gareth@valinux.com>, May 2000 | ||
8 | */ | ||
9 | |||
10 | /* | ||
11 | * 'Traps.c' handles hardware traps and faults after we have saved some | ||
12 | * state in 'asm.s'. | ||
13 | */ | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/mm.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/highmem.h> | ||
25 | #include <linux/kallsyms.h> | ||
26 | #include <linux/ptrace.h> | ||
27 | #include <linux/utsname.h> | ||
28 | #include <linux/kprobes.h> | ||
29 | #include <linux/kexec.h> | ||
30 | #include <linux/unwind.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | #include <linux/nmi.h> | ||
33 | #include <linux/bug.h> | ||
34 | |||
35 | #ifdef CONFIG_EISA | ||
36 | #include <linux/ioport.h> | ||
37 | #include <linux/eisa.h> | ||
38 | #endif | ||
39 | |||
40 | #ifdef CONFIG_MCA | ||
41 | #include <linux/mca.h> | ||
42 | #endif | ||
43 | |||
44 | #if defined(CONFIG_EDAC) | ||
45 | #include <linux/edac.h> | ||
46 | #endif | ||
47 | |||
48 | #include <asm/processor.h> | ||
49 | #include <asm/system.h> | ||
50 | #include <asm/io.h> | ||
51 | #include <asm/atomic.h> | ||
52 | #include <asm/debugreg.h> | ||
53 | #include <asm/desc.h> | ||
54 | #include <asm/i387.h> | ||
55 | #include <asm/nmi.h> | ||
56 | #include <asm/unwind.h> | ||
57 | #include <asm/smp.h> | ||
58 | #include <asm/arch_hooks.h> | ||
59 | #include <linux/kdebug.h> | ||
60 | #include <asm/stacktrace.h> | ||
61 | |||
62 | #include <linux/module.h> | ||
63 | |||
64 | #include "mach_traps.h" | ||
65 | |||
66 | int panic_on_unrecovered_nmi; | ||
67 | |||
68 | asmlinkage int system_call(void); | ||
69 | |||
70 | /* Do we ignore FPU interrupts ? */ | ||
71 | char ignore_fpu_irq = 0; | ||
72 | |||
73 | /* | ||
74 | * The IDT has to be page-aligned to simplify the Pentium | ||
75 | * F0 0F bug workaround.. We have a special link segment | ||
76 | * for this. | ||
77 | */ | ||
78 | struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; | ||
79 | |||
80 | asmlinkage void divide_error(void); | ||
81 | asmlinkage void debug(void); | ||
82 | asmlinkage void nmi(void); | ||
83 | asmlinkage void int3(void); | ||
84 | asmlinkage void overflow(void); | ||
85 | asmlinkage void bounds(void); | ||
86 | asmlinkage void invalid_op(void); | ||
87 | asmlinkage void device_not_available(void); | ||
88 | asmlinkage void coprocessor_segment_overrun(void); | ||
89 | asmlinkage void invalid_TSS(void); | ||
90 | asmlinkage void segment_not_present(void); | ||
91 | asmlinkage void stack_segment(void); | ||
92 | asmlinkage void general_protection(void); | ||
93 | asmlinkage void page_fault(void); | ||
94 | asmlinkage void coprocessor_error(void); | ||
95 | asmlinkage void simd_coprocessor_error(void); | ||
96 | asmlinkage void alignment_check(void); | ||
97 | asmlinkage void spurious_interrupt_bug(void); | ||
98 | asmlinkage void machine_check(void); | ||
99 | |||
100 | int kstack_depth_to_print = 24; | ||
101 | static unsigned int code_bytes = 64; | ||
102 | |||
103 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size) | ||
104 | { | ||
105 | return p > (void *)tinfo && | ||
106 | p <= (void *)tinfo + THREAD_SIZE - size; | ||
107 | } | ||
108 | |||
109 | /* The form of the top of the frame on the stack */ | ||
110 | struct stack_frame { | ||
111 | struct stack_frame *next_frame; | ||
112 | unsigned long return_address; | ||
113 | }; | ||
114 | |||
115 | static inline unsigned long print_context_stack(struct thread_info *tinfo, | ||
116 | unsigned long *stack, unsigned long ebp, | ||
117 | struct stacktrace_ops *ops, void *data) | ||
118 | { | ||
119 | #ifdef CONFIG_FRAME_POINTER | ||
120 | struct stack_frame *frame = (struct stack_frame *)ebp; | ||
121 | while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) { | ||
122 | struct stack_frame *next; | ||
123 | unsigned long addr; | ||
124 | |||
125 | addr = frame->return_address; | ||
126 | ops->address(data, addr); | ||
127 | /* | ||
128 | * break out of recursive entries (such as | ||
129 | * end_of_stack_stop_unwind_function). Also, | ||
130 | * we can never allow a frame pointer to | ||
131 | * move downwards! | ||
132 | */ | ||
133 | next = frame->next_frame; | ||
134 | if (next <= frame) | ||
135 | break; | ||
136 | frame = next; | ||
137 | } | ||
138 | #else | ||
139 | while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) { | ||
140 | unsigned long addr; | ||
141 | |||
142 | addr = *stack++; | ||
143 | if (__kernel_text_address(addr)) | ||
144 | ops->address(data, addr); | ||
145 | } | ||
146 | #endif | ||
147 | return ebp; | ||
148 | } | ||
149 | |||
150 | #define MSG(msg) ops->warning(data, msg) | ||
151 | |||
152 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | ||
153 | unsigned long *stack, | ||
154 | struct stacktrace_ops *ops, void *data) | ||
155 | { | ||
156 | unsigned long ebp = 0; | ||
157 | |||
158 | if (!task) | ||
159 | task = current; | ||
160 | |||
161 | if (!stack) { | ||
162 | unsigned long dummy; | ||
163 | stack = &dummy; | ||
164 | if (task != current) | ||
165 | stack = (unsigned long *)task->thread.esp; | ||
166 | } | ||
167 | |||
168 | #ifdef CONFIG_FRAME_POINTER | ||
169 | if (!ebp) { | ||
170 | if (task == current) { | ||
171 | /* Grab ebp right from our regs */ | ||
172 | asm ("movl %%ebp, %0" : "=r" (ebp) : ); | ||
173 | } else { | ||
174 | /* ebp is the last reg pushed by switch_to */ | ||
175 | ebp = *(unsigned long *) task->thread.esp; | ||
176 | } | ||
177 | } | ||
178 | #endif | ||
179 | |||
180 | while (1) { | ||
181 | struct thread_info *context; | ||
182 | context = (struct thread_info *) | ||
183 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | ||
184 | ebp = print_context_stack(context, stack, ebp, ops, data); | ||
185 | /* Should be after the line below, but somewhere | ||
186 | in early boot context comes out corrupted and we | ||
187 | can't reference it -AK */ | ||
188 | if (ops->stack(data, "IRQ") < 0) | ||
189 | break; | ||
190 | stack = (unsigned long*)context->previous_esp; | ||
191 | if (!stack) | ||
192 | break; | ||
193 | touch_nmi_watchdog(); | ||
194 | } | ||
195 | } | ||
196 | EXPORT_SYMBOL(dump_trace); | ||
197 | |||
198 | static void | ||
199 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
200 | { | ||
201 | printk(data); | ||
202 | print_symbol(msg, symbol); | ||
203 | printk("\n"); | ||
204 | } | ||
205 | |||
206 | static void print_trace_warning(void *data, char *msg) | ||
207 | { | ||
208 | printk("%s%s\n", (char *)data, msg); | ||
209 | } | ||
210 | |||
211 | static int print_trace_stack(void *data, char *name) | ||
212 | { | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | * Print one address/symbol entries per line. | ||
218 | */ | ||
219 | static void print_trace_address(void *data, unsigned long addr) | ||
220 | { | ||
221 | printk("%s [<%08lx>] ", (char *)data, addr); | ||
222 | print_symbol("%s\n", addr); | ||
223 | touch_nmi_watchdog(); | ||
224 | } | ||
225 | |||
226 | static struct stacktrace_ops print_trace_ops = { | ||
227 | .warning = print_trace_warning, | ||
228 | .warning_symbol = print_trace_warning_symbol, | ||
229 | .stack = print_trace_stack, | ||
230 | .address = print_trace_address, | ||
231 | }; | ||
232 | |||
233 | static void | ||
234 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
235 | unsigned long * stack, char *log_lvl) | ||
236 | { | ||
237 | dump_trace(task, regs, stack, &print_trace_ops, log_lvl); | ||
238 | printk("%s =======================\n", log_lvl); | ||
239 | } | ||
240 | |||
241 | void show_trace(struct task_struct *task, struct pt_regs *regs, | ||
242 | unsigned long * stack) | ||
243 | { | ||
244 | show_trace_log_lvl(task, regs, stack, ""); | ||
245 | } | ||
246 | |||
247 | static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
248 | unsigned long *esp, char *log_lvl) | ||
249 | { | ||
250 | unsigned long *stack; | ||
251 | int i; | ||
252 | |||
253 | if (esp == NULL) { | ||
254 | if (task) | ||
255 | esp = (unsigned long*)task->thread.esp; | ||
256 | else | ||
257 | esp = (unsigned long *)&esp; | ||
258 | } | ||
259 | |||
260 | stack = esp; | ||
261 | for(i = 0; i < kstack_depth_to_print; i++) { | ||
262 | if (kstack_end(stack)) | ||
263 | break; | ||
264 | if (i && ((i % 8) == 0)) | ||
265 | printk("\n%s ", log_lvl); | ||
266 | printk("%08lx ", *stack++); | ||
267 | } | ||
268 | printk("\n%sCall Trace:\n", log_lvl); | ||
269 | show_trace_log_lvl(task, regs, esp, log_lvl); | ||
270 | } | ||
271 | |||
272 | void show_stack(struct task_struct *task, unsigned long *esp) | ||
273 | { | ||
274 | printk(" "); | ||
275 | show_stack_log_lvl(task, NULL, esp, ""); | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * The architecture-independent dump_stack generator | ||
280 | */ | ||
281 | void dump_stack(void) | ||
282 | { | ||
283 | unsigned long stack; | ||
284 | |||
285 | show_trace(current, NULL, &stack); | ||
286 | } | ||
287 | |||
288 | EXPORT_SYMBOL(dump_stack); | ||
289 | |||
290 | void show_registers(struct pt_regs *regs) | ||
291 | { | ||
292 | int i; | ||
293 | int in_kernel = 1; | ||
294 | unsigned long esp; | ||
295 | unsigned short ss, gs; | ||
296 | |||
297 | esp = (unsigned long) (®s->esp); | ||
298 | savesegment(ss, ss); | ||
299 | savesegment(gs, gs); | ||
300 | if (user_mode_vm(regs)) { | ||
301 | in_kernel = 0; | ||
302 | esp = regs->esp; | ||
303 | ss = regs->xss & 0xffff; | ||
304 | } | ||
305 | print_modules(); | ||
306 | printk(KERN_EMERG "CPU: %d\n" | ||
307 | KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" | ||
308 | KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", | ||
309 | smp_processor_id(), 0xffff & regs->xcs, regs->eip, | ||
310 | print_tainted(), regs->eflags, init_utsname()->release, | ||
311 | (int)strcspn(init_utsname()->version, " "), | ||
312 | init_utsname()->version); | ||
313 | print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); | ||
314 | printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", | ||
315 | regs->eax, regs->ebx, regs->ecx, regs->edx); | ||
316 | printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", | ||
317 | regs->esi, regs->edi, regs->ebp, esp); | ||
318 | printk(KERN_EMERG "ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n", | ||
319 | regs->xds & 0xffff, regs->xes & 0xffff, regs->xfs & 0xffff, gs, ss); | ||
320 | printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", | ||
321 | TASK_COMM_LEN, current->comm, current->pid, | ||
322 | current_thread_info(), current, task_thread_info(current)); | ||
323 | /* | ||
324 | * When in-kernel, we also print out the stack and code at the | ||
325 | * time of the fault.. | ||
326 | */ | ||
327 | if (in_kernel) { | ||
328 | u8 *eip; | ||
329 | unsigned int code_prologue = code_bytes * 43 / 64; | ||
330 | unsigned int code_len = code_bytes; | ||
331 | unsigned char c; | ||
332 | |||
333 | printk("\n" KERN_EMERG "Stack: "); | ||
334 | show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); | ||
335 | |||
336 | printk(KERN_EMERG "Code: "); | ||
337 | |||
338 | eip = (u8 *)regs->eip - code_prologue; | ||
339 | if (eip < (u8 *)PAGE_OFFSET || | ||
340 | probe_kernel_address(eip, c)) { | ||
341 | /* try starting at EIP */ | ||
342 | eip = (u8 *)regs->eip; | ||
343 | code_len = code_len - code_prologue + 1; | ||
344 | } | ||
345 | for (i = 0; i < code_len; i++, eip++) { | ||
346 | if (eip < (u8 *)PAGE_OFFSET || | ||
347 | probe_kernel_address(eip, c)) { | ||
348 | printk(" Bad EIP value."); | ||
349 | break; | ||
350 | } | ||
351 | if (eip == (u8 *)regs->eip) | ||
352 | printk("<%02x> ", c); | ||
353 | else | ||
354 | printk("%02x ", c); | ||
355 | } | ||
356 | } | ||
357 | printk("\n"); | ||
358 | } | ||
359 | |||
360 | int is_valid_bugaddr(unsigned long eip) | ||
361 | { | ||
362 | unsigned short ud2; | ||
363 | |||
364 | if (eip < PAGE_OFFSET) | ||
365 | return 0; | ||
366 | if (probe_kernel_address((unsigned short *)eip, ud2)) | ||
367 | return 0; | ||
368 | |||
369 | return ud2 == 0x0b0f; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * This is gone through when something in the kernel has done something bad and | ||
374 | * is about to be terminated. | ||
375 | */ | ||
376 | void die(const char * str, struct pt_regs * regs, long err) | ||
377 | { | ||
378 | static struct { | ||
379 | spinlock_t lock; | ||
380 | u32 lock_owner; | ||
381 | int lock_owner_depth; | ||
382 | } die = { | ||
383 | .lock = __SPIN_LOCK_UNLOCKED(die.lock), | ||
384 | .lock_owner = -1, | ||
385 | .lock_owner_depth = 0 | ||
386 | }; | ||
387 | static int die_counter; | ||
388 | unsigned long flags; | ||
389 | |||
390 | oops_enter(); | ||
391 | |||
392 | if (die.lock_owner != raw_smp_processor_id()) { | ||
393 | console_verbose(); | ||
394 | spin_lock_irqsave(&die.lock, flags); | ||
395 | die.lock_owner = smp_processor_id(); | ||
396 | die.lock_owner_depth = 0; | ||
397 | bust_spinlocks(1); | ||
398 | } | ||
399 | else | ||
400 | local_save_flags(flags); | ||
401 | |||
402 | if (++die.lock_owner_depth < 3) { | ||
403 | int nl = 0; | ||
404 | unsigned long esp; | ||
405 | unsigned short ss; | ||
406 | |||
407 | report_bug(regs->eip, regs); | ||
408 | |||
409 | printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); | ||
410 | #ifdef CONFIG_PREEMPT | ||
411 | printk(KERN_EMERG "PREEMPT "); | ||
412 | nl = 1; | ||
413 | #endif | ||
414 | #ifdef CONFIG_SMP | ||
415 | if (!nl) | ||
416 | printk(KERN_EMERG); | ||
417 | printk("SMP "); | ||
418 | nl = 1; | ||
419 | #endif | ||
420 | #ifdef CONFIG_DEBUG_PAGEALLOC | ||
421 | if (!nl) | ||
422 | printk(KERN_EMERG); | ||
423 | printk("DEBUG_PAGEALLOC"); | ||
424 | nl = 1; | ||
425 | #endif | ||
426 | if (nl) | ||
427 | printk("\n"); | ||
428 | if (notify_die(DIE_OOPS, str, regs, err, | ||
429 | current->thread.trap_no, SIGSEGV) != | ||
430 | NOTIFY_STOP) { | ||
431 | show_registers(regs); | ||
432 | /* Executive summary in case the oops scrolled away */ | ||
433 | esp = (unsigned long) (®s->esp); | ||
434 | savesegment(ss, ss); | ||
435 | if (user_mode(regs)) { | ||
436 | esp = regs->esp; | ||
437 | ss = regs->xss & 0xffff; | ||
438 | } | ||
439 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip); | ||
440 | print_symbol("%s", regs->eip); | ||
441 | printk(" SS:ESP %04x:%08lx\n", ss, esp); | ||
442 | } | ||
443 | else | ||
444 | regs = NULL; | ||
445 | } else | ||
446 | printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); | ||
447 | |||
448 | bust_spinlocks(0); | ||
449 | die.lock_owner = -1; | ||
450 | add_taint(TAINT_DIE); | ||
451 | spin_unlock_irqrestore(&die.lock, flags); | ||
452 | |||
453 | if (!regs) | ||
454 | return; | ||
455 | |||
456 | if (kexec_should_crash(current)) | ||
457 | crash_kexec(regs); | ||
458 | |||
459 | if (in_interrupt()) | ||
460 | panic("Fatal exception in interrupt"); | ||
461 | |||
462 | if (panic_on_oops) | ||
463 | panic("Fatal exception"); | ||
464 | |||
465 | oops_exit(); | ||
466 | do_exit(SIGSEGV); | ||
467 | } | ||
468 | |||
469 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | ||
470 | { | ||
471 | if (!user_mode_vm(regs)) | ||
472 | die(str, regs, err); | ||
473 | } | ||
474 | |||
475 | static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, | ||
476 | struct pt_regs * regs, long error_code, | ||
477 | siginfo_t *info) | ||
478 | { | ||
479 | struct task_struct *tsk = current; | ||
480 | |||
481 | if (regs->eflags & VM_MASK) { | ||
482 | if (vm86) | ||
483 | goto vm86_trap; | ||
484 | goto trap_signal; | ||
485 | } | ||
486 | |||
487 | if (!user_mode(regs)) | ||
488 | goto kernel_trap; | ||
489 | |||
490 | trap_signal: { | ||
491 | /* | ||
492 | * We want error_code and trap_no set for userspace faults and | ||
493 | * kernelspace faults which result in die(), but not | ||
494 | * kernelspace faults which are fixed up. die() gives the | ||
495 | * process no chance to handle the signal and notice the | ||
496 | * kernel fault information, so that won't result in polluting | ||
497 | * the information about previously queued, but not yet | ||
498 | * delivered, faults. See also do_general_protection below. | ||
499 | */ | ||
500 | tsk->thread.error_code = error_code; | ||
501 | tsk->thread.trap_no = trapnr; | ||
502 | |||
503 | if (info) | ||
504 | force_sig_info(signr, info, tsk); | ||
505 | else | ||
506 | force_sig(signr, tsk); | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | kernel_trap: { | ||
511 | if (!fixup_exception(regs)) { | ||
512 | tsk->thread.error_code = error_code; | ||
513 | tsk->thread.trap_no = trapnr; | ||
514 | die(str, regs, error_code); | ||
515 | } | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | vm86_trap: { | ||
520 | int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); | ||
521 | if (ret) goto trap_signal; | ||
522 | return; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | #define DO_ERROR(trapnr, signr, str, name) \ | ||
527 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | ||
528 | { \ | ||
529 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
530 | == NOTIFY_STOP) \ | ||
531 | return; \ | ||
532 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ | ||
533 | } | ||
534 | |||
535 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ | ||
536 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | ||
537 | { \ | ||
538 | siginfo_t info; \ | ||
539 | if (irq) \ | ||
540 | local_irq_enable(); \ | ||
541 | info.si_signo = signr; \ | ||
542 | info.si_errno = 0; \ | ||
543 | info.si_code = sicode; \ | ||
544 | info.si_addr = (void __user *)siaddr; \ | ||
545 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
546 | == NOTIFY_STOP) \ | ||
547 | return; \ | ||
548 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ | ||
549 | } | ||
550 | |||
551 | #define DO_VM86_ERROR(trapnr, signr, str, name) \ | ||
552 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | ||
553 | { \ | ||
554 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
555 | == NOTIFY_STOP) \ | ||
556 | return; \ | ||
557 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ | ||
558 | } | ||
559 | |||
560 | #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | ||
561 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | ||
562 | { \ | ||
563 | siginfo_t info; \ | ||
564 | info.si_signo = signr; \ | ||
565 | info.si_errno = 0; \ | ||
566 | info.si_code = sicode; \ | ||
567 | info.si_addr = (void __user *)siaddr; \ | ||
568 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | ||
569 | == NOTIFY_STOP) \ | ||
570 | return; \ | ||
571 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ | ||
572 | } | ||
573 | |||
574 | DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) | ||
575 | #ifndef CONFIG_KPROBES | ||
576 | DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) | ||
577 | #endif | ||
578 | DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) | ||
579 | DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) | ||
580 | DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip, 0) | ||
581 | DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | ||
582 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | ||
583 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | ||
584 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | ||
585 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) | ||
586 | DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1) | ||
587 | |||
588 | fastcall void __kprobes do_general_protection(struct pt_regs * regs, | ||
589 | long error_code) | ||
590 | { | ||
591 | int cpu = get_cpu(); | ||
592 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | ||
593 | struct thread_struct *thread = ¤t->thread; | ||
594 | |||
595 | /* | ||
596 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an | ||
597 | * invalid offset set (the LAZY one) and the faulting thread has | ||
598 | * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS | ||
599 | * and we set the offset field correctly. Then we let the CPU to | ||
600 | * restart the faulting instruction. | ||
601 | */ | ||
602 | if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && | ||
603 | thread->io_bitmap_ptr) { | ||
604 | memcpy(tss->io_bitmap, thread->io_bitmap_ptr, | ||
605 | thread->io_bitmap_max); | ||
606 | /* | ||
607 | * If the previously set map was extending to higher ports | ||
608 | * than the current one, pad extra space with 0xff (no access). | ||
609 | */ | ||
610 | if (thread->io_bitmap_max < tss->io_bitmap_max) | ||
611 | memset((char *) tss->io_bitmap + | ||
612 | thread->io_bitmap_max, 0xff, | ||
613 | tss->io_bitmap_max - thread->io_bitmap_max); | ||
614 | tss->io_bitmap_max = thread->io_bitmap_max; | ||
615 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; | ||
616 | tss->io_bitmap_owner = thread; | ||
617 | put_cpu(); | ||
618 | return; | ||
619 | } | ||
620 | put_cpu(); | ||
621 | |||
622 | if (regs->eflags & VM_MASK) | ||
623 | goto gp_in_vm86; | ||
624 | |||
625 | if (!user_mode(regs)) | ||
626 | goto gp_in_kernel; | ||
627 | |||
628 | current->thread.error_code = error_code; | ||
629 | current->thread.trap_no = 13; | ||
630 | if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) && | ||
631 | printk_ratelimit()) | ||
632 | printk(KERN_INFO | ||
633 | "%s[%d] general protection eip:%lx esp:%lx error:%lx\n", | ||
634 | current->comm, current->pid, | ||
635 | regs->eip, regs->esp, error_code); | ||
636 | |||
637 | force_sig(SIGSEGV, current); | ||
638 | return; | ||
639 | |||
640 | gp_in_vm86: | ||
641 | local_irq_enable(); | ||
642 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | ||
643 | return; | ||
644 | |||
645 | gp_in_kernel: | ||
646 | if (!fixup_exception(regs)) { | ||
647 | current->thread.error_code = error_code; | ||
648 | current->thread.trap_no = 13; | ||
649 | if (notify_die(DIE_GPF, "general protection fault", regs, | ||
650 | error_code, 13, SIGSEGV) == NOTIFY_STOP) | ||
651 | return; | ||
652 | die("general protection fault", regs, error_code); | ||
653 | } | ||
654 | } | ||
655 | |||
656 | static __kprobes void | ||
657 | mem_parity_error(unsigned char reason, struct pt_regs * regs) | ||
658 | { | ||
659 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " | ||
660 | "CPU %d.\n", reason, smp_processor_id()); | ||
661 | printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); | ||
662 | |||
663 | #if defined(CONFIG_EDAC) | ||
664 | if(edac_handler_set()) { | ||
665 | edac_atomic_assert_error(); | ||
666 | return; | ||
667 | } | ||
668 | #endif | ||
669 | |||
670 | if (panic_on_unrecovered_nmi) | ||
671 | panic("NMI: Not continuing"); | ||
672 | |||
673 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | ||
674 | |||
675 | /* Clear and disable the memory parity error line. */ | ||
676 | clear_mem_error(reason); | ||
677 | } | ||
678 | |||
679 | static __kprobes void | ||
680 | io_check_error(unsigned char reason, struct pt_regs * regs) | ||
681 | { | ||
682 | unsigned long i; | ||
683 | |||
684 | printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n"); | ||
685 | show_registers(regs); | ||
686 | |||
687 | /* Re-enable the IOCK line, wait for a few seconds */ | ||
688 | reason = (reason & 0xf) | 8; | ||
689 | outb(reason, 0x61); | ||
690 | i = 2000; | ||
691 | while (--i) udelay(1000); | ||
692 | reason &= ~8; | ||
693 | outb(reason, 0x61); | ||
694 | } | ||
695 | |||
696 | static __kprobes void | ||
697 | unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | ||
698 | { | ||
699 | #ifdef CONFIG_MCA | ||
700 | /* Might actually be able to figure out what the guilty party | ||
701 | * is. */ | ||
702 | if( MCA_bus ) { | ||
703 | mca_handle_nmi(); | ||
704 | return; | ||
705 | } | ||
706 | #endif | ||
707 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " | ||
708 | "CPU %d.\n", reason, smp_processor_id()); | ||
709 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | ||
710 | if (panic_on_unrecovered_nmi) | ||
711 | panic("NMI: Not continuing"); | ||
712 | |||
713 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | ||
714 | } | ||
715 | |||
716 | static DEFINE_SPINLOCK(nmi_print_lock); | ||
717 | |||
718 | void __kprobes die_nmi(struct pt_regs *regs, const char *msg) | ||
719 | { | ||
720 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == | ||
721 | NOTIFY_STOP) | ||
722 | return; | ||
723 | |||
724 | spin_lock(&nmi_print_lock); | ||
725 | /* | ||
726 | * We are in trouble anyway, lets at least try | ||
727 | * to get a message out. | ||
728 | */ | ||
729 | bust_spinlocks(1); | ||
730 | printk(KERN_EMERG "%s", msg); | ||
731 | printk(" on CPU%d, eip %08lx, registers:\n", | ||
732 | smp_processor_id(), regs->eip); | ||
733 | show_registers(regs); | ||
734 | console_silent(); | ||
735 | spin_unlock(&nmi_print_lock); | ||
736 | bust_spinlocks(0); | ||
737 | |||
738 | /* If we are in kernel we are probably nested up pretty bad | ||
739 | * and might aswell get out now while we still can. | ||
740 | */ | ||
741 | if (!user_mode_vm(regs)) { | ||
742 | current->thread.trap_no = 2; | ||
743 | crash_kexec(regs); | ||
744 | } | ||
745 | |||
746 | do_exit(SIGSEGV); | ||
747 | } | ||
748 | |||
749 | static __kprobes void default_do_nmi(struct pt_regs * regs) | ||
750 | { | ||
751 | unsigned char reason = 0; | ||
752 | |||
753 | /* Only the BSP gets external NMIs from the system. */ | ||
754 | if (!smp_processor_id()) | ||
755 | reason = get_nmi_reason(); | ||
756 | |||
757 | if (!(reason & 0xc0)) { | ||
758 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | ||
759 | == NOTIFY_STOP) | ||
760 | return; | ||
761 | #ifdef CONFIG_X86_LOCAL_APIC | ||
762 | /* | ||
763 | * Ok, so this is none of the documented NMI sources, | ||
764 | * so it must be the NMI watchdog. | ||
765 | */ | ||
766 | if (nmi_watchdog_tick(regs, reason)) | ||
767 | return; | ||
768 | if (!do_nmi_callback(regs, smp_processor_id())) | ||
769 | #endif | ||
770 | unknown_nmi_error(reason, regs); | ||
771 | |||
772 | return; | ||
773 | } | ||
774 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | ||
775 | return; | ||
776 | if (reason & 0x80) | ||
777 | mem_parity_error(reason, regs); | ||
778 | if (reason & 0x40) | ||
779 | io_check_error(reason, regs); | ||
780 | /* | ||
781 | * Reassert NMI in case it became active meanwhile | ||
782 | * as it's edge-triggered. | ||
783 | */ | ||
784 | reassert_nmi(); | ||
785 | } | ||
786 | |||
787 | static int ignore_nmis; | ||
788 | |||
789 | fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) | ||
790 | { | ||
791 | int cpu; | ||
792 | |||
793 | nmi_enter(); | ||
794 | |||
795 | cpu = smp_processor_id(); | ||
796 | |||
797 | ++nmi_count(cpu); | ||
798 | |||
799 | if (!ignore_nmis) | ||
800 | default_do_nmi(regs); | ||
801 | |||
802 | nmi_exit(); | ||
803 | } | ||
804 | |||
805 | void stop_nmi(void) | ||
806 | { | ||
807 | acpi_nmi_disable(); | ||
808 | ignore_nmis++; | ||
809 | } | ||
810 | |||
811 | void restart_nmi(void) | ||
812 | { | ||
813 | ignore_nmis--; | ||
814 | acpi_nmi_enable(); | ||
815 | } | ||
816 | |||
817 | #ifdef CONFIG_KPROBES | ||
818 | fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) | ||
819 | { | ||
820 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) | ||
821 | == NOTIFY_STOP) | ||
822 | return; | ||
823 | /* This is an interrupt gate, because kprobes wants interrupts | ||
824 | disabled. Normal trap handlers don't. */ | ||
825 | restore_interrupts(regs); | ||
826 | do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); | ||
827 | } | ||
828 | #endif | ||
829 | |||
830 | /* | ||
831 | * Our handling of the processor debug registers is non-trivial. | ||
832 | * We do not clear them on entry and exit from the kernel. Therefore | ||
833 | * it is possible to get a watchpoint trap here from inside the kernel. | ||
834 | * However, the code in ./ptrace.c has ensured that the user can | ||
835 | * only set watchpoints on userspace addresses. Therefore the in-kernel | ||
836 | * watchpoint trap can only occur in code which is reading/writing | ||
837 | * from user space. Such code must not hold kernel locks (since it | ||
838 | * can equally take a page fault), therefore it is safe to call | ||
839 | * force_sig_info even though that claims and releases locks. | ||
840 | * | ||
841 | * Code in ./signal.c ensures that the debug control register | ||
842 | * is restored before we deliver any signal, and therefore that | ||
843 | * user code runs with the correct debug control register even though | ||
844 | * we clear it here. | ||
845 | * | ||
846 | * Being careful here means that we don't have to be as careful in a | ||
847 | * lot of more complicated places (task switching can be a bit lazy | ||
848 | * about restoring all the debug state, and ptrace doesn't have to | ||
849 | * find every occurrence of the TF bit that could be saved away even | ||
850 | * by user code) | ||
851 | */ | ||
852 | fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code) | ||
853 | { | ||
854 | unsigned int condition; | ||
855 | struct task_struct *tsk = current; | ||
856 | |||
857 | get_debugreg(condition, 6); | ||
858 | |||
859 | if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, | ||
860 | SIGTRAP) == NOTIFY_STOP) | ||
861 | return; | ||
862 | /* It's safe to allow irq's after DR6 has been saved */ | ||
863 | if (regs->eflags & X86_EFLAGS_IF) | ||
864 | local_irq_enable(); | ||
865 | |||
866 | /* Mask out spurious debug traps due to lazy DR7 setting */ | ||
867 | if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { | ||
868 | if (!tsk->thread.debugreg[7]) | ||
869 | goto clear_dr7; | ||
870 | } | ||
871 | |||
872 | if (regs->eflags & VM_MASK) | ||
873 | goto debug_vm86; | ||
874 | |||
875 | /* Save debug status register where ptrace can see it */ | ||
876 | tsk->thread.debugreg[6] = condition; | ||
877 | |||
878 | /* | ||
879 | * Single-stepping through TF: make sure we ignore any events in | ||
880 | * kernel space (but re-enable TF when returning to user mode). | ||
881 | */ | ||
882 | if (condition & DR_STEP) { | ||
883 | /* | ||
884 | * We already checked v86 mode above, so we can | ||
885 | * check for kernel mode by just checking the CPL | ||
886 | * of CS. | ||
887 | */ | ||
888 | if (!user_mode(regs)) | ||
889 | goto clear_TF_reenable; | ||
890 | } | ||
891 | |||
892 | /* Ok, finally something we can handle */ | ||
893 | send_sigtrap(tsk, regs, error_code); | ||
894 | |||
895 | /* Disable additional traps. They'll be re-enabled when | ||
896 | * the signal is delivered. | ||
897 | */ | ||
898 | clear_dr7: | ||
899 | set_debugreg(0, 7); | ||
900 | return; | ||
901 | |||
902 | debug_vm86: | ||
903 | handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); | ||
904 | return; | ||
905 | |||
906 | clear_TF_reenable: | ||
907 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); | ||
908 | regs->eflags &= ~TF_MASK; | ||
909 | return; | ||
910 | } | ||
911 | |||
912 | /* | ||
913 | * Note that we play around with the 'TS' bit in an attempt to get | ||
914 | * the correct behaviour even in the presence of the asynchronous | ||
915 | * IRQ13 behaviour | ||
916 | */ | ||
917 | void math_error(void __user *eip) | ||
918 | { | ||
919 | struct task_struct * task; | ||
920 | siginfo_t info; | ||
921 | unsigned short cwd, swd; | ||
922 | |||
923 | /* | ||
924 | * Save the info for the exception handler and clear the error. | ||
925 | */ | ||
926 | task = current; | ||
927 | save_init_fpu(task); | ||
928 | task->thread.trap_no = 16; | ||
929 | task->thread.error_code = 0; | ||
930 | info.si_signo = SIGFPE; | ||
931 | info.si_errno = 0; | ||
932 | info.si_code = __SI_FAULT; | ||
933 | info.si_addr = eip; | ||
934 | /* | ||
935 | * (~cwd & swd) will mask out exceptions that are not set to unmasked | ||
936 | * status. 0x3f is the exception bits in these regs, 0x200 is the | ||
937 | * C1 reg you need in case of a stack fault, 0x040 is the stack | ||
938 | * fault bit. We should only be taking one exception at a time, | ||
939 | * so if this combination doesn't produce any single exception, | ||
940 | * then we have a bad program that isn't syncronizing its FPU usage | ||
941 | * and it will suffer the consequences since we won't be able to | ||
942 | * fully reproduce the context of the exception | ||
943 | */ | ||
944 | cwd = get_fpu_cwd(task); | ||
945 | swd = get_fpu_swd(task); | ||
946 | switch (swd & ~cwd & 0x3f) { | ||
947 | case 0x000: /* No unmasked exception */ | ||
948 | return; | ||
949 | default: /* Multiple exceptions */ | ||
950 | break; | ||
951 | case 0x001: /* Invalid Op */ | ||
952 | /* | ||
953 | * swd & 0x240 == 0x040: Stack Underflow | ||
954 | * swd & 0x240 == 0x240: Stack Overflow | ||
955 | * User must clear the SF bit (0x40) if set | ||
956 | */ | ||
957 | info.si_code = FPE_FLTINV; | ||
958 | break; | ||
959 | case 0x002: /* Denormalize */ | ||
960 | case 0x010: /* Underflow */ | ||
961 | info.si_code = FPE_FLTUND; | ||
962 | break; | ||
963 | case 0x004: /* Zero Divide */ | ||
964 | info.si_code = FPE_FLTDIV; | ||
965 | break; | ||
966 | case 0x008: /* Overflow */ | ||
967 | info.si_code = FPE_FLTOVF; | ||
968 | break; | ||
969 | case 0x020: /* Precision */ | ||
970 | info.si_code = FPE_FLTRES; | ||
971 | break; | ||
972 | } | ||
973 | force_sig_info(SIGFPE, &info, task); | ||
974 | } | ||
975 | |||
976 | fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code) | ||
977 | { | ||
978 | ignore_fpu_irq = 1; | ||
979 | math_error((void __user *)regs->eip); | ||
980 | } | ||
981 | |||
982 | static void simd_math_error(void __user *eip) | ||
983 | { | ||
984 | struct task_struct * task; | ||
985 | siginfo_t info; | ||
986 | unsigned short mxcsr; | ||
987 | |||
988 | /* | ||
989 | * Save the info for the exception handler and clear the error. | ||
990 | */ | ||
991 | task = current; | ||
992 | save_init_fpu(task); | ||
993 | task->thread.trap_no = 19; | ||
994 | task->thread.error_code = 0; | ||
995 | info.si_signo = SIGFPE; | ||
996 | info.si_errno = 0; | ||
997 | info.si_code = __SI_FAULT; | ||
998 | info.si_addr = eip; | ||
999 | /* | ||
1000 | * The SIMD FPU exceptions are handled a little differently, as there | ||
1001 | * is only a single status/control register. Thus, to determine which | ||
1002 | * unmasked exception was caught we must mask the exception mask bits | ||
1003 | * at 0x1f80, and then use these to mask the exception bits at 0x3f. | ||
1004 | */ | ||
1005 | mxcsr = get_fpu_mxcsr(task); | ||
1006 | switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { | ||
1007 | case 0x000: | ||
1008 | default: | ||
1009 | break; | ||
1010 | case 0x001: /* Invalid Op */ | ||
1011 | info.si_code = FPE_FLTINV; | ||
1012 | break; | ||
1013 | case 0x002: /* Denormalize */ | ||
1014 | case 0x010: /* Underflow */ | ||
1015 | info.si_code = FPE_FLTUND; | ||
1016 | break; | ||
1017 | case 0x004: /* Zero Divide */ | ||
1018 | info.si_code = FPE_FLTDIV; | ||
1019 | break; | ||
1020 | case 0x008: /* Overflow */ | ||
1021 | info.si_code = FPE_FLTOVF; | ||
1022 | break; | ||
1023 | case 0x020: /* Precision */ | ||
1024 | info.si_code = FPE_FLTRES; | ||
1025 | break; | ||
1026 | } | ||
1027 | force_sig_info(SIGFPE, &info, task); | ||
1028 | } | ||
1029 | |||
1030 | fastcall void do_simd_coprocessor_error(struct pt_regs * regs, | ||
1031 | long error_code) | ||
1032 | { | ||
1033 | if (cpu_has_xmm) { | ||
1034 | /* Handle SIMD FPU exceptions on PIII+ processors. */ | ||
1035 | ignore_fpu_irq = 1; | ||
1036 | simd_math_error((void __user *)regs->eip); | ||
1037 | } else { | ||
1038 | /* | ||
1039 | * Handle strange cache flush from user space exception | ||
1040 | * in all other cases. This is undocumented behaviour. | ||
1041 | */ | ||
1042 | if (regs->eflags & VM_MASK) { | ||
1043 | handle_vm86_fault((struct kernel_vm86_regs *)regs, | ||
1044 | error_code); | ||
1045 | return; | ||
1046 | } | ||
1047 | current->thread.trap_no = 19; | ||
1048 | current->thread.error_code = error_code; | ||
1049 | die_if_kernel("cache flush denied", regs, error_code); | ||
1050 | force_sig(SIGSEGV, current); | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | fastcall void do_spurious_interrupt_bug(struct pt_regs * regs, | ||
1055 | long error_code) | ||
1056 | { | ||
1057 | #if 0 | ||
1058 | /* No need to warn about this any longer. */ | ||
1059 | printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); | ||
1060 | #endif | ||
1061 | } | ||
1062 | |||
1063 | fastcall unsigned long patch_espfix_desc(unsigned long uesp, | ||
1064 | unsigned long kesp) | ||
1065 | { | ||
1066 | struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; | ||
1067 | unsigned long base = (kesp - uesp) & -THREAD_SIZE; | ||
1068 | unsigned long new_kesp = kesp - base; | ||
1069 | unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; | ||
1070 | __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; | ||
1071 | /* Set up base for espfix segment */ | ||
1072 | desc &= 0x00f0ff0000000000ULL; | ||
1073 | desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | | ||
1074 | ((((__u64)base) << 32) & 0xff00000000000000ULL) | | ||
1075 | ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | | ||
1076 | (lim_pages & 0xffff); | ||
1077 | *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; | ||
1078 | return new_kesp; | ||
1079 | } | ||
1080 | |||
1081 | /* | ||
1082 | * 'math_state_restore()' saves the current math information in the | ||
1083 | * old math state array, and gets the new ones from the current task | ||
1084 | * | ||
1085 | * Careful.. There are problems with IBM-designed IRQ13 behaviour. | ||
1086 | * Don't touch unless you *really* know how it works. | ||
1087 | * | ||
1088 | * Must be called with kernel preemption disabled (in this case, | ||
1089 | * local interrupts are disabled at the call-site in entry.S). | ||
1090 | */ | ||
1091 | asmlinkage void math_state_restore(void) | ||
1092 | { | ||
1093 | struct thread_info *thread = current_thread_info(); | ||
1094 | struct task_struct *tsk = thread->task; | ||
1095 | |||
1096 | clts(); /* Allow maths ops (or we recurse) */ | ||
1097 | if (!tsk_used_math(tsk)) | ||
1098 | init_fpu(tsk); | ||
1099 | restore_fpu(tsk); | ||
1100 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ | ||
1101 | tsk->fpu_counter++; | ||
1102 | } | ||
1103 | EXPORT_SYMBOL_GPL(math_state_restore); | ||
1104 | |||
1105 | #ifndef CONFIG_MATH_EMULATION | ||
1106 | |||
1107 | asmlinkage void math_emulate(long arg) | ||
1108 | { | ||
1109 | printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n"); | ||
1110 | printk(KERN_EMERG "killing %s.\n",current->comm); | ||
1111 | force_sig(SIGFPE,current); | ||
1112 | schedule(); | ||
1113 | } | ||
1114 | |||
1115 | #endif /* CONFIG_MATH_EMULATION */ | ||
1116 | |||
1117 | #ifdef CONFIG_X86_F00F_BUG | ||
1118 | void __init trap_init_f00f_bug(void) | ||
1119 | { | ||
1120 | __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); | ||
1121 | |||
1122 | /* | ||
1123 | * Update the IDT descriptor and reload the IDT so that | ||
1124 | * it uses the read-only mapped virtual address. | ||
1125 | */ | ||
1126 | idt_descr.address = fix_to_virt(FIX_F00F_IDT); | ||
1127 | load_idt(&idt_descr); | ||
1128 | } | ||
1129 | #endif | ||
1130 | |||
1131 | /* | ||
1132 | * This needs to use 'idt_table' rather than 'idt', and | ||
1133 | * thus use the _nonmapped_ version of the IDT, as the | ||
1134 | * Pentium F0 0F bugfix can have resulted in the mapped | ||
1135 | * IDT being write-protected. | ||
1136 | */ | ||
1137 | void set_intr_gate(unsigned int n, void *addr) | ||
1138 | { | ||
1139 | _set_gate(n, DESCTYPE_INT, addr, __KERNEL_CS); | ||
1140 | } | ||
1141 | |||
1142 | /* | ||
1143 | * This routine sets up an interrupt gate at directory privilege level 3. | ||
1144 | */ | ||
1145 | static inline void set_system_intr_gate(unsigned int n, void *addr) | ||
1146 | { | ||
1147 | _set_gate(n, DESCTYPE_INT | DESCTYPE_DPL3, addr, __KERNEL_CS); | ||
1148 | } | ||
1149 | |||
1150 | static void __init set_trap_gate(unsigned int n, void *addr) | ||
1151 | { | ||
1152 | _set_gate(n, DESCTYPE_TRAP, addr, __KERNEL_CS); | ||
1153 | } | ||
1154 | |||
1155 | static void __init set_system_gate(unsigned int n, void *addr) | ||
1156 | { | ||
1157 | _set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS); | ||
1158 | } | ||
1159 | |||
1160 | static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) | ||
1161 | { | ||
1162 | _set_gate(n, DESCTYPE_TASK, (void *)0, (gdt_entry<<3)); | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | void __init trap_init(void) | ||
1167 | { | ||
1168 | #ifdef CONFIG_EISA | ||
1169 | void __iomem *p = ioremap(0x0FFFD9, 4); | ||
1170 | if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) { | ||
1171 | EISA_bus = 1; | ||
1172 | } | ||
1173 | iounmap(p); | ||
1174 | #endif | ||
1175 | |||
1176 | #ifdef CONFIG_X86_LOCAL_APIC | ||
1177 | init_apic_mappings(); | ||
1178 | #endif | ||
1179 | |||
1180 | set_trap_gate(0,÷_error); | ||
1181 | set_intr_gate(1,&debug); | ||
1182 | set_intr_gate(2,&nmi); | ||
1183 | set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ | ||
1184 | set_system_gate(4,&overflow); | ||
1185 | set_trap_gate(5,&bounds); | ||
1186 | set_trap_gate(6,&invalid_op); | ||
1187 | set_trap_gate(7,&device_not_available); | ||
1188 | set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS); | ||
1189 | set_trap_gate(9,&coprocessor_segment_overrun); | ||
1190 | set_trap_gate(10,&invalid_TSS); | ||
1191 | set_trap_gate(11,&segment_not_present); | ||
1192 | set_trap_gate(12,&stack_segment); | ||
1193 | set_trap_gate(13,&general_protection); | ||
1194 | set_intr_gate(14,&page_fault); | ||
1195 | set_trap_gate(15,&spurious_interrupt_bug); | ||
1196 | set_trap_gate(16,&coprocessor_error); | ||
1197 | set_trap_gate(17,&alignment_check); | ||
1198 | #ifdef CONFIG_X86_MCE | ||
1199 | set_trap_gate(18,&machine_check); | ||
1200 | #endif | ||
1201 | set_trap_gate(19,&simd_coprocessor_error); | ||
1202 | |||
1203 | if (cpu_has_fxsr) { | ||
1204 | /* | ||
1205 | * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. | ||
1206 | * Generates a compile-time "error: zero width for bit-field" if | ||
1207 | * the alignment is wrong. | ||
1208 | */ | ||
1209 | struct fxsrAlignAssert { | ||
1210 | int _:!(offsetof(struct task_struct, | ||
1211 | thread.i387.fxsave) & 15); | ||
1212 | }; | ||
1213 | |||
1214 | printk(KERN_INFO "Enabling fast FPU save and restore... "); | ||
1215 | set_in_cr4(X86_CR4_OSFXSR); | ||
1216 | printk("done.\n"); | ||
1217 | } | ||
1218 | if (cpu_has_xmm) { | ||
1219 | printk(KERN_INFO "Enabling unmasked SIMD FPU exception " | ||
1220 | "support... "); | ||
1221 | set_in_cr4(X86_CR4_OSXMMEXCPT); | ||
1222 | printk("done.\n"); | ||
1223 | } | ||
1224 | |||
1225 | set_system_gate(SYSCALL_VECTOR,&system_call); | ||
1226 | |||
1227 | /* | ||
1228 | * Should be a barrier for any external CPU state. | ||
1229 | */ | ||
1230 | cpu_init(); | ||
1231 | |||
1232 | trap_init_hook(); | ||
1233 | } | ||
1234 | |||
1235 | static int __init kstack_setup(char *s) | ||
1236 | { | ||
1237 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | ||
1238 | return 1; | ||
1239 | } | ||
1240 | __setup("kstack=", kstack_setup); | ||
1241 | |||
1242 | static int __init code_bytes_setup(char *s) | ||
1243 | { | ||
1244 | code_bytes = simple_strtoul(s, NULL, 0); | ||
1245 | if (code_bytes > 8192) | ||
1246 | code_bytes = 8192; | ||
1247 | |||
1248 | return 1; | ||
1249 | } | ||
1250 | __setup("code_bytes=", code_bytes_setup); | ||