aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh')
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c7
-rw-r--r--arch/sh/kernel/traps.c74
-rw-r--r--arch/sh/mm/fault.c26
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 */
504asmlinkage void do_address_error(struct pt_regs *regs, 514asmlinkage 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: 561uspace_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 */
29asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess, 29asmlinkage 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 */
67good_area: 71good_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))