diff options
| author | Stuart Menefy <stuart.menefy@st.com> | 2006-11-20 23:34:04 -0500 |
|---|---|---|
| committer | Paul Mundt <lethal@linux-sh.org> | 2006-12-05 20:45:38 -0500 |
| commit | b5a1bcbee434b843c8850a968d9a6c7541f1be9d (patch) | |
| tree | 2745f5efa2b4d6dfe18f4f186738612f0e77f79c | |
| parent | f0bc814cfbc212683c882e58b3d1afec6b3e3aa3 (diff) | |
sh: Set up correct siginfo structures for page faults.
Remove the previous saving of fault codes into the thread_struct
as they are never used, and appeared to be inherited from x86.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
| -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 | ||||
| -rw-r--r-- | include/asm-sh/processor.h | 12 |
4 files changed, 61 insertions, 58 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)) |
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index da22ac30c75f..4a90e7cd8199 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h | |||
| @@ -136,12 +136,11 @@ union sh_fpu_union { | |||
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | struct thread_struct { | 138 | struct thread_struct { |
| 139 | /* Saved registers when thread is descheduled */ | ||
| 139 | unsigned long sp; | 140 | unsigned long sp; |
| 140 | unsigned long pc; | 141 | unsigned long pc; |
| 141 | 142 | ||
| 142 | unsigned long trap_no, error_code; | 143 | /* Hardware debugging registers */ |
| 143 | unsigned long address; | ||
| 144 | /* Hardware debugging registers may come here */ | ||
| 145 | unsigned long ubc_pc; | 144 | unsigned long ubc_pc; |
| 146 | 145 | ||
| 147 | /* floating point info */ | 146 | /* floating point info */ |
| @@ -156,12 +155,7 @@ typedef struct { | |||
| 156 | extern int ubc_usercnt; | 155 | extern int ubc_usercnt; |
| 157 | 156 | ||
| 158 | #define INIT_THREAD { \ | 157 | #define INIT_THREAD { \ |
| 159 | sizeof(init_stack) + (long) &init_stack, /* sp */ \ | 158 | .sp = sizeof(init_stack) + (long) &init_stack, \ |
| 160 | 0, /* pc */ \ | ||
| 161 | 0, 0, \ | ||
| 162 | 0, \ | ||
| 163 | 0, \ | ||
| 164 | {{{0,}},} /* fpu state */ \ | ||
| 165 | } | 159 | } |
| 166 | 160 | ||
| 167 | /* | 161 | /* |
