Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | */ | |
1da177e4 LT |
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> | |
6e274d14 | 29 | #include <linux/kexec.h> |
176a2718 | 30 | #include <linux/unwind.h> |
1e2af92e | 31 | #include <linux/uaccess.h> |
1da177e4 LT |
32 | |
33 | #ifdef CONFIG_EISA | |
34 | #include <linux/ioport.h> | |
35 | #include <linux/eisa.h> | |
36 | #endif | |
37 | ||
38 | #ifdef CONFIG_MCA | |
39 | #include <linux/mca.h> | |
40 | #endif | |
41 | ||
42 | #include <asm/processor.h> | |
43 | #include <asm/system.h> | |
1da177e4 LT |
44 | #include <asm/io.h> |
45 | #include <asm/atomic.h> | |
46 | #include <asm/debugreg.h> | |
47 | #include <asm/desc.h> | |
48 | #include <asm/i387.h> | |
49 | #include <asm/nmi.h> | |
176a2718 | 50 | #include <asm/unwind.h> |
1da177e4 LT |
51 | #include <asm/smp.h> |
52 | #include <asm/arch_hooks.h> | |
53 | #include <asm/kdebug.h> | |
2b14a78c | 54 | #include <asm/stacktrace.h> |
1da177e4 | 55 | |
1da177e4 LT |
56 | #include <linux/module.h> |
57 | ||
58 | #include "mach_traps.h" | |
59 | ||
60 | asmlinkage int system_call(void); | |
61 | ||
62 | struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, | |
63 | { 0, 0 }, { 0, 0 } }; | |
64 | ||
65 | /* Do we ignore FPU interrupts ? */ | |
66 | char ignore_fpu_irq = 0; | |
67 | ||
68 | /* | |
69 | * The IDT has to be page-aligned to simplify the Pentium | |
70 | * F0 0F bug workaround.. We have a special link segment | |
71 | * for this. | |
72 | */ | |
73 | struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; | |
74 | ||
75 | asmlinkage void divide_error(void); | |
76 | asmlinkage void debug(void); | |
77 | asmlinkage void nmi(void); | |
78 | asmlinkage void int3(void); | |
79 | asmlinkage void overflow(void); | |
80 | asmlinkage void bounds(void); | |
81 | asmlinkage void invalid_op(void); | |
82 | asmlinkage void device_not_available(void); | |
83 | asmlinkage void coprocessor_segment_overrun(void); | |
84 | asmlinkage void invalid_TSS(void); | |
85 | asmlinkage void segment_not_present(void); | |
86 | asmlinkage void stack_segment(void); | |
87 | asmlinkage void general_protection(void); | |
88 | asmlinkage void page_fault(void); | |
89 | asmlinkage void coprocessor_error(void); | |
90 | asmlinkage void simd_coprocessor_error(void); | |
91 | asmlinkage void alignment_check(void); | |
92 | asmlinkage void spurious_interrupt_bug(void); | |
93 | asmlinkage void machine_check(void); | |
94 | ||
95 | static int kstack_depth_to_print = 24; | |
ea424055 | 96 | #ifdef CONFIG_STACK_UNWIND |
c33bd9aa | 97 | static int call_trace = 1; |
ea424055 JB |
98 | #else |
99 | #define call_trace (-1) | |
100 | #endif | |
e041c683 | 101 | ATOMIC_NOTIFIER_HEAD(i386die_chain); |
1da177e4 LT |
102 | |
103 | int register_die_notifier(struct notifier_block *nb) | |
104 | { | |
101f12af | 105 | vmalloc_sync_all(); |
e041c683 | 106 | return atomic_notifier_chain_register(&i386die_chain, nb); |
1da177e4 | 107 | } |
1454aed9 | 108 | EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ |
1da177e4 | 109 | |
e041c683 AS |
110 | int unregister_die_notifier(struct notifier_block *nb) |
111 | { | |
112 | return atomic_notifier_chain_unregister(&i386die_chain, nb); | |
113 | } | |
1454aed9 | 114 | EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ |
e041c683 | 115 | |
1da177e4 LT |
116 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) |
117 | { | |
118 | return p > (void *)tinfo && | |
119 | p < (void *)tinfo + THREAD_SIZE - 3; | |
120 | } | |
121 | ||
122 | static inline unsigned long print_context_stack(struct thread_info *tinfo, | |
7aa89746 | 123 | unsigned long *stack, unsigned long ebp, |
2b14a78c | 124 | struct stacktrace_ops *ops, void *data) |
1da177e4 LT |
125 | { |
126 | unsigned long addr; | |
127 | ||
128 | #ifdef CONFIG_FRAME_POINTER | |
129 | while (valid_stack_ptr(tinfo, (void *)ebp)) { | |
130 | addr = *(unsigned long *)(ebp + 4); | |
2b14a78c | 131 | ops->address(data, addr); |
b88d4f1d IM |
132 | /* |
133 | * break out of recursive entries (such as | |
134 | * end_of_stack_stop_unwind_function): | |
135 | */ | |
136 | if (ebp == *(unsigned long *)ebp) | |
137 | break; | |
1da177e4 LT |
138 | ebp = *(unsigned long *)ebp; |
139 | } | |
140 | #else | |
141 | while (valid_stack_ptr(tinfo, stack)) { | |
142 | addr = *stack++; | |
7aa89746 | 143 | if (__kernel_text_address(addr)) |
2b14a78c | 144 | ops->address(data, addr); |
1da177e4 LT |
145 | } |
146 | #endif | |
147 | return ebp; | |
148 | } | |
149 | ||
2b14a78c AK |
150 | struct ops_and_data { |
151 | struct stacktrace_ops *ops; | |
152 | void *data; | |
153 | }; | |
154 | ||
f0a5c315 | 155 | static asmlinkage int |
2b14a78c | 156 | dump_trace_unwind(struct unwind_frame_info *info, void *data) |
176a2718 | 157 | { |
2b14a78c | 158 | struct ops_and_data *oad = (struct ops_and_data *)data; |
c33bd9aa | 159 | int n = 0; |
176a2718 JB |
160 | |
161 | while (unwind(info) == 0 && UNW_PC(info)) { | |
f0a5c315 | 162 | n++; |
2b14a78c | 163 | oad->ops->address(oad->data, UNW_PC(info)); |
176a2718 JB |
164 | if (arch_unw_user_mode(info)) |
165 | break; | |
166 | } | |
c33bd9aa | 167 | return n; |
176a2718 JB |
168 | } |
169 | ||
2b14a78c AK |
170 | void dump_trace(struct task_struct *task, struct pt_regs *regs, |
171 | unsigned long *stack, | |
172 | struct stacktrace_ops *ops, void *data) | |
1da177e4 | 173 | { |
a32cf397 | 174 | unsigned long ebp = 0; |
1da177e4 LT |
175 | |
176 | if (!task) | |
177 | task = current; | |
178 | ||
c33bd9aa JB |
179 | if (call_trace >= 0) { |
180 | int unw_ret = 0; | |
181 | struct unwind_frame_info info; | |
2b14a78c | 182 | struct ops_and_data oad = { .ops = ops, .data = data }; |
c33bd9aa JB |
183 | |
184 | if (regs) { | |
185 | if (unwind_init_frame_info(&info, task, regs) == 0) | |
2b14a78c | 186 | unw_ret = dump_trace_unwind(&info, &oad); |
c33bd9aa | 187 | } else if (task == current) |
2b14a78c | 188 | unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); |
c33bd9aa JB |
189 | else { |
190 | if (unwind_init_blocked(&info, task) == 0) | |
2b14a78c | 191 | unw_ret = dump_trace_unwind(&info, &oad); |
176a2718 | 192 | } |
ea424055 JB |
193 | if (unw_ret > 0) { |
194 | if (call_trace == 1 && !arch_unw_user_mode(&info)) { | |
2b14a78c | 195 | ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", |
ea424055 JB |
196 | UNW_PC(&info)); |
197 | if (UNW_SP(&info) >= PAGE_OFFSET) { | |
2b14a78c | 198 | ops->warning(data, "Leftover inexact backtrace:\n"); |
70583161 | 199 | stack = (void *)UNW_SP(&info); |
950fee84 AK |
200 | if (!stack) |
201 | return; | |
a32cf397 | 202 | ebp = UNW_FP(&info); |
ea424055 | 203 | } else |
2b14a78c | 204 | ops->warning(data, "Full inexact backtrace again:\n"); |
ea424055 | 205 | } else if (call_trace >= 1) |
c33bd9aa | 206 | return; |
c97d20a6 | 207 | else |
2b14a78c | 208 | ops->warning(data, "Full inexact backtrace again:\n"); |
ea424055 | 209 | } else |
2b14a78c | 210 | ops->warning(data, "Inexact backtrace:\n"); |
a32cf397 AK |
211 | } |
212 | if (!stack) { | |
2b14a78c AK |
213 | unsigned long dummy; |
214 | stack = &dummy; | |
215 | if (task && task != current) | |
216 | stack = (unsigned long *)task->thread.esp; | |
176a2718 JB |
217 | } |
218 | ||
a32cf397 AK |
219 | #ifdef CONFIG_FRAME_POINTER |
220 | if (!ebp) { | |
221 | if (task == current) { | |
222 | /* Grab ebp right from our regs */ | |
223 | asm ("movl %%ebp, %0" : "=r" (ebp) : ); | |
224 | } else { | |
225 | /* ebp is the last reg pushed by switch_to */ | |
226 | ebp = *(unsigned long *) task->thread.esp; | |
227 | } | |
1da177e4 | 228 | } |
a32cf397 | 229 | #endif |
1da177e4 LT |
230 | |
231 | while (1) { | |
232 | struct thread_info *context; | |
233 | context = (struct thread_info *) | |
234 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | |
2b14a78c AK |
235 | ebp = print_context_stack(context, stack, ebp, ops, data); |
236 | /* Should be after the line below, but somewhere | |
237 | in early boot context comes out corrupted and we | |
238 | can't reference it -AK */ | |
239 | if (ops->stack(data, "IRQ") < 0) | |
240 | break; | |
1da177e4 LT |
241 | stack = (unsigned long*)context->previous_esp; |
242 | if (!stack) | |
243 | break; | |
1da177e4 LT |
244 | } |
245 | } | |
2b14a78c AK |
246 | EXPORT_SYMBOL(dump_trace); |
247 | ||
248 | static void | |
249 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | |
250 | { | |
251 | printk(data); | |
252 | print_symbol(msg, symbol); | |
253 | printk("\n"); | |
254 | } | |
255 | ||
256 | static void print_trace_warning(void *data, char *msg) | |
257 | { | |
258 | printk("%s%s\n", (char *)data, msg); | |
259 | } | |
260 | ||
261 | static int print_trace_stack(void *data, char *name) | |
262 | { | |
263 | return 0; | |
264 | } | |
265 | ||
266 | /* | |
267 | * Print one address/symbol entries per line. | |
268 | */ | |
269 | static void print_trace_address(void *data, unsigned long addr) | |
270 | { | |
271 | printk("%s [<%08lx>] ", (char *)data, addr); | |
272 | print_symbol("%s\n", addr); | |
273 | } | |
274 | ||
275 | static struct stacktrace_ops print_trace_ops = { | |
276 | .warning = print_trace_warning, | |
277 | .warning_symbol = print_trace_warning_symbol, | |
278 | .stack = print_trace_stack, | |
279 | .address = print_trace_address, | |
280 | }; | |
281 | ||
282 | static void | |
283 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | |
284 | unsigned long * stack, char *log_lvl) | |
285 | { | |
286 | dump_trace(task, regs, stack, &print_trace_ops, log_lvl); | |
287 | printk("%s =======================\n", log_lvl); | |
288 | } | |
1da177e4 | 289 | |
2b14a78c AK |
290 | void show_trace(struct task_struct *task, struct pt_regs *regs, |
291 | unsigned long * stack) | |
7aa89746 | 292 | { |
176a2718 | 293 | show_trace_log_lvl(task, regs, stack, ""); |
7aa89746 CE |
294 | } |
295 | ||
176a2718 JB |
296 | static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
297 | unsigned long *esp, char *log_lvl) | |
1da177e4 LT |
298 | { |
299 | unsigned long *stack; | |
300 | int i; | |
301 | ||
302 | if (esp == NULL) { | |
303 | if (task) | |
304 | esp = (unsigned long*)task->thread.esp; | |
305 | else | |
306 | esp = (unsigned long *)&esp; | |
307 | } | |
308 | ||
309 | stack = esp; | |
310 | for(i = 0; i < kstack_depth_to_print; i++) { | |
311 | if (kstack_end(stack)) | |
312 | break; | |
75874d5c CE |
313 | if (i && ((i % 8) == 0)) |
314 | printk("\n%s ", log_lvl); | |
1da177e4 LT |
315 | printk("%08lx ", *stack++); |
316 | } | |
75874d5c | 317 | printk("\n%sCall Trace:\n", log_lvl); |
176a2718 | 318 | show_trace_log_lvl(task, regs, esp, log_lvl); |
7aa89746 CE |
319 | } |
320 | ||
321 | void show_stack(struct task_struct *task, unsigned long *esp) | |
322 | { | |
75874d5c | 323 | printk(" "); |
176a2718 | 324 | show_stack_log_lvl(task, NULL, esp, ""); |
1da177e4 LT |
325 | } |
326 | ||
327 | /* | |
328 | * The architecture-independent dump_stack generator | |
329 | */ | |
330 | void dump_stack(void) | |
331 | { | |
332 | unsigned long stack; | |
333 | ||
176a2718 | 334 | show_trace(current, NULL, &stack); |
1da177e4 LT |
335 | } |
336 | ||
337 | EXPORT_SYMBOL(dump_stack); | |
338 | ||
339 | void show_registers(struct pt_regs *regs) | |
340 | { | |
341 | int i; | |
342 | int in_kernel = 1; | |
343 | unsigned long esp; | |
344 | unsigned short ss; | |
345 | ||
346 | esp = (unsigned long) (®s->esp); | |
0998e422 | 347 | savesegment(ss, ss); |
db753bdf | 348 | if (user_mode_vm(regs)) { |
1da177e4 LT |
349 | in_kernel = 0; |
350 | esp = regs->esp; | |
351 | ss = regs->xss & 0xffff; | |
352 | } | |
353 | print_modules(); | |
f354b3a9 DJ |
354 | printk(KERN_EMERG "CPU: %d\n" |
355 | KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n" | |
356 | KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n", | |
1da177e4 | 357 | smp_processor_id(), 0xffff & regs->xcs, regs->eip, |
b53e8f68 CE |
358 | print_tainted(), regs->eflags, system_utsname.release, |
359 | (int)strcspn(system_utsname.version, " "), | |
360 | system_utsname.version); | |
9c107805 DJ |
361 | print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); |
362 | printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", | |
1da177e4 | 363 | regs->eax, regs->ebx, regs->ecx, regs->edx); |
9c107805 | 364 | printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", |
1da177e4 | 365 | regs->esi, regs->edi, regs->ebp, esp); |
9c107805 | 366 | printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", |
1da177e4 | 367 | regs->xds & 0xffff, regs->xes & 0xffff, ss); |
7e04a118 CE |
368 | printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", |
369 | TASK_COMM_LEN, current->comm, current->pid, | |
370 | current_thread_info(), current, current->thread_info); | |
1da177e4 LT |
371 | /* |
372 | * When in-kernel, we also print out the stack and code at the | |
373 | * time of the fault.. | |
374 | */ | |
375 | if (in_kernel) { | |
3f3ae347 | 376 | u8 __user *eip; |
99325326 CE |
377 | int code_bytes = 64; |
378 | unsigned char c; | |
1da177e4 | 379 | |
9c107805 | 380 | printk("\n" KERN_EMERG "Stack: "); |
176a2718 | 381 | show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); |
1da177e4 | 382 | |
9c107805 | 383 | printk(KERN_EMERG "Code: "); |
1da177e4 | 384 | |
3f3ae347 | 385 | eip = (u8 __user *)regs->eip - 43; |
99325326 CE |
386 | if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { |
387 | /* try starting at EIP */ | |
388 | eip = (u8 __user *)regs->eip; | |
389 | code_bytes = 32; | |
390 | } | |
391 | for (i = 0; i < code_bytes; i++, eip++) { | |
3f3ae347 | 392 | if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { |
1da177e4 LT |
393 | printk(" Bad EIP value."); |
394 | break; | |
395 | } | |
3f3ae347 | 396 | if (eip == (u8 __user *)regs->eip) |
1da177e4 LT |
397 | printk("<%02x> ", c); |
398 | else | |
399 | printk("%02x ", c); | |
400 | } | |
401 | } | |
402 | printk("\n"); | |
403 | } | |
404 | ||
405 | static void handle_BUG(struct pt_regs *regs) | |
406 | { | |
b7015331 | 407 | unsigned long eip = regs->eip; |
1da177e4 | 408 | unsigned short ud2; |
1da177e4 LT |
409 | |
410 | if (eip < PAGE_OFFSET) | |
b7015331 | 411 | return; |
1e2af92e | 412 | if (probe_kernel_address((unsigned short __user *)eip, ud2)) |
b7015331 | 413 | return; |
1da177e4 | 414 | if (ud2 != 0x0b0f) |
b7015331 | 415 | return; |
1da177e4 | 416 | |
9c107805 | 417 | printk(KERN_EMERG "------------[ cut here ]------------\n"); |
1da177e4 | 418 | |
b7015331 CE |
419 | #ifdef CONFIG_DEBUG_BUGVERBOSE |
420 | do { | |
421 | unsigned short line; | |
422 | char *file; | |
423 | char c; | |
424 | ||
1e2af92e AM |
425 | if (probe_kernel_address((unsigned short __user *)(eip + 2), |
426 | line)) | |
b7015331 CE |
427 | break; |
428 | if (__get_user(file, (char * __user *)(eip + 4)) || | |
429 | (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) | |
430 | file = "<bad filename>"; | |
1da177e4 | 431 | |
b7015331 CE |
432 | printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); |
433 | return; | |
434 | } while (0); | |
435 | #endif | |
436 | printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n"); | |
1da177e4 LT |
437 | } |
438 | ||
6e274d14 AN |
439 | /* This is gone through when something in the kernel |
440 | * has done something bad and is about to be terminated. | |
441 | */ | |
1da177e4 LT |
442 | void die(const char * str, struct pt_regs * regs, long err) |
443 | { | |
444 | static struct { | |
445 | spinlock_t lock; | |
446 | u32 lock_owner; | |
447 | int lock_owner_depth; | |
448 | } die = { | |
449 | .lock = SPIN_LOCK_UNLOCKED, | |
450 | .lock_owner = -1, | |
451 | .lock_owner_depth = 0 | |
452 | }; | |
453 | static int die_counter; | |
e43d674f | 454 | unsigned long flags; |
1da177e4 | 455 | |
dd287796 AM |
456 | oops_enter(); |
457 | ||
39c715b7 | 458 | if (die.lock_owner != raw_smp_processor_id()) { |
1da177e4 | 459 | console_verbose(); |
e43d674f | 460 | spin_lock_irqsave(&die.lock, flags); |
1da177e4 LT |
461 | die.lock_owner = smp_processor_id(); |
462 | die.lock_owner_depth = 0; | |
463 | bust_spinlocks(1); | |
464 | } | |
e43d674f JB |
465 | else |
466 | local_save_flags(flags); | |
1da177e4 LT |
467 | |
468 | if (++die.lock_owner_depth < 3) { | |
469 | int nl = 0; | |
7bee5c0f RD |
470 | unsigned long esp; |
471 | unsigned short ss; | |
472 | ||
1da177e4 | 473 | handle_BUG(regs); |
9c107805 | 474 | printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); |
1da177e4 | 475 | #ifdef CONFIG_PREEMPT |
9c107805 | 476 | printk(KERN_EMERG "PREEMPT "); |
1da177e4 LT |
477 | nl = 1; |
478 | #endif | |
479 | #ifdef CONFIG_SMP | |
9c107805 DJ |
480 | if (!nl) |
481 | printk(KERN_EMERG); | |
1da177e4 LT |
482 | printk("SMP "); |
483 | nl = 1; | |
484 | #endif | |
485 | #ifdef CONFIG_DEBUG_PAGEALLOC | |
9c107805 DJ |
486 | if (!nl) |
487 | printk(KERN_EMERG); | |
1da177e4 LT |
488 | printk("DEBUG_PAGEALLOC"); |
489 | nl = 1; | |
490 | #endif | |
491 | if (nl) | |
492 | printk("\n"); | |
20c0d2d4 JB |
493 | if (notify_die(DIE_OOPS, str, regs, err, |
494 | current->thread.trap_no, SIGSEGV) != | |
7bee5c0f | 495 | NOTIFY_STOP) { |
20c0d2d4 | 496 | show_registers(regs); |
7bee5c0f RD |
497 | /* Executive summary in case the oops scrolled away */ |
498 | esp = (unsigned long) (®s->esp); | |
499 | savesegment(ss, ss); | |
500 | if (user_mode(regs)) { | |
501 | esp = regs->esp; | |
502 | ss = regs->xss & 0xffff; | |
503 | } | |
504 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip); | |
505 | print_symbol("%s", regs->eip); | |
506 | printk(" SS:ESP %04x:%08lx\n", ss, esp); | |
507 | } | |
20c0d2d4 JB |
508 | else |
509 | regs = NULL; | |
1da177e4 | 510 | } else |
9c107805 | 511 | printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); |
1da177e4 LT |
512 | |
513 | bust_spinlocks(0); | |
514 | die.lock_owner = -1; | |
e43d674f | 515 | spin_unlock_irqrestore(&die.lock, flags); |
6e274d14 | 516 | |
20c0d2d4 JB |
517 | if (!regs) |
518 | return; | |
519 | ||
6e274d14 AN |
520 | if (kexec_should_crash(current)) |
521 | crash_kexec(regs); | |
522 | ||
1da177e4 LT |
523 | if (in_interrupt()) |
524 | panic("Fatal exception in interrupt"); | |
525 | ||
cea6a4ba | 526 | if (panic_on_oops) |
012c437d | 527 | panic("Fatal exception"); |
cea6a4ba | 528 | |
dd287796 | 529 | oops_exit(); |
1da177e4 LT |
530 | do_exit(SIGSEGV); |
531 | } | |
532 | ||
533 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | |
534 | { | |
717b594a | 535 | if (!user_mode_vm(regs)) |
1da177e4 LT |
536 | die(str, regs, err); |
537 | } | |
538 | ||
3d97ae5b PP |
539 | static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, |
540 | struct pt_regs * regs, long error_code, | |
541 | siginfo_t *info) | |
1da177e4 | 542 | { |
4f339ecb AN |
543 | struct task_struct *tsk = current; |
544 | tsk->thread.error_code = error_code; | |
545 | tsk->thread.trap_no = trapnr; | |
546 | ||
1da177e4 LT |
547 | if (regs->eflags & VM_MASK) { |
548 | if (vm86) | |
549 | goto vm86_trap; | |
550 | goto trap_signal; | |
551 | } | |
552 | ||
717b594a | 553 | if (!user_mode(regs)) |
1da177e4 LT |
554 | goto kernel_trap; |
555 | ||
556 | trap_signal: { | |
1da177e4 LT |
557 | if (info) |
558 | force_sig_info(signr, info, tsk); | |
559 | else | |
560 | force_sig(signr, tsk); | |
561 | return; | |
562 | } | |
563 | ||
564 | kernel_trap: { | |
565 | if (!fixup_exception(regs)) | |
566 | die(str, regs, error_code); | |
567 | return; | |
568 | } | |
569 | ||
570 | vm86_trap: { | |
571 | int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); | |
572 | if (ret) goto trap_signal; | |
573 | return; | |
574 | } | |
575 | } | |
576 | ||
577 | #define DO_ERROR(trapnr, signr, str, name) \ | |
578 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | |
579 | { \ | |
580 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | |
581 | == NOTIFY_STOP) \ | |
582 | return; \ | |
583 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ | |
584 | } | |
585 | ||
586 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | |
587 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | |
588 | { \ | |
589 | siginfo_t info; \ | |
590 | info.si_signo = signr; \ | |
591 | info.si_errno = 0; \ | |
592 | info.si_code = sicode; \ | |
593 | info.si_addr = (void __user *)siaddr; \ | |
594 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | |
595 | == NOTIFY_STOP) \ | |
596 | return; \ | |
597 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ | |
598 | } | |
599 | ||
600 | #define DO_VM86_ERROR(trapnr, signr, str, name) \ | |
601 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | |
602 | { \ | |
603 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | |
604 | == NOTIFY_STOP) \ | |
605 | return; \ | |
606 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ | |
607 | } | |
608 | ||
609 | #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | |
610 | fastcall void do_##name(struct pt_regs * regs, long error_code) \ | |
611 | { \ | |
612 | siginfo_t info; \ | |
613 | info.si_signo = signr; \ | |
614 | info.si_errno = 0; \ | |
615 | info.si_code = sicode; \ | |
616 | info.si_addr = (void __user *)siaddr; \ | |
617 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | |
618 | == NOTIFY_STOP) \ | |
619 | return; \ | |
620 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ | |
621 | } | |
622 | ||
623 | DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) | |
624 | #ifndef CONFIG_KPROBES | |
625 | DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) | |
626 | #endif | |
627 | DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) | |
628 | DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) | |
631b0347 | 629 | DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip) |
1da177e4 LT |
630 | DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) |
631 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | |
632 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | |
633 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | |
634 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) | |
a879cbbb | 635 | DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) |
1da177e4 | 636 | |
3d97ae5b PP |
637 | fastcall void __kprobes do_general_protection(struct pt_regs * regs, |
638 | long error_code) | |
1da177e4 LT |
639 | { |
640 | int cpu = get_cpu(); | |
641 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | |
642 | struct thread_struct *thread = ¤t->thread; | |
643 | ||
644 | /* | |
645 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an | |
646 | * invalid offset set (the LAZY one) and the faulting thread has | |
647 | * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS | |
648 | * and we set the offset field correctly. Then we let the CPU to | |
649 | * restart the faulting instruction. | |
650 | */ | |
651 | if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && | |
652 | thread->io_bitmap_ptr) { | |
653 | memcpy(tss->io_bitmap, thread->io_bitmap_ptr, | |
654 | thread->io_bitmap_max); | |
655 | /* | |
656 | * If the previously set map was extending to higher ports | |
657 | * than the current one, pad extra space with 0xff (no access). | |
658 | */ | |
659 | if (thread->io_bitmap_max < tss->io_bitmap_max) | |
660 | memset((char *) tss->io_bitmap + | |
661 | thread->io_bitmap_max, 0xff, | |
662 | tss->io_bitmap_max - thread->io_bitmap_max); | |
663 | tss->io_bitmap_max = thread->io_bitmap_max; | |
664 | tss->io_bitmap_base = IO_BITMAP_OFFSET; | |
d5cd4aad | 665 | tss->io_bitmap_owner = thread; |
1da177e4 LT |
666 | put_cpu(); |
667 | return; | |
668 | } | |
669 | put_cpu(); | |
670 | ||
4f339ecb AN |
671 | current->thread.error_code = error_code; |
672 | current->thread.trap_no = 13; | |
673 | ||
1da177e4 LT |
674 | if (regs->eflags & VM_MASK) |
675 | goto gp_in_vm86; | |
676 | ||
717b594a | 677 | if (!user_mode(regs)) |
1da177e4 LT |
678 | goto gp_in_kernel; |
679 | ||
680 | current->thread.error_code = error_code; | |
681 | current->thread.trap_no = 13; | |
682 | force_sig(SIGSEGV, current); | |
683 | return; | |
684 | ||
685 | gp_in_vm86: | |
686 | local_irq_enable(); | |
687 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | |
688 | return; | |
689 | ||
690 | gp_in_kernel: | |
691 | if (!fixup_exception(regs)) { | |
692 | if (notify_die(DIE_GPF, "general protection fault", regs, | |
693 | error_code, 13, SIGSEGV) == NOTIFY_STOP) | |
694 | return; | |
695 | die("general protection fault", regs, error_code); | |
696 | } | |
697 | } | |
698 | ||