diff options
Diffstat (limited to 'arch/sh')
-rw-r--r-- | arch/sh/kernel/cpu/sh4/fpu.c | 7 | ||||
-rw-r--r-- | arch/sh/kernel/traps.c | 74 | ||||
-rw-r--r-- | arch/sh/mm/fault.c | 26 |
3 files changed, 58 insertions, 49 deletions
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index 378b488237c9..7624677f6628 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c | |||
@@ -282,11 +282,8 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
282 | grab_fpu(regs); | 282 | grab_fpu(regs); |
283 | restore_fpu(tsk); | 283 | restore_fpu(tsk); |
284 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 284 | set_tsk_thread_flag(tsk, TIF_USEDFPU); |
285 | } else { | 285 | } else |
286 | tsk->thread.trap_no = 11; | ||
287 | tsk->thread.error_code = 0; | ||
288 | force_sig(SIGFPE, tsk); | 286 | force_sig(SIGFPE, tsk); |
289 | } | ||
290 | 287 | ||
291 | regs->pc = nextpc; | 288 | regs->pc = nextpc; |
292 | return 1; | 289 | return 1; |
@@ -307,8 +304,6 @@ do_fpu_error(unsigned long r4, unsigned long r5, unsigned long r6, | |||
307 | 304 | ||
308 | regs->pc += 2; | 305 | regs->pc += 2; |
309 | save_fpu(tsk, regs); | 306 | save_fpu(tsk, regs); |
310 | tsk->thread.trap_no = 11; | ||
311 | tsk->thread.error_code = 0; | ||
312 | force_sig(SIGFPE, tsk); | 307 | force_sig(SIGFPE, tsk); |
313 | } | 308 | } |
314 | 309 | ||
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index b52037bc1255..0ee298079d82 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c | |||
@@ -93,7 +93,7 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
93 | 93 | ||
94 | if (!user_mode(regs) || in_interrupt()) | 94 | if (!user_mode(regs) || in_interrupt()) |
95 | dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + | 95 | dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + |
96 | (unsigned long)task_stack_page(current)); | 96 | (unsigned long)task_stack_page(current)); |
97 | 97 | ||
98 | bust_spinlocks(0); | 98 | bust_spinlocks(0); |
99 | spin_unlock_irq(&die_lock); | 99 | spin_unlock_irq(&die_lock); |
@@ -201,7 +201,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
201 | if (copy_to_user(dst,src,4)) | 201 | if (copy_to_user(dst,src,4)) |
202 | goto fetch_fault; | 202 | goto fetch_fault; |
203 | ret = 0; | 203 | ret = 0; |
204 | break; | 204 | break; |
205 | 205 | ||
206 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ | 206 | case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ |
207 | if (instruction & 4) | 207 | if (instruction & 4) |
@@ -225,7 +225,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
225 | if (copy_from_user(dst,src,4)) | 225 | if (copy_from_user(dst,src,4)) |
226 | goto fetch_fault; | 226 | goto fetch_fault; |
227 | ret = 0; | 227 | ret = 0; |
228 | break; | 228 | break; |
229 | 229 | ||
230 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ | 230 | case 6: /* mov.[bwl] from memory, possibly with post-increment */ |
231 | src = (unsigned char*) *rm; | 231 | src = (unsigned char*) *rm; |
@@ -233,7 +233,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
233 | *rm += count; | 233 | *rm += count; |
234 | dst = (unsigned char*) rn; | 234 | dst = (unsigned char*) rn; |
235 | *(unsigned long*)dst = 0; | 235 | *(unsigned long*)dst = 0; |
236 | 236 | ||
237 | #ifdef __LITTLE_ENDIAN__ | 237 | #ifdef __LITTLE_ENDIAN__ |
238 | if (copy_from_user(dst, src, count)) | 238 | if (copy_from_user(dst, src, count)) |
239 | goto fetch_fault; | 239 | goto fetch_fault; |
@@ -244,7 +244,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
244 | } | 244 | } |
245 | #else | 245 | #else |
246 | dst += 4-count; | 246 | dst += 4-count; |
247 | 247 | ||
248 | if (copy_from_user(dst, src, count)) | 248 | if (copy_from_user(dst, src, count)) |
249 | goto fetch_fault; | 249 | goto fetch_fault; |
250 | 250 | ||
@@ -323,7 +323,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) | |||
323 | return -EFAULT; | 323 | return -EFAULT; |
324 | 324 | ||
325 | /* kernel */ | 325 | /* kernel */ |
326 | die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0); | 326 | die("delay-slot-insn faulting in handle_unaligned_delayslot", |
327 | regs, 0); | ||
327 | } | 328 | } |
328 | 329 | ||
329 | return handle_unaligned_ins(instruction,regs); | 330 | return handle_unaligned_ins(instruction,regs); |
@@ -364,7 +365,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
364 | if (user_mode(regs) && handle_unaligned_notify_count>0) { | 365 | if (user_mode(regs) && handle_unaligned_notify_count>0) { |
365 | handle_unaligned_notify_count--; | 366 | handle_unaligned_notify_count--; |
366 | 367 | ||
367 | printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | 368 | printk(KERN_NOTICE "Fixing up unaligned userspace access " |
369 | "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", | ||
368 | current->comm,current->pid,(u16*)regs->pc,instruction); | 370 | current->comm,current->pid,(u16*)regs->pc,instruction); |
369 | } | 371 | } |
370 | 372 | ||
@@ -499,7 +501,15 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | |||
499 | #endif | 501 | #endif |
500 | 502 | ||
501 | /* | 503 | /* |
502 | * Handle various address error exceptions | 504 | * Handle various address error exceptions: |
505 | * - instruction address error: | ||
506 | * misaligned PC | ||
507 | * PC >= 0x80000000 in user mode | ||
508 | * - data address error (read and write) | ||
509 | * misaligned data access | ||
510 | * access to >= 0x80000000 is user mode | ||
511 | * Unfortuntaly we can't distinguish between instruction address error | ||
512 | * and data address errors caused by read acceses. | ||
503 | */ | 513 | */ |
504 | asmlinkage void do_address_error(struct pt_regs *regs, | 514 | asmlinkage void do_address_error(struct pt_regs *regs, |
505 | unsigned long writeaccess, | 515 | unsigned long writeaccess, |
@@ -507,6 +517,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
507 | { | 517 | { |
508 | unsigned long error_code = 0; | 518 | unsigned long error_code = 0; |
509 | mm_segment_t oldfs; | 519 | mm_segment_t oldfs; |
520 | siginfo_t info; | ||
510 | #ifndef CONFIG_CPU_SH2A | 521 | #ifndef CONFIG_CPU_SH2A |
511 | u16 instruction; | 522 | u16 instruction; |
512 | int tmp; | 523 | int tmp; |
@@ -520,22 +531,15 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
520 | oldfs = get_fs(); | 531 | oldfs = get_fs(); |
521 | 532 | ||
522 | if (user_mode(regs)) { | 533 | if (user_mode(regs)) { |
534 | int si_code = BUS_ADRERR; | ||
535 | |||
523 | local_irq_enable(); | 536 | local_irq_enable(); |
524 | current->thread.error_code = error_code; | ||
525 | #ifdef CONFIG_CPU_SH2 | ||
526 | /* | ||
527 | * On the SH-2, we only have a single vector for address | ||
528 | * errors, there's no differentiating between a load error | ||
529 | * and a store error. | ||
530 | */ | ||
531 | current->thread.trap_no = 9; | ||
532 | #else | ||
533 | current->thread.trap_no = (writeaccess) ? 8 : 7; | ||
534 | #endif | ||
535 | 537 | ||
536 | /* bad PC is not something we can fix */ | 538 | /* bad PC is not something we can fix */ |
537 | if (regs->pc & 1) | 539 | if (regs->pc & 1) { |
540 | si_code = BUS_ADRALN; | ||
538 | goto uspace_segv; | 541 | goto uspace_segv; |
542 | } | ||
539 | 543 | ||
540 | #ifndef CONFIG_CPU_SH2A | 544 | #ifndef CONFIG_CPU_SH2A |
541 | set_fs(USER_DS); | 545 | set_fs(USER_DS); |
@@ -554,9 +558,16 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
554 | return; /* sorted */ | 558 | return; /* sorted */ |
555 | #endif | 559 | #endif |
556 | 560 | ||
557 | uspace_segv: | 561 | uspace_segv: |
558 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); | 562 | printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " |
559 | force_sig(SIGSEGV, current); | 563 | "access (PC %lx PR %lx)\n", current->comm, regs->pc, |
564 | regs->pr); | ||
565 | |||
566 | info.si_signo = SIGBUS; | ||
567 | info.si_errno = 0; | ||
568 | info.si_code = si_code; | ||
569 | info.si_addr = (void *) address; | ||
570 | force_sig_info(SIGBUS, &info, current); | ||
560 | } else { | 571 | } else { |
561 | if (regs->pc & 1) | 572 | if (regs->pc & 1) |
562 | die("unaligned program counter", regs, error_code); | 573 | die("unaligned program counter", regs, error_code); |
@@ -574,7 +585,9 @@ asmlinkage void do_address_error(struct pt_regs *regs, | |||
574 | handle_unaligned_access(instruction, regs); | 585 | handle_unaligned_access(instruction, regs); |
575 | set_fs(oldfs); | 586 | set_fs(oldfs); |
576 | #else | 587 | #else |
577 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); | 588 | printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " |
589 | "access\n", current->comm); | ||
590 | |||
578 | force_sig(SIGSEGV, current); | 591 | force_sig(SIGSEGV, current); |
579 | #endif | 592 | #endif |
580 | } | 593 | } |
@@ -617,9 +630,6 @@ asmlinkage void do_divide_error(unsigned long r4, unsigned long r5, | |||
617 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); | 630 | struct pt_regs *regs = RELOC_HIDE(&__regs, 0); |
618 | siginfo_t info; | 631 | siginfo_t info; |
619 | 632 | ||
620 | current->thread.trap_no = r4; | ||
621 | current->thread.error_code = 0; | ||
622 | |||
623 | switch (r4) { | 633 | switch (r4) { |
624 | case TRAP_DIVZERO_ERROR: | 634 | case TRAP_DIVZERO_ERROR: |
625 | info.si_code = FPE_INTDIV; | 635 | info.si_code = FPE_INTDIV; |
@@ -662,7 +672,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | |||
662 | 672 | ||
663 | #ifdef CONFIG_SH_DSP | 673 | #ifdef CONFIG_SH_DSP |
664 | /* Check if it's a DSP instruction */ | 674 | /* Check if it's a DSP instruction */ |
665 | if (is_dsp_inst(regs)) { | 675 | if (is_dsp_inst(regs)) { |
666 | /* Enable DSP mode, and restart instruction. */ | 676 | /* Enable DSP mode, and restart instruction. */ |
667 | regs->sr |= SR_DSP; | 677 | regs->sr |= SR_DSP; |
668 | return; | 678 | return; |
@@ -672,8 +682,6 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | |||
672 | lookup_exception_vector(error_code); | 682 | lookup_exception_vector(error_code); |
673 | 683 | ||
674 | local_irq_enable(); | 684 | local_irq_enable(); |
675 | tsk->thread.error_code = error_code; | ||
676 | tsk->thread.trap_no = TRAP_RESERVED_INST; | ||
677 | CHK_REMOTE_DEBUG(regs); | 685 | CHK_REMOTE_DEBUG(regs); |
678 | force_sig(SIGILL, tsk); | 686 | force_sig(SIGILL, tsk); |
679 | die_if_no_fixup("reserved instruction", regs, error_code); | 687 | die_if_no_fixup("reserved instruction", regs, error_code); |
@@ -745,8 +753,6 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, | |||
745 | lookup_exception_vector(error_code); | 753 | lookup_exception_vector(error_code); |
746 | 754 | ||
747 | local_irq_enable(); | 755 | local_irq_enable(); |
748 | tsk->thread.error_code = error_code; | ||
749 | tsk->thread.trap_no = TRAP_RESERVED_INST; | ||
750 | CHK_REMOTE_DEBUG(regs); | 756 | CHK_REMOTE_DEBUG(regs); |
751 | force_sig(SIGILL, tsk); | 757 | force_sig(SIGILL, tsk); |
752 | die_if_no_fixup("illegal slot instruction", regs, error_code); | 758 | die_if_no_fixup("illegal slot instruction", regs, error_code); |
@@ -805,7 +811,7 @@ void *set_exception_table_vec(unsigned int vec, void *handler) | |||
805 | { | 811 | { |
806 | extern void *exception_handling_table[]; | 812 | extern void *exception_handling_table[]; |
807 | void *old_handler; | 813 | void *old_handler; |
808 | 814 | ||
809 | old_handler = exception_handling_table[vec]; | 815 | old_handler = exception_handling_table[vec]; |
810 | exception_handling_table[vec] = handler; | 816 | exception_handling_table[vec] = handler; |
811 | return old_handler; | 817 | return old_handler; |
@@ -841,7 +847,7 @@ void __init trap_init(void) | |||
841 | set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); | 847 | set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error); |
842 | set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); | 848 | set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error); |
843 | #endif | 849 | #endif |
844 | 850 | ||
845 | /* Setup VBR for boot cpu */ | 851 | /* Setup VBR for boot cpu */ |
846 | per_cpu_trap_init(); | 852 | per_cpu_trap_init(); |
847 | } | 853 | } |
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c index 68663b8f99ae..43bed2cb00e3 100644 --- a/arch/sh/mm/fault.c +++ b/arch/sh/mm/fault.c | |||
@@ -26,13 +26,16 @@ extern void die(const char *,struct pt_regs *,long); | |||
26 | * and the problem, and then passes it off to one of the appropriate | 26 | * and the problem, and then passes it off to one of the appropriate |
27 | * routines. | 27 | * routines. |
28 | */ | 28 | */ |
29 | asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | 29 | asmlinkage void __kprobes do_page_fault(struct pt_regs *regs, |
30 | unsigned long address) | 30 | unsigned long writeaccess, |
31 | unsigned long address) | ||
31 | { | 32 | { |
32 | struct task_struct *tsk; | 33 | struct task_struct *tsk; |
33 | struct mm_struct *mm; | 34 | struct mm_struct *mm; |
34 | struct vm_area_struct * vma; | 35 | struct vm_area_struct * vma; |
35 | unsigned long page; | 36 | unsigned long page; |
37 | int si_code; | ||
38 | siginfo_t info; | ||
36 | 39 | ||
37 | #ifdef CONFIG_SH_KGDB | 40 | #ifdef CONFIG_SH_KGDB |
38 | if (kgdb_nofault && kgdb_bus_err_hook) | 41 | if (kgdb_nofault && kgdb_bus_err_hook) |
@@ -41,6 +44,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | |||
41 | 44 | ||
42 | tsk = current; | 45 | tsk = current; |
43 | mm = tsk->mm; | 46 | mm = tsk->mm; |
47 | si_code = SEGV_MAPERR; | ||
44 | 48 | ||
45 | /* | 49 | /* |
46 | * If we're in an interrupt or have no user | 50 | * If we're in an interrupt or have no user |
@@ -65,6 +69,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, | |||
65 | * we can handle it.. | 69 | * we can handle it.. |
66 | */ | 70 | */ |
67 | good_area: | 71 | good_area: |
72 | si_code = SEGV_ACCERR; | ||
68 | if (writeaccess) { | 73 | if (writeaccess) { |
69 | if (!(vma->vm_flags & VM_WRITE)) | 74 | if (!(vma->vm_flags & VM_WRITE)) |
70 | goto bad_area; | 75 | goto bad_area; |
@@ -105,9 +110,11 @@ bad_area: | |||
105 | up_read(&mm->mmap_sem); | 110 | up_read(&mm->mmap_sem); |
106 | 111 | ||
107 | if (user_mode(regs)) { | 112 | if (user_mode(regs)) { |
108 | tsk->thread.address = address; | 113 | info.si_signo = SIGSEGV; |
109 | tsk->thread.error_code = writeaccess; | 114 | info.si_errno = 0; |
110 | force_sig(SIGSEGV, tsk); | 115 | info.si_code = si_code; |
116 | info.si_addr = (void *) address; | ||
117 | force_sig_info(SIGSEGV, &info, tsk); | ||
111 | return; | 118 | return; |
112 | } | 119 | } |
113 | 120 | ||
@@ -166,10 +173,11 @@ do_sigbus: | |||
166 | * Send a sigbus, regardless of whether we were in kernel | 173 | * Send a sigbus, regardless of whether we were in kernel |
167 | * or user mode. | 174 | * or user mode. |
168 | */ | 175 | */ |
169 | tsk->thread.address = address; | 176 | info.si_signo = SIGBUS; |
170 | tsk->thread.error_code = writeaccess; | 177 | info.si_errno = 0; |
171 | tsk->thread.trap_no = 14; | 178 | info.si_code = BUS_ADRERR; |
172 | force_sig(SIGBUS, tsk); | 179 | info.si_addr = (void *)address; |
180 | force_sig_info(SIGBUS, &info, tsk); | ||
173 | 181 | ||
174 | /* Kernel mode? Handle exceptions or die */ | 182 | /* Kernel mode? Handle exceptions or die */ |
175 | if (!user_mode(regs)) | 183 | if (!user_mode(regs)) |