diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-02-26 05:15:50 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-04-17 11:40:51 -0400 |
commit | b5964405fbc4fd4c57e0e1f86bc9f1b3dbfa040a (patch) | |
tree | 8cb6205cf11f150251e81cb95d59c010bd717ced /arch/x86 | |
parent | 10cd5a1e5403d79a2d53425e6a4c8612e02ba973 (diff) |
x86: clean up traps_32.c
Before:
total: 86 errors, 29 warnings, 1248 lines checked
After:
total: 0 errors, 17 warnings, 1281 lines checked
No code changed:
arch/x86/kernel/traps_32.o:
text data bss dec hex filename
8711 2168 72 10951 2ac7 traps_32.o.before
8711 2168 72 10951 2ac7 traps_32.o.after
(md5 sums differ because some stack offset positions changed.)
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/traps_32.c | 604 |
1 files changed, 318 insertions, 286 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index b22c01e05a18..57a5704e3f6c 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -9,26 +9,28 @@ | |||
9 | * 'Traps.c' handles hardware traps and faults after we have saved some | 9 | * 'Traps.c' handles hardware traps and faults after we have saved some |
10 | * state in 'asm.s'. | 10 | * state in 'asm.s'. |
11 | */ | 11 | */ |
12 | #include <linux/sched.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/kallsyms.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/highmem.h> | ||
16 | #include <linux/kprobes.h> | ||
17 | #include <linux/uaccess.h> | ||
18 | #include <linux/utsname.h> | ||
19 | #include <linux/kdebug.h> | ||
13 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/module.h> | ||
22 | #include <linux/ptrace.h> | ||
14 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/unwind.h> | ||
25 | #include <linux/delay.h> | ||
15 | #include <linux/errno.h> | 26 | #include <linux/errno.h> |
27 | #include <linux/kexec.h> | ||
28 | #include <linux/sched.h> | ||
16 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
17 | #include <linux/mm.h> | ||
18 | #include <linux/init.h> | 30 | #include <linux/init.h> |
19 | #include <linux/delay.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/highmem.h> | ||
23 | #include <linux/kallsyms.h> | ||
24 | #include <linux/ptrace.h> | ||
25 | #include <linux/utsname.h> | ||
26 | #include <linux/kprobes.h> | ||
27 | #include <linux/kexec.h> | ||
28 | #include <linux/unwind.h> | ||
29 | #include <linux/uaccess.h> | ||
30 | #include <linux/nmi.h> | ||
31 | #include <linux/bug.h> | 31 | #include <linux/bug.h> |
32 | #include <linux/nmi.h> | ||
33 | #include <linux/mm.h> | ||
32 | 34 | ||
33 | #ifdef CONFIG_EISA | 35 | #ifdef CONFIG_EISA |
34 | #include <linux/ioport.h> | 36 | #include <linux/ioport.h> |
@@ -43,21 +45,18 @@ | |||
43 | #include <linux/edac.h> | 45 | #include <linux/edac.h> |
44 | #endif | 46 | #endif |
45 | 47 | ||
48 | #include <asm/arch_hooks.h> | ||
49 | #include <asm/stacktrace.h> | ||
46 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
47 | #include <asm/system.h> | ||
48 | #include <asm/io.h> | ||
49 | #include <asm/atomic.h> | ||
50 | #include <asm/debugreg.h> | 51 | #include <asm/debugreg.h> |
52 | #include <asm/atomic.h> | ||
53 | #include <asm/system.h> | ||
54 | #include <asm/unwind.h> | ||
51 | #include <asm/desc.h> | 55 | #include <asm/desc.h> |
52 | #include <asm/i387.h> | 56 | #include <asm/i387.h> |
53 | #include <asm/nmi.h> | 57 | #include <asm/nmi.h> |
54 | #include <asm/unwind.h> | ||
55 | #include <asm/smp.h> | 58 | #include <asm/smp.h> |
56 | #include <asm/arch_hooks.h> | 59 | #include <asm/io.h> |
57 | #include <linux/kdebug.h> | ||
58 | #include <asm/stacktrace.h> | ||
59 | |||
60 | #include <linux/module.h> | ||
61 | 60 | ||
62 | #include "mach_traps.h" | 61 | #include "mach_traps.h" |
63 | 62 | ||
@@ -69,7 +68,7 @@ EXPORT_SYMBOL_GPL(used_vectors); | |||
69 | asmlinkage int system_call(void); | 68 | asmlinkage int system_call(void); |
70 | 69 | ||
71 | /* Do we ignore FPU interrupts ? */ | 70 | /* Do we ignore FPU interrupts ? */ |
72 | char ignore_fpu_irq = 0; | 71 | char ignore_fpu_irq; |
73 | 72 | ||
74 | /* | 73 | /* |
75 | * The IDT has to be page-aligned to simplify the Pentium | 74 | * The IDT has to be page-aligned to simplify the Pentium |
@@ -105,12 +104,13 @@ static unsigned int code_bytes = 64; | |||
105 | void printk_address(unsigned long address, int reliable) | 104 | void printk_address(unsigned long address, int reliable) |
106 | { | 105 | { |
107 | #ifdef CONFIG_KALLSYMS | 106 | #ifdef CONFIG_KALLSYMS |
108 | unsigned long offset = 0, symsize; | 107 | char namebuf[KSYM_NAME_LEN]; |
108 | unsigned long offset = 0; | ||
109 | unsigned long symsize; | ||
109 | const char *symname; | 110 | const char *symname; |
110 | char *modname; | ||
111 | char *delim = ":"; | ||
112 | char namebuf[128]; | ||
113 | char reliab[4] = ""; | 111 | char reliab[4] = ""; |
112 | char *delim = ":"; | ||
113 | char *modname; | ||
114 | 114 | ||
115 | symname = kallsyms_lookup(address, &symsize, &offset, | 115 | symname = kallsyms_lookup(address, &symsize, &offset, |
116 | &modname, namebuf); | 116 | &modname, namebuf); |
@@ -138,13 +138,14 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned s | |||
138 | 138 | ||
139 | /* The form of the top of the frame on the stack */ | 139 | /* The form of the top of the frame on the stack */ |
140 | struct stack_frame { | 140 | struct stack_frame { |
141 | struct stack_frame *next_frame; | 141 | struct stack_frame *next_frame; |
142 | unsigned long return_address; | 142 | unsigned long return_address; |
143 | }; | 143 | }; |
144 | 144 | ||
145 | static inline unsigned long print_context_stack(struct thread_info *tinfo, | 145 | static inline unsigned long |
146 | unsigned long *stack, unsigned long bp, | 146 | print_context_stack(struct thread_info *tinfo, |
147 | const struct stacktrace_ops *ops, void *data) | 147 | unsigned long *stack, unsigned long bp, |
148 | const struct stacktrace_ops *ops, void *data) | ||
148 | { | 149 | { |
149 | struct stack_frame *frame = (struct stack_frame *)bp; | 150 | struct stack_frame *frame = (struct stack_frame *)bp; |
150 | 151 | ||
@@ -166,7 +167,7 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
166 | return bp; | 167 | return bp; |
167 | } | 168 | } |
168 | 169 | ||
169 | #define MSG(msg) ops->warning(data, msg) | 170 | #define MSG(msg) ops->warning(data, msg) |
170 | 171 | ||
171 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 172 | void dump_trace(struct task_struct *task, struct pt_regs *regs, |
172 | unsigned long *stack, unsigned long bp, | 173 | unsigned long *stack, unsigned long bp, |
@@ -177,6 +178,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
177 | 178 | ||
178 | if (!stack) { | 179 | if (!stack) { |
179 | unsigned long dummy; | 180 | unsigned long dummy; |
181 | |||
180 | stack = &dummy; | 182 | stack = &dummy; |
181 | if (task != current) | 183 | if (task != current) |
182 | stack = (unsigned long *)task->thread.sp; | 184 | stack = (unsigned long *)task->thread.sp; |
@@ -186,7 +188,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
186 | if (!bp) { | 188 | if (!bp) { |
187 | if (task == current) { | 189 | if (task == current) { |
188 | /* Grab bp right from our regs */ | 190 | /* Grab bp right from our regs */ |
189 | asm ("movl %%ebp, %0" : "=r" (bp) : ); | 191 | asm("movl %%ebp, %0" : "=r" (bp) :); |
190 | } else { | 192 | } else { |
191 | /* bp is the last reg pushed by switch_to */ | 193 | /* bp is the last reg pushed by switch_to */ |
192 | bp = *(unsigned long *) task->thread.sp; | 194 | bp = *(unsigned long *) task->thread.sp; |
@@ -196,15 +198,18 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
196 | 198 | ||
197 | while (1) { | 199 | while (1) { |
198 | struct thread_info *context; | 200 | struct thread_info *context; |
201 | |||
199 | context = (struct thread_info *) | 202 | context = (struct thread_info *) |
200 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); | 203 | ((unsigned long)stack & (~(THREAD_SIZE - 1))); |
201 | bp = print_context_stack(context, stack, bp, ops, data); | 204 | bp = print_context_stack(context, stack, bp, ops, data); |
202 | /* Should be after the line below, but somewhere | 205 | /* |
203 | in early boot context comes out corrupted and we | 206 | * Should be after the line below, but somewhere |
204 | can't reference it -AK */ | 207 | * in early boot context comes out corrupted and we |
208 | * can't reference it: | ||
209 | */ | ||
205 | if (ops->stack(data, "IRQ") < 0) | 210 | if (ops->stack(data, "IRQ") < 0) |
206 | break; | 211 | break; |
207 | stack = (unsigned long*)context->previous_esp; | 212 | stack = (unsigned long *)context->previous_esp; |
208 | if (!stack) | 213 | if (!stack) |
209 | break; | 214 | break; |
210 | touch_nmi_watchdog(); | 215 | touch_nmi_watchdog(); |
@@ -243,15 +248,15 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) | |||
243 | } | 248 | } |
244 | 249 | ||
245 | static const struct stacktrace_ops print_trace_ops = { | 250 | static const struct stacktrace_ops print_trace_ops = { |
246 | .warning = print_trace_warning, | 251 | .warning = print_trace_warning, |
247 | .warning_symbol = print_trace_warning_symbol, | 252 | .warning_symbol = print_trace_warning_symbol, |
248 | .stack = print_trace_stack, | 253 | .stack = print_trace_stack, |
249 | .address = print_trace_address, | 254 | .address = print_trace_address, |
250 | }; | 255 | }; |
251 | 256 | ||
252 | static void | 257 | static void |
253 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 258 | show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, |
254 | unsigned long *stack, unsigned long bp, char *log_lvl) | 259 | unsigned long *stack, unsigned long bp, char *log_lvl) |
255 | { | 260 | { |
256 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); | 261 | dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl); |
257 | printk("%s =======================\n", log_lvl); | 262 | printk("%s =======================\n", log_lvl); |
@@ -263,21 +268,22 @@ void show_trace(struct task_struct *task, struct pt_regs *regs, | |||
263 | show_trace_log_lvl(task, regs, stack, bp, ""); | 268 | show_trace_log_lvl(task, regs, stack, bp, ""); |
264 | } | 269 | } |
265 | 270 | ||
266 | static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | 271 | static void |
267 | unsigned long *sp, unsigned long bp, char *log_lvl) | 272 | show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
273 | unsigned long *sp, unsigned long bp, char *log_lvl) | ||
268 | { | 274 | { |
269 | unsigned long *stack; | 275 | unsigned long *stack; |
270 | int i; | 276 | int i; |
271 | 277 | ||
272 | if (sp == NULL) { | 278 | if (sp == NULL) { |
273 | if (task) | 279 | if (task) |
274 | sp = (unsigned long*)task->thread.sp; | 280 | sp = (unsigned long *)task->thread.sp; |
275 | else | 281 | else |
276 | sp = (unsigned long *)&sp; | 282 | sp = (unsigned long *)&sp; |
277 | } | 283 | } |
278 | 284 | ||
279 | stack = sp; | 285 | stack = sp; |
280 | for(i = 0; i < kstack_depth_to_print; i++) { | 286 | for (i = 0; i < kstack_depth_to_print; i++) { |
281 | if (kstack_end(stack)) | 287 | if (kstack_end(stack)) |
282 | break; | 288 | break; |
283 | if (i && ((i % 8) == 0)) | 289 | if (i && ((i % 8) == 0)) |
@@ -285,6 +291,7 @@ static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, | |||
285 | printk("%08lx ", *stack++); | 291 | printk("%08lx ", *stack++); |
286 | } | 292 | } |
287 | printk("\n%sCall Trace:\n", log_lvl); | 293 | printk("\n%sCall Trace:\n", log_lvl); |
294 | |||
288 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); | 295 | show_trace_log_lvl(task, regs, sp, bp, log_lvl); |
289 | } | 296 | } |
290 | 297 | ||
@@ -299,8 +306,8 @@ void show_stack(struct task_struct *task, unsigned long *sp) | |||
299 | */ | 306 | */ |
300 | void dump_stack(void) | 307 | void dump_stack(void) |
301 | { | 308 | { |
302 | unsigned long stack; | ||
303 | unsigned long bp = 0; | 309 | unsigned long bp = 0; |
310 | unsigned long stack; | ||
304 | 311 | ||
305 | #ifdef CONFIG_FRAME_POINTER | 312 | #ifdef CONFIG_FRAME_POINTER |
306 | if (!bp) | 313 | if (!bp) |
@@ -312,6 +319,7 @@ void dump_stack(void) | |||
312 | init_utsname()->release, | 319 | init_utsname()->release, |
313 | (int)strcspn(init_utsname()->version, " "), | 320 | (int)strcspn(init_utsname()->version, " "), |
314 | init_utsname()->version); | 321 | init_utsname()->version); |
322 | |||
315 | show_trace(current, NULL, &stack, bp); | 323 | show_trace(current, NULL, &stack, bp); |
316 | } | 324 | } |
317 | 325 | ||
@@ -323,6 +331,7 @@ void show_registers(struct pt_regs *regs) | |||
323 | 331 | ||
324 | print_modules(); | 332 | print_modules(); |
325 | __show_registers(regs, 0); | 333 | __show_registers(regs, 0); |
334 | |||
326 | printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", | 335 | printk(KERN_EMERG "Process %.*s (pid: %d, ti=%p task=%p task.ti=%p)", |
327 | TASK_COMM_LEN, current->comm, task_pid_nr(current), | 336 | TASK_COMM_LEN, current->comm, task_pid_nr(current), |
328 | current_thread_info(), current, task_thread_info(current)); | 337 | current_thread_info(), current, task_thread_info(current)); |
@@ -331,10 +340,10 @@ void show_registers(struct pt_regs *regs) | |||
331 | * time of the fault.. | 340 | * time of the fault.. |
332 | */ | 341 | */ |
333 | if (!user_mode_vm(regs)) { | 342 | if (!user_mode_vm(regs)) { |
334 | u8 *ip; | ||
335 | unsigned int code_prologue = code_bytes * 43 / 64; | 343 | unsigned int code_prologue = code_bytes * 43 / 64; |
336 | unsigned int code_len = code_bytes; | 344 | unsigned int code_len = code_bytes; |
337 | unsigned char c; | 345 | unsigned char c; |
346 | u8 *ip; | ||
338 | 347 | ||
339 | printk("\n" KERN_EMERG "Stack: "); | 348 | printk("\n" KERN_EMERG "Stack: "); |
340 | show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG); | 349 | show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG); |
@@ -361,7 +370,7 @@ void show_registers(struct pt_regs *regs) | |||
361 | } | 370 | } |
362 | } | 371 | } |
363 | printk("\n"); | 372 | printk("\n"); |
364 | } | 373 | } |
365 | 374 | ||
366 | int is_valid_bugaddr(unsigned long ip) | 375 | int is_valid_bugaddr(unsigned long ip) |
367 | { | 376 | { |
@@ -377,10 +386,10 @@ int is_valid_bugaddr(unsigned long ip) | |||
377 | 386 | ||
378 | static int die_counter; | 387 | static int die_counter; |
379 | 388 | ||
380 | int __kprobes __die(const char * str, struct pt_regs * regs, long err) | 389 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) |
381 | { | 390 | { |
382 | unsigned long sp; | ||
383 | unsigned short ss; | 391 | unsigned short ss; |
392 | unsigned long sp; | ||
384 | 393 | ||
385 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); | 394 | printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter); |
386 | #ifdef CONFIG_PREEMPT | 395 | #ifdef CONFIG_PREEMPT |
@@ -395,8 +404,8 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err) | |||
395 | printk("\n"); | 404 | printk("\n"); |
396 | 405 | ||
397 | if (notify_die(DIE_OOPS, str, regs, err, | 406 | if (notify_die(DIE_OOPS, str, regs, err, |
398 | current->thread.trap_no, SIGSEGV) != | 407 | current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) { |
399 | NOTIFY_STOP) { | 408 | |
400 | show_registers(regs); | 409 | show_registers(regs); |
401 | /* Executive summary in case the oops scrolled away */ | 410 | /* Executive summary in case the oops scrolled away */ |
402 | sp = (unsigned long) (®s->sp); | 411 | sp = (unsigned long) (®s->sp); |
@@ -408,17 +417,18 @@ int __kprobes __die(const char * str, struct pt_regs * regs, long err) | |||
408 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | 417 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); |
409 | print_symbol("%s", regs->ip); | 418 | print_symbol("%s", regs->ip); |
410 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | 419 | printk(" SS:ESP %04x:%08lx\n", ss, sp); |
420 | |||
411 | return 0; | 421 | return 0; |
412 | } else { | ||
413 | return 1; | ||
414 | } | 422 | } |
423 | |||
424 | return 1; | ||
415 | } | 425 | } |
416 | 426 | ||
417 | /* | 427 | /* |
418 | * This is gone through when something in the kernel has done something bad and | 428 | * This is gone through when something in the kernel has done something bad |
419 | * is about to be terminated. | 429 | * and is about to be terminated: |
420 | */ | 430 | */ |
421 | void die(const char * str, struct pt_regs * regs, long err) | 431 | void die(const char *str, struct pt_regs *regs, long err) |
422 | { | 432 | { |
423 | static struct { | 433 | static struct { |
424 | raw_spinlock_t lock; | 434 | raw_spinlock_t lock; |
@@ -440,8 +450,9 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
440 | die.lock_owner = smp_processor_id(); | 450 | die.lock_owner = smp_processor_id(); |
441 | die.lock_owner_depth = 0; | 451 | die.lock_owner_depth = 0; |
442 | bust_spinlocks(1); | 452 | bust_spinlocks(1); |
443 | } else | 453 | } else { |
444 | raw_local_irq_save(flags); | 454 | raw_local_irq_save(flags); |
455 | } | ||
445 | 456 | ||
446 | if (++die.lock_owner_depth < 3) { | 457 | if (++die.lock_owner_depth < 3) { |
447 | report_bug(regs->ip, regs); | 458 | report_bug(regs->ip, regs); |
@@ -474,15 +485,16 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
474 | do_exit(SIGSEGV); | 485 | do_exit(SIGSEGV); |
475 | } | 486 | } |
476 | 487 | ||
477 | static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) | 488 | static inline void |
489 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | ||
478 | { | 490 | { |
479 | if (!user_mode_vm(regs)) | 491 | if (!user_mode_vm(regs)) |
480 | die(str, regs, err); | 492 | die(str, regs, err); |
481 | } | 493 | } |
482 | 494 | ||
483 | static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, | 495 | static void __kprobes |
484 | struct pt_regs * regs, long error_code, | 496 | do_trap(int trapnr, int signr, char *str, int vm86, struct pt_regs *regs, |
485 | siginfo_t *info) | 497 | long error_code, siginfo_t *info) |
486 | { | 498 | { |
487 | struct task_struct *tsk = current; | 499 | struct task_struct *tsk = current; |
488 | 500 | ||
@@ -495,111 +507,112 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, | |||
495 | if (!user_mode(regs)) | 507 | if (!user_mode(regs)) |
496 | goto kernel_trap; | 508 | goto kernel_trap; |
497 | 509 | ||
498 | trap_signal: { | 510 | trap_signal: |
499 | /* | 511 | /* |
500 | * We want error_code and trap_no set for userspace faults and | 512 | * We want error_code and trap_no set for userspace faults and |
501 | * kernelspace faults which result in die(), but not | 513 | * kernelspace faults which result in die(), but not |
502 | * kernelspace faults which are fixed up. die() gives the | 514 | * kernelspace faults which are fixed up. die() gives the |
503 | * process no chance to handle the signal and notice the | 515 | * process no chance to handle the signal and notice the |
504 | * kernel fault information, so that won't result in polluting | 516 | * kernel fault information, so that won't result in polluting |
505 | * the information about previously queued, but not yet | 517 | * the information about previously queued, but not yet |
506 | * delivered, faults. See also do_general_protection below. | 518 | * delivered, faults. See also do_general_protection below. |
507 | */ | 519 | */ |
508 | tsk->thread.error_code = error_code; | 520 | tsk->thread.error_code = error_code; |
509 | tsk->thread.trap_no = trapnr; | 521 | tsk->thread.trap_no = trapnr; |
510 | 522 | ||
511 | if (info) | 523 | if (info) |
512 | force_sig_info(signr, info, tsk); | 524 | force_sig_info(signr, info, tsk); |
513 | else | 525 | else |
514 | force_sig(signr, tsk); | 526 | force_sig(signr, tsk); |
515 | return; | 527 | return; |
516 | } | ||
517 | 528 | ||
518 | kernel_trap: { | 529 | kernel_trap: |
519 | if (!fixup_exception(regs)) { | 530 | if (!fixup_exception(regs)) { |
520 | tsk->thread.error_code = error_code; | 531 | tsk->thread.error_code = error_code; |
521 | tsk->thread.trap_no = trapnr; | 532 | tsk->thread.trap_no = trapnr; |
522 | die(str, regs, error_code); | 533 | die(str, regs, error_code); |
523 | } | ||
524 | return; | ||
525 | } | 534 | } |
535 | return; | ||
526 | 536 | ||
527 | vm86_trap: { | 537 | vm86_trap: |
528 | int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); | 538 | if (handle_vm86_trap((struct kernel_vm86_regs *) regs, |
529 | if (ret) goto trap_signal; | 539 | error_code, trapnr)) |
530 | return; | 540 | goto trap_signal; |
531 | } | 541 | return; |
532 | } | 542 | } |
533 | 543 | ||
534 | #define DO_ERROR(trapnr, signr, str, name) \ | 544 | #define DO_ERROR(trapnr, signr, str, name) \ |
535 | void do_##name(struct pt_regs * regs, long error_code) \ | 545 | void do_##name(struct pt_regs *regs, long error_code) \ |
536 | { \ | 546 | { \ |
537 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 547 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
538 | == NOTIFY_STOP) \ | 548 | == NOTIFY_STOP) \ |
539 | return; \ | 549 | return; \ |
540 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ | 550 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ |
541 | } | 551 | } |
542 | 552 | ||
543 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ | 553 | #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr, irq) \ |
544 | void do_##name(struct pt_regs * regs, long error_code) \ | 554 | void do_##name(struct pt_regs *regs, long error_code) \ |
545 | { \ | 555 | { \ |
546 | siginfo_t info; \ | 556 | siginfo_t info; \ |
547 | if (irq) \ | 557 | if (irq) \ |
548 | local_irq_enable(); \ | 558 | local_irq_enable(); \ |
549 | info.si_signo = signr; \ | 559 | info.si_signo = signr; \ |
550 | info.si_errno = 0; \ | 560 | info.si_errno = 0; \ |
551 | info.si_code = sicode; \ | 561 | info.si_code = sicode; \ |
552 | info.si_addr = (void __user *)siaddr; \ | 562 | info.si_addr = (void __user *)siaddr; \ |
553 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 563 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
554 | == NOTIFY_STOP) \ | 564 | == NOTIFY_STOP) \ |
555 | return; \ | 565 | return; \ |
556 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ | 566 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ |
557 | } | 567 | } |
558 | 568 | ||
559 | #define DO_VM86_ERROR(trapnr, signr, str, name) \ | 569 | #define DO_VM86_ERROR(trapnr, signr, str, name) \ |
560 | void do_##name(struct pt_regs * regs, long error_code) \ | 570 | void do_##name(struct pt_regs *regs, long error_code) \ |
561 | { \ | 571 | { \ |
562 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 572 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
563 | == NOTIFY_STOP) \ | 573 | == NOTIFY_STOP) \ |
564 | return; \ | 574 | return; \ |
565 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ | 575 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ |
566 | } | 576 | } |
567 | 577 | ||
568 | #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ | 578 | #define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ |
569 | void do_##name(struct pt_regs * regs, long error_code) \ | 579 | void do_##name(struct pt_regs *regs, long error_code) \ |
570 | { \ | 580 | { \ |
571 | siginfo_t info; \ | 581 | siginfo_t info; \ |
572 | info.si_signo = signr; \ | 582 | info.si_signo = signr; \ |
573 | info.si_errno = 0; \ | 583 | info.si_errno = 0; \ |
574 | info.si_code = sicode; \ | 584 | info.si_code = sicode; \ |
575 | info.si_addr = (void __user *)siaddr; \ | 585 | info.si_addr = (void __user *)siaddr; \ |
576 | trace_hardirqs_fixup(); \ | 586 | trace_hardirqs_fixup(); \ |
577 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 587 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
578 | == NOTIFY_STOP) \ | 588 | == NOTIFY_STOP) \ |
579 | return; \ | 589 | return; \ |
580 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ | 590 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ |
581 | } | 591 | } |
582 | 592 | ||
583 | DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) | 593 | DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) |
584 | #ifndef CONFIG_KPROBES | 594 | #ifndef CONFIG_KPROBES |
585 | DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) | 595 | DO_VM86_ERROR(3, SIGTRAP, "int3", int3) |
586 | #endif | 596 | #endif |
587 | DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) | 597 | DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow) |
588 | DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) | 598 | DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds) |
589 | DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0) | 599 | DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0) |
590 | DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | 600 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) |
591 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | 601 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) |
592 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | 602 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) |
593 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | 603 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) |
594 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) | 604 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) |
595 | DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1) | 605 | DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0, 1) |
596 | 606 | ||
597 | void __kprobes do_general_protection(struct pt_regs * regs, | 607 | void __kprobes do_general_protection(struct pt_regs *regs, long error_code) |
598 | long error_code) | ||
599 | { | 608 | { |
600 | int cpu = get_cpu(); | 609 | struct thread_struct *thread; |
601 | struct tss_struct *tss = &per_cpu(init_tss, cpu); | 610 | struct tss_struct *tss; |
602 | struct thread_struct *thread = ¤t->thread; | 611 | int cpu; |
612 | |||
613 | cpu = get_cpu(); | ||
614 | tss = &per_cpu(init_tss, cpu); | ||
615 | thread = ¤t->thread; | ||
603 | 616 | ||
604 | /* | 617 | /* |
605 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an | 618 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an |
@@ -616,14 +629,16 @@ void __kprobes do_general_protection(struct pt_regs * regs, | |||
616 | * If the previously set map was extending to higher ports | 629 | * If the previously set map was extending to higher ports |
617 | * than the current one, pad extra space with 0xff (no access). | 630 | * than the current one, pad extra space with 0xff (no access). |
618 | */ | 631 | */ |
619 | if (thread->io_bitmap_max < tss->io_bitmap_max) | 632 | if (thread->io_bitmap_max < tss->io_bitmap_max) { |
620 | memset((char *) tss->io_bitmap + | 633 | memset((char *) tss->io_bitmap + |
621 | thread->io_bitmap_max, 0xff, | 634 | thread->io_bitmap_max, 0xff, |
622 | tss->io_bitmap_max - thread->io_bitmap_max); | 635 | tss->io_bitmap_max - thread->io_bitmap_max); |
636 | } | ||
623 | tss->io_bitmap_max = thread->io_bitmap_max; | 637 | tss->io_bitmap_max = thread->io_bitmap_max; |
624 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; | 638 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; |
625 | tss->io_bitmap_owner = thread; | 639 | tss->io_bitmap_owner = thread; |
626 | put_cpu(); | 640 | put_cpu(); |
641 | |||
627 | return; | 642 | return; |
628 | } | 643 | } |
629 | put_cpu(); | 644 | put_cpu(); |
@@ -636,6 +651,7 @@ void __kprobes do_general_protection(struct pt_regs * regs, | |||
636 | 651 | ||
637 | current->thread.error_code = error_code; | 652 | current->thread.error_code = error_code; |
638 | current->thread.trap_no = 13; | 653 | current->thread.trap_no = 13; |
654 | |||
639 | if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) && | 655 | if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) && |
640 | printk_ratelimit()) { | 656 | printk_ratelimit()) { |
641 | printk(KERN_INFO | 657 | printk(KERN_INFO |
@@ -666,21 +682,24 @@ gp_in_kernel: | |||
666 | } | 682 | } |
667 | 683 | ||
668 | static __kprobes void | 684 | static __kprobes void |
669 | mem_parity_error(unsigned char reason, struct pt_regs * regs) | 685 | mem_parity_error(unsigned char reason, struct pt_regs *regs) |
670 | { | 686 | { |
671 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " | 687 | printk(KERN_EMERG |
672 | "CPU %d.\n", reason, smp_processor_id()); | 688 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", |
673 | printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n"); | 689 | reason, smp_processor_id()); |
690 | |||
691 | printk(KERN_EMERG | ||
692 | "You have some hardware problem, likely on the PCI bus.\n"); | ||
674 | 693 | ||
675 | #if defined(CONFIG_EDAC) | 694 | #if defined(CONFIG_EDAC) |
676 | if(edac_handler_set()) { | 695 | if (edac_handler_set()) { |
677 | edac_atomic_assert_error(); | 696 | edac_atomic_assert_error(); |
678 | return; | 697 | return; |
679 | } | 698 | } |
680 | #endif | 699 | #endif |
681 | 700 | ||
682 | if (panic_on_unrecovered_nmi) | 701 | if (panic_on_unrecovered_nmi) |
683 | panic("NMI: Not continuing"); | 702 | panic("NMI: Not continuing"); |
684 | 703 | ||
685 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 704 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
686 | 705 | ||
@@ -689,7 +708,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs) | |||
689 | } | 708 | } |
690 | 709 | ||
691 | static __kprobes void | 710 | static __kprobes void |
692 | io_check_error(unsigned char reason, struct pt_regs * regs) | 711 | io_check_error(unsigned char reason, struct pt_regs *regs) |
693 | { | 712 | { |
694 | unsigned long i; | 713 | unsigned long i; |
695 | 714 | ||
@@ -699,28 +718,35 @@ io_check_error(unsigned char reason, struct pt_regs * regs) | |||
699 | /* Re-enable the IOCK line, wait for a few seconds */ | 718 | /* Re-enable the IOCK line, wait for a few seconds */ |
700 | reason = (reason & 0xf) | 8; | 719 | reason = (reason & 0xf) | 8; |
701 | outb(reason, 0x61); | 720 | outb(reason, 0x61); |
721 | |||
702 | i = 2000; | 722 | i = 2000; |
703 | while (--i) udelay(1000); | 723 | while (--i) |
724 | udelay(1000); | ||
725 | |||
704 | reason &= ~8; | 726 | reason &= ~8; |
705 | outb(reason, 0x61); | 727 | outb(reason, 0x61); |
706 | } | 728 | } |
707 | 729 | ||
708 | static __kprobes void | 730 | static __kprobes void |
709 | unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | 731 | unknown_nmi_error(unsigned char reason, struct pt_regs *regs) |
710 | { | 732 | { |
711 | #ifdef CONFIG_MCA | 733 | #ifdef CONFIG_MCA |
712 | /* Might actually be able to figure out what the guilty party | 734 | /* |
713 | * is. */ | 735 | * Might actually be able to figure out what the guilty party |
714 | if( MCA_bus ) { | 736 | * is: |
737 | */ | ||
738 | if (MCA_bus) { | ||
715 | mca_handle_nmi(); | 739 | mca_handle_nmi(); |
716 | return; | 740 | return; |
717 | } | 741 | } |
718 | #endif | 742 | #endif |
719 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " | 743 | printk(KERN_EMERG |
720 | "CPU %d.\n", reason, smp_processor_id()); | 744 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", |
745 | reason, smp_processor_id()); | ||
746 | |||
721 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | 747 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); |
722 | if (panic_on_unrecovered_nmi) | 748 | if (panic_on_unrecovered_nmi) |
723 | panic("NMI: Not continuing"); | 749 | panic("NMI: Not continuing"); |
724 | 750 | ||
725 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 751 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
726 | } | 752 | } |
@@ -729,14 +755,13 @@ static DEFINE_SPINLOCK(nmi_print_lock); | |||
729 | 755 | ||
730 | void __kprobes die_nmi(struct pt_regs *regs, const char *msg) | 756 | void __kprobes die_nmi(struct pt_regs *regs, const char *msg) |
731 | { | 757 | { |
732 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == | 758 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == NOTIFY_STOP) |
733 | NOTIFY_STOP) | ||
734 | return; | 759 | return; |
735 | 760 | ||
736 | spin_lock(&nmi_print_lock); | 761 | spin_lock(&nmi_print_lock); |
737 | /* | 762 | /* |
738 | * We are in trouble anyway, lets at least try | 763 | * We are in trouble anyway, lets at least try |
739 | * to get a message out. | 764 | * to get a message out: |
740 | */ | 765 | */ |
741 | bust_spinlocks(1); | 766 | bust_spinlocks(1); |
742 | printk(KERN_EMERG "%s", msg); | 767 | printk(KERN_EMERG "%s", msg); |
@@ -747,9 +772,10 @@ void __kprobes die_nmi(struct pt_regs *regs, const char *msg) | |||
747 | spin_unlock(&nmi_print_lock); | 772 | spin_unlock(&nmi_print_lock); |
748 | bust_spinlocks(0); | 773 | bust_spinlocks(0); |
749 | 774 | ||
750 | /* If we are in kernel we are probably nested up pretty bad | 775 | /* |
751 | * and might aswell get out now while we still can. | 776 | * If we are in kernel we are probably nested up pretty bad |
752 | */ | 777 | * and might aswell get out now while we still can: |
778 | */ | ||
753 | if (!user_mode_vm(regs)) { | 779 | if (!user_mode_vm(regs)) { |
754 | current->thread.trap_no = 2; | 780 | current->thread.trap_no = 2; |
755 | crash_kexec(regs); | 781 | crash_kexec(regs); |
@@ -758,14 +784,14 @@ void __kprobes die_nmi(struct pt_regs *regs, const char *msg) | |||
758 | do_exit(SIGSEGV); | 784 | do_exit(SIGSEGV); |
759 | } | 785 | } |
760 | 786 | ||
761 | static __kprobes void default_do_nmi(struct pt_regs * regs) | 787 | static __kprobes void default_do_nmi(struct pt_regs *regs) |
762 | { | 788 | { |
763 | unsigned char reason = 0; | 789 | unsigned char reason = 0; |
764 | 790 | ||
765 | /* Only the BSP gets external NMIs from the system. */ | 791 | /* Only the BSP gets external NMIs from the system: */ |
766 | if (!smp_processor_id()) | 792 | if (!smp_processor_id()) |
767 | reason = get_nmi_reason(); | 793 | reason = get_nmi_reason(); |
768 | 794 | ||
769 | if (!(reason & 0xc0)) { | 795 | if (!(reason & 0xc0)) { |
770 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | 796 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) |
771 | == NOTIFY_STOP) | 797 | == NOTIFY_STOP) |
@@ -778,8 +804,10 @@ static __kprobes void default_do_nmi(struct pt_regs * regs) | |||
778 | if (nmi_watchdog_tick(regs, reason)) | 804 | if (nmi_watchdog_tick(regs, reason)) |
779 | return; | 805 | return; |
780 | if (!do_nmi_callback(regs, smp_processor_id())) | 806 | if (!do_nmi_callback(regs, smp_processor_id())) |
781 | #endif | ||
782 | unknown_nmi_error(reason, regs); | 807 | unknown_nmi_error(reason, regs); |
808 | #else | ||
809 | unknown_nmi_error(reason, regs); | ||
810 | #endif | ||
783 | 811 | ||
784 | return; | 812 | return; |
785 | } | 813 | } |
@@ -791,14 +819,14 @@ static __kprobes void default_do_nmi(struct pt_regs * regs) | |||
791 | io_check_error(reason, regs); | 819 | io_check_error(reason, regs); |
792 | /* | 820 | /* |
793 | * Reassert NMI in case it became active meanwhile | 821 | * Reassert NMI in case it became active meanwhile |
794 | * as it's edge-triggered. | 822 | * as it's edge-triggered: |
795 | */ | 823 | */ |
796 | reassert_nmi(); | 824 | reassert_nmi(); |
797 | } | 825 | } |
798 | 826 | ||
799 | static int ignore_nmis; | 827 | static int ignore_nmis; |
800 | 828 | ||
801 | __kprobes void do_nmi(struct pt_regs * regs, long error_code) | 829 | __kprobes void do_nmi(struct pt_regs *regs, long error_code) |
802 | { | 830 | { |
803 | int cpu; | 831 | int cpu; |
804 | 832 | ||
@@ -834,9 +862,12 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code) | |||
834 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) | 862 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) |
835 | == NOTIFY_STOP) | 863 | == NOTIFY_STOP) |
836 | return; | 864 | return; |
837 | /* This is an interrupt gate, because kprobes wants interrupts | 865 | /* |
838 | disabled. Normal trap handlers don't. */ | 866 | * This is an interrupt gate, because kprobes wants interrupts |
867 | * disabled. Normal trap handlers don't. | ||
868 | */ | ||
839 | restore_interrupts(regs); | 869 | restore_interrupts(regs); |
870 | |||
840 | do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); | 871 | do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); |
841 | } | 872 | } |
842 | #endif | 873 | #endif |
@@ -851,7 +882,7 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code) | |||
851 | * from user space. Such code must not hold kernel locks (since it | 882 | * from user space. Such code must not hold kernel locks (since it |
852 | * can equally take a page fault), therefore it is safe to call | 883 | * can equally take a page fault), therefore it is safe to call |
853 | * force_sig_info even though that claims and releases locks. | 884 | * force_sig_info even though that claims and releases locks. |
854 | * | 885 | * |
855 | * Code in ./signal.c ensures that the debug control register | 886 | * Code in ./signal.c ensures that the debug control register |
856 | * is restored before we deliver any signal, and therefore that | 887 | * is restored before we deliver any signal, and therefore that |
857 | * user code runs with the correct debug control register even though | 888 | * user code runs with the correct debug control register even though |
@@ -863,10 +894,10 @@ void __kprobes do_int3(struct pt_regs *regs, long error_code) | |||
863 | * find every occurrence of the TF bit that could be saved away even | 894 | * find every occurrence of the TF bit that could be saved away even |
864 | * by user code) | 895 | * by user code) |
865 | */ | 896 | */ |
866 | void __kprobes do_debug(struct pt_regs * regs, long error_code) | 897 | void __kprobes do_debug(struct pt_regs *regs, long error_code) |
867 | { | 898 | { |
868 | unsigned int condition; | ||
869 | struct task_struct *tsk = current; | 899 | struct task_struct *tsk = current; |
900 | unsigned int condition; | ||
870 | 901 | ||
871 | trace_hardirqs_fixup(); | 902 | trace_hardirqs_fixup(); |
872 | 903 | ||
@@ -914,7 +945,8 @@ void __kprobes do_debug(struct pt_regs * regs, long error_code) | |||
914 | /* Ok, finally something we can handle */ | 945 | /* Ok, finally something we can handle */ |
915 | send_sigtrap(tsk, regs, error_code); | 946 | send_sigtrap(tsk, regs, error_code); |
916 | 947 | ||
917 | /* Disable additional traps. They'll be re-enabled when | 948 | /* |
949 | * Disable additional traps. They'll be re-enabled when | ||
918 | * the signal is delivered. | 950 | * the signal is delivered. |
919 | */ | 951 | */ |
920 | clear_dr7: | 952 | clear_dr7: |
@@ -938,9 +970,10 @@ clear_TF_reenable: | |||
938 | */ | 970 | */ |
939 | void math_error(void __user *ip) | 971 | void math_error(void __user *ip) |
940 | { | 972 | { |
941 | struct task_struct * task; | 973 | struct task_struct *task; |
974 | unsigned short cwd; | ||
975 | unsigned short swd; | ||
942 | siginfo_t info; | 976 | siginfo_t info; |
943 | unsigned short cwd, swd; | ||
944 | 977 | ||
945 | /* | 978 | /* |
946 | * Save the info for the exception handler and clear the error. | 979 | * Save the info for the exception handler and clear the error. |
@@ -966,36 +999,36 @@ void math_error(void __user *ip) | |||
966 | cwd = get_fpu_cwd(task); | 999 | cwd = get_fpu_cwd(task); |
967 | swd = get_fpu_swd(task); | 1000 | swd = get_fpu_swd(task); |
968 | switch (swd & ~cwd & 0x3f) { | 1001 | switch (swd & ~cwd & 0x3f) { |
969 | case 0x000: /* No unmasked exception */ | 1002 | case 0x000: /* No unmasked exception */ |
970 | return; | 1003 | return; |
971 | default: /* Multiple exceptions */ | 1004 | default: /* Multiple exceptions */ |
972 | break; | 1005 | break; |
973 | case 0x001: /* Invalid Op */ | 1006 | case 0x001: /* Invalid Op */ |
974 | /* | 1007 | /* |
975 | * swd & 0x240 == 0x040: Stack Underflow | 1008 | * swd & 0x240 == 0x040: Stack Underflow |
976 | * swd & 0x240 == 0x240: Stack Overflow | 1009 | * swd & 0x240 == 0x240: Stack Overflow |
977 | * User must clear the SF bit (0x40) if set | 1010 | * User must clear the SF bit (0x40) if set |
978 | */ | 1011 | */ |
979 | info.si_code = FPE_FLTINV; | 1012 | info.si_code = FPE_FLTINV; |
980 | break; | 1013 | break; |
981 | case 0x002: /* Denormalize */ | 1014 | case 0x002: /* Denormalize */ |
982 | case 0x010: /* Underflow */ | 1015 | case 0x010: /* Underflow */ |
983 | info.si_code = FPE_FLTUND; | 1016 | info.si_code = FPE_FLTUND; |
984 | break; | 1017 | break; |
985 | case 0x004: /* Zero Divide */ | 1018 | case 0x004: /* Zero Divide */ |
986 | info.si_code = FPE_FLTDIV; | 1019 | info.si_code = FPE_FLTDIV; |
987 | break; | 1020 | break; |
988 | case 0x008: /* Overflow */ | 1021 | case 0x008: /* Overflow */ |
989 | info.si_code = FPE_FLTOVF; | 1022 | info.si_code = FPE_FLTOVF; |
990 | break; | 1023 | break; |
991 | case 0x020: /* Precision */ | 1024 | case 0x020: /* Precision */ |
992 | info.si_code = FPE_FLTRES; | 1025 | info.si_code = FPE_FLTRES; |
993 | break; | 1026 | break; |
994 | } | 1027 | } |
995 | force_sig_info(SIGFPE, &info, task); | 1028 | force_sig_info(SIGFPE, &info, task); |
996 | } | 1029 | } |
997 | 1030 | ||
998 | void do_coprocessor_error(struct pt_regs * regs, long error_code) | 1031 | void do_coprocessor_error(struct pt_regs *regs, long error_code) |
999 | { | 1032 | { |
1000 | ignore_fpu_irq = 1; | 1033 | ignore_fpu_irq = 1; |
1001 | math_error((void __user *)regs->ip); | 1034 | math_error((void __user *)regs->ip); |
@@ -1003,9 +1036,9 @@ void do_coprocessor_error(struct pt_regs * regs, long error_code) | |||
1003 | 1036 | ||
1004 | static void simd_math_error(void __user *ip) | 1037 | static void simd_math_error(void __user *ip) |
1005 | { | 1038 | { |
1006 | struct task_struct * task; | 1039 | struct task_struct *task; |
1007 | siginfo_t info; | ||
1008 | unsigned short mxcsr; | 1040 | unsigned short mxcsr; |
1041 | siginfo_t info; | ||
1009 | 1042 | ||
1010 | /* | 1043 | /* |
1011 | * Save the info for the exception handler and clear the error. | 1044 | * Save the info for the exception handler and clear the error. |
@@ -1026,82 +1059,80 @@ static void simd_math_error(void __user *ip) | |||
1026 | */ | 1059 | */ |
1027 | mxcsr = get_fpu_mxcsr(task); | 1060 | mxcsr = get_fpu_mxcsr(task); |
1028 | switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { | 1061 | switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { |
1029 | case 0x000: | 1062 | case 0x000: |
1030 | default: | 1063 | default: |
1031 | break; | 1064 | break; |
1032 | case 0x001: /* Invalid Op */ | 1065 | case 0x001: /* Invalid Op */ |
1033 | info.si_code = FPE_FLTINV; | 1066 | info.si_code = FPE_FLTINV; |
1034 | break; | 1067 | break; |
1035 | case 0x002: /* Denormalize */ | 1068 | case 0x002: /* Denormalize */ |
1036 | case 0x010: /* Underflow */ | 1069 | case 0x010: /* Underflow */ |
1037 | info.si_code = FPE_FLTUND; | 1070 | info.si_code = FPE_FLTUND; |
1038 | break; | 1071 | break; |
1039 | case 0x004: /* Zero Divide */ | 1072 | case 0x004: /* Zero Divide */ |
1040 | info.si_code = FPE_FLTDIV; | 1073 | info.si_code = FPE_FLTDIV; |
1041 | break; | 1074 | break; |
1042 | case 0x008: /* Overflow */ | 1075 | case 0x008: /* Overflow */ |
1043 | info.si_code = FPE_FLTOVF; | 1076 | info.si_code = FPE_FLTOVF; |
1044 | break; | 1077 | break; |
1045 | case 0x020: /* Precision */ | 1078 | case 0x020: /* Precision */ |
1046 | info.si_code = FPE_FLTRES; | 1079 | info.si_code = FPE_FLTRES; |
1047 | break; | 1080 | break; |
1048 | } | 1081 | } |
1049 | force_sig_info(SIGFPE, &info, task); | 1082 | force_sig_info(SIGFPE, &info, task); |
1050 | } | 1083 | } |
1051 | 1084 | ||
1052 | void do_simd_coprocessor_error(struct pt_regs * regs, | 1085 | void do_simd_coprocessor_error(struct pt_regs *regs, long error_code) |
1053 | long error_code) | ||
1054 | { | 1086 | { |
1055 | if (cpu_has_xmm) { | 1087 | if (cpu_has_xmm) { |
1056 | /* Handle SIMD FPU exceptions on PIII+ processors. */ | 1088 | /* Handle SIMD FPU exceptions on PIII+ processors. */ |
1057 | ignore_fpu_irq = 1; | 1089 | ignore_fpu_irq = 1; |
1058 | simd_math_error((void __user *)regs->ip); | 1090 | simd_math_error((void __user *)regs->ip); |
1059 | } else { | 1091 | return; |
1060 | /* | 1092 | } |
1061 | * Handle strange cache flush from user space exception | 1093 | /* |
1062 | * in all other cases. This is undocumented behaviour. | 1094 | * Handle strange cache flush from user space exception |
1063 | */ | 1095 | * in all other cases. This is undocumented behaviour. |
1064 | if (regs->flags & VM_MASK) { | 1096 | */ |
1065 | handle_vm86_fault((struct kernel_vm86_regs *)regs, | 1097 | if (regs->flags & VM_MASK) { |
1066 | error_code); | 1098 | handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code); |
1067 | return; | 1099 | return; |
1068 | } | ||
1069 | current->thread.trap_no = 19; | ||
1070 | current->thread.error_code = error_code; | ||
1071 | die_if_kernel("cache flush denied", regs, error_code); | ||
1072 | force_sig(SIGSEGV, current); | ||
1073 | } | 1100 | } |
1101 | current->thread.trap_no = 19; | ||
1102 | current->thread.error_code = error_code; | ||
1103 | die_if_kernel("cache flush denied", regs, error_code); | ||
1104 | force_sig(SIGSEGV, current); | ||
1074 | } | 1105 | } |
1075 | 1106 | ||
1076 | void do_spurious_interrupt_bug(struct pt_regs * regs, | 1107 | void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) |
1077 | long error_code) | ||
1078 | { | 1108 | { |
1079 | #if 0 | 1109 | #if 0 |
1080 | /* No need to warn about this any longer. */ | 1110 | /* No need to warn about this any longer. */ |
1081 | printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); | 1111 | printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); |
1082 | #endif | 1112 | #endif |
1083 | } | 1113 | } |
1084 | 1114 | ||
1085 | unsigned long patch_espfix_desc(unsigned long uesp, | 1115 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) |
1086 | unsigned long kesp) | ||
1087 | { | 1116 | { |
1088 | struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; | 1117 | struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; |
1089 | unsigned long base = (kesp - uesp) & -THREAD_SIZE; | 1118 | unsigned long base = (kesp - uesp) & -THREAD_SIZE; |
1090 | unsigned long new_kesp = kesp - base; | 1119 | unsigned long new_kesp = kesp - base; |
1091 | unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; | 1120 | unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; |
1092 | __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; | 1121 | __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; |
1122 | |||
1093 | /* Set up base for espfix segment */ | 1123 | /* Set up base for espfix segment */ |
1094 | desc &= 0x00f0ff0000000000ULL; | 1124 | desc &= 0x00f0ff0000000000ULL; |
1095 | desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | | 1125 | desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | |
1096 | ((((__u64)base) << 32) & 0xff00000000000000ULL) | | 1126 | ((((__u64)base) << 32) & 0xff00000000000000ULL) | |
1097 | ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | | 1127 | ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | |
1098 | (lim_pages & 0xffff); | 1128 | (lim_pages & 0xffff); |
1099 | *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; | 1129 | *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; |
1130 | |||
1100 | return new_kesp; | 1131 | return new_kesp; |
1101 | } | 1132 | } |
1102 | 1133 | ||
1103 | /* | 1134 | /* |
1104 | * 'math_state_restore()' saves the current math information in the | 1135 | * 'math_state_restore()' saves the current math information in the |
1105 | * old math state array, and gets the new ones from the current task | 1136 | * old math state array, and gets the new ones from the current task |
1106 | * | 1137 | * |
1107 | * Careful.. There are problems with IBM-designed IRQ13 behaviour. | 1138 | * Careful.. There are problems with IBM-designed IRQ13 behaviour. |
@@ -1115,7 +1146,7 @@ asmlinkage void math_state_restore(void) | |||
1115 | struct thread_info *thread = current_thread_info(); | 1146 | struct thread_info *thread = current_thread_info(); |
1116 | struct task_struct *tsk = thread->task; | 1147 | struct task_struct *tsk = thread->task; |
1117 | 1148 | ||
1118 | clts(); /* Allow maths ops (or we recurse) */ | 1149 | clts(); /* Allow maths ops (or we recurse) */ |
1119 | if (!tsk_used_math(tsk)) | 1150 | if (!tsk_used_math(tsk)) |
1120 | init_fpu(tsk); | 1151 | init_fpu(tsk); |
1121 | restore_fpu(tsk); | 1152 | restore_fpu(tsk); |
@@ -1128,53 +1159,52 @@ EXPORT_SYMBOL_GPL(math_state_restore); | |||
1128 | 1159 | ||
1129 | asmlinkage void math_emulate(long arg) | 1160 | asmlinkage void math_emulate(long arg) |
1130 | { | 1161 | { |
1131 | printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n"); | 1162 | printk(KERN_EMERG |
1132 | printk(KERN_EMERG "killing %s.\n",current->comm); | 1163 | "math-emulation not enabled and no coprocessor found.\n"); |
1133 | force_sig(SIGFPE,current); | 1164 | printk(KERN_EMERG "killing %s.\n", current->comm); |
1165 | force_sig(SIGFPE, current); | ||
1134 | schedule(); | 1166 | schedule(); |
1135 | } | 1167 | } |
1136 | 1168 | ||
1137 | #endif /* CONFIG_MATH_EMULATION */ | 1169 | #endif /* CONFIG_MATH_EMULATION */ |
1138 | 1170 | ||
1139 | |||
1140 | void __init trap_init(void) | 1171 | void __init trap_init(void) |
1141 | { | 1172 | { |
1142 | int i; | 1173 | int i; |
1143 | 1174 | ||
1144 | #ifdef CONFIG_EISA | 1175 | #ifdef CONFIG_EISA |
1145 | void __iomem *p = early_ioremap(0x0FFFD9, 4); | 1176 | void __iomem *p = early_ioremap(0x0FFFD9, 4); |
1146 | if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) { | 1177 | |
1178 | if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) | ||
1147 | EISA_bus = 1; | 1179 | EISA_bus = 1; |
1148 | } | ||
1149 | early_iounmap(p, 4); | 1180 | early_iounmap(p, 4); |
1150 | #endif | 1181 | #endif |
1151 | 1182 | ||
1152 | #ifdef CONFIG_X86_LOCAL_APIC | 1183 | #ifdef CONFIG_X86_LOCAL_APIC |
1153 | init_apic_mappings(); | 1184 | init_apic_mappings(); |
1154 | #endif | 1185 | #endif |
1155 | 1186 | set_trap_gate(0, ÷_error); | |
1156 | set_trap_gate(0,÷_error); | 1187 | set_intr_gate(1, &debug); |
1157 | set_intr_gate(1,&debug); | 1188 | set_intr_gate(2, &nmi); |
1158 | set_intr_gate(2,&nmi); | ||
1159 | set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ | 1189 | set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ |
1160 | set_system_gate(4,&overflow); | 1190 | set_system_gate(4, &overflow); |
1161 | set_trap_gate(5,&bounds); | 1191 | set_trap_gate(5, &bounds); |
1162 | set_trap_gate(6,&invalid_op); | 1192 | set_trap_gate(6, &invalid_op); |
1163 | set_trap_gate(7,&device_not_available); | 1193 | set_trap_gate(7, &device_not_available); |
1164 | set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS); | 1194 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); |
1165 | set_trap_gate(9,&coprocessor_segment_overrun); | 1195 | set_trap_gate(9, &coprocessor_segment_overrun); |
1166 | set_trap_gate(10,&invalid_TSS); | 1196 | set_trap_gate(10, &invalid_TSS); |
1167 | set_trap_gate(11,&segment_not_present); | 1197 | set_trap_gate(11, &segment_not_present); |
1168 | set_trap_gate(12,&stack_segment); | 1198 | set_trap_gate(12, &stack_segment); |
1169 | set_trap_gate(13,&general_protection); | 1199 | set_trap_gate(13, &general_protection); |
1170 | set_intr_gate(14,&page_fault); | 1200 | set_intr_gate(14, &page_fault); |
1171 | set_trap_gate(15,&spurious_interrupt_bug); | 1201 | set_trap_gate(15, &spurious_interrupt_bug); |
1172 | set_trap_gate(16,&coprocessor_error); | 1202 | set_trap_gate(16, &coprocessor_error); |
1173 | set_trap_gate(17,&alignment_check); | 1203 | set_trap_gate(17, &alignment_check); |
1174 | #ifdef CONFIG_X86_MCE | 1204 | #ifdef CONFIG_X86_MCE |
1175 | set_trap_gate(18,&machine_check); | 1205 | set_trap_gate(18, &machine_check); |
1176 | #endif | 1206 | #endif |
1177 | set_trap_gate(19,&simd_coprocessor_error); | 1207 | set_trap_gate(19, &simd_coprocessor_error); |
1178 | 1208 | ||
1179 | /* | 1209 | /* |
1180 | * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. | 1210 | * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. |
@@ -1187,21 +1217,22 @@ void __init trap_init(void) | |||
1187 | printk("done.\n"); | 1217 | printk("done.\n"); |
1188 | } | 1218 | } |
1189 | if (cpu_has_xmm) { | 1219 | if (cpu_has_xmm) { |
1190 | printk(KERN_INFO "Enabling unmasked SIMD FPU exception " | 1220 | printk(KERN_INFO |
1191 | "support... "); | 1221 | "Enabling unmasked SIMD FPU exception support... "); |
1192 | set_in_cr4(X86_CR4_OSXMMEXCPT); | 1222 | set_in_cr4(X86_CR4_OSXMMEXCPT); |
1193 | printk("done.\n"); | 1223 | printk("done.\n"); |
1194 | } | 1224 | } |
1195 | 1225 | ||
1196 | set_system_gate(SYSCALL_VECTOR,&system_call); | 1226 | set_system_gate(SYSCALL_VECTOR, &system_call); |
1197 | 1227 | ||
1198 | /* Reserve all the builtin and the syscall vector. */ | 1228 | /* Reserve all the builtin and the syscall vector: */ |
1199 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) | 1229 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) |
1200 | set_bit(i, used_vectors); | 1230 | set_bit(i, used_vectors); |
1231 | |||
1201 | set_bit(SYSCALL_VECTOR, used_vectors); | 1232 | set_bit(SYSCALL_VECTOR, used_vectors); |
1202 | 1233 | ||
1203 | /* | 1234 | /* |
1204 | * Should be a barrier for any external CPU state. | 1235 | * Should be a barrier for any external CPU state: |
1205 | */ | 1236 | */ |
1206 | cpu_init(); | 1237 | cpu_init(); |
1207 | 1238 | ||
@@ -1211,6 +1242,7 @@ void __init trap_init(void) | |||
1211 | static int __init kstack_setup(char *s) | 1242 | static int __init kstack_setup(char *s) |
1212 | { | 1243 | { |
1213 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); | 1244 | kstack_depth_to_print = simple_strtoul(s, NULL, 0); |
1245 | |||
1214 | return 1; | 1246 | return 1; |
1215 | } | 1247 | } |
1216 | __setup("kstack=", kstack_setup); | 1248 | __setup("kstack=", kstack_setup); |