aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/traps.c')
-rw-r--r--arch/sh/kernel/traps.c235
1 files changed, 182 insertions, 53 deletions
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index 53dfa55f3156..ec110157992d 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -18,13 +18,15 @@
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/kallsyms.h> 19#include <linux/kallsyms.h>
20#include <linux/io.h> 20#include <linux/io.h>
21#include <linux/debug_locks.h>
22#include <linux/limits.h>
21#include <asm/system.h> 23#include <asm/system.h>
22#include <asm/uaccess.h> 24#include <asm/uaccess.h>
23 25
24#ifdef CONFIG_SH_KGDB 26#ifdef CONFIG_SH_KGDB
25#include <asm/kgdb.h> 27#include <asm/kgdb.h>
26#define CHK_REMOTE_DEBUG(regs) \ 28#define CHK_REMOTE_DEBUG(regs) \
27{ \ 29{ \
28 if (kgdb_debug_hook && !user_mode(regs))\ 30 if (kgdb_debug_hook && !user_mode(regs))\
29 (*kgdb_debug_hook)(regs); \ 31 (*kgdb_debug_hook)(regs); \
30} 32}
@@ -33,8 +35,13 @@
33#endif 35#endif
34 36
35#ifdef CONFIG_CPU_SH2 37#ifdef CONFIG_CPU_SH2
36#define TRAP_RESERVED_INST 4 38# define TRAP_RESERVED_INST 4
37#define TRAP_ILLEGAL_SLOT_INST 6 39# define TRAP_ILLEGAL_SLOT_INST 6
40# define TRAP_ADDRESS_ERROR 9
41# ifdef CONFIG_CPU_SH2A
42# define TRAP_DIVZERO_ERROR 17
43# define TRAP_DIVOVF_ERROR 18
44# endif
38#else 45#else
39#define TRAP_RESERVED_INST 12 46#define TRAP_RESERVED_INST 12
40#define TRAP_ILLEGAL_SLOT_INST 13 47#define TRAP_ILLEGAL_SLOT_INST 13
@@ -88,7 +95,7 @@ void die(const char * str, struct pt_regs * regs, long err)
88 95
89 if (!user_mode(regs) || in_interrupt()) 96 if (!user_mode(regs) || in_interrupt())
90 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE + 97 dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
91 (unsigned long)task_stack_page(current)); 98 (unsigned long)task_stack_page(current));
92 99
93 bust_spinlocks(0); 100 bust_spinlocks(0);
94 spin_unlock_irq(&die_lock); 101 spin_unlock_irq(&die_lock);
@@ -102,8 +109,6 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs,
102 die(str, regs, err); 109 die(str, regs, err);
103} 110}
104 111
105static int handle_unaligned_notify_count = 10;
106
107/* 112/*
108 * try and fix up kernelspace address errors 113 * try and fix up kernelspace address errors
109 * - userspace errors just cause EFAULT to be returned, resulting in SEGV 114 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
@@ -125,6 +130,40 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
125 return -EFAULT; 130 return -EFAULT;
126} 131}
127 132
133#ifdef CONFIG_BUG
134#ifdef CONFIG_DEBUG_BUGVERBOSE
135static inline void do_bug_verbose(struct pt_regs *regs)
136{
137 struct bug_frame f;
138 long len;
139
140 if (__copy_from_user(&f, (const void __user *)regs->pc,
141 sizeof(struct bug_frame)))
142 return;
143
144 len = __strnlen_user(f.file, PATH_MAX) - 1;
145 if (unlikely(len < 0 || len >= PATH_MAX))
146 f.file = "<bad filename>";
147 len = __strnlen_user(f.func, PATH_MAX) - 1;
148 if (unlikely(len < 0 || len >= PATH_MAX))
149 f.func = "<bad function>";
150
151 printk(KERN_ALERT "kernel BUG in %s() at %s:%d!\n",
152 f.func, f.file, f.line);
153}
154#else
155static inline void do_bug_verbose(struct pt_regs *regs)
156{
157}
158#endif /* CONFIG_DEBUG_BUGVERBOSE */
159#endif /* CONFIG_BUG */
160
161void handle_BUG(struct pt_regs *regs)
162{
163 do_bug_verbose(regs);
164 die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
165}
166
128/* 167/*
129 * handle an instruction that does an unaligned memory access by emulating the 168 * handle an instruction that does an unaligned memory access by emulating the
130 * desired behaviour 169 * desired behaviour
@@ -198,7 +237,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
198 if (copy_to_user(dst,src,4)) 237 if (copy_to_user(dst,src,4))
199 goto fetch_fault; 238 goto fetch_fault;
200 ret = 0; 239 ret = 0;
201 break; 240 break;
202 241
203 case 2: /* mov.[bwl] to memory, possibly with pre-decrement */ 242 case 2: /* mov.[bwl] to memory, possibly with pre-decrement */
204 if (instruction & 4) 243 if (instruction & 4)
@@ -222,7 +261,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
222 if (copy_from_user(dst,src,4)) 261 if (copy_from_user(dst,src,4))
223 goto fetch_fault; 262 goto fetch_fault;
224 ret = 0; 263 ret = 0;
225 break; 264 break;
226 265
227 case 6: /* mov.[bwl] from memory, possibly with post-increment */ 266 case 6: /* mov.[bwl] from memory, possibly with post-increment */
228 src = (unsigned char*) *rm; 267 src = (unsigned char*) *rm;
@@ -230,7 +269,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
230 *rm += count; 269 *rm += count;
231 dst = (unsigned char*) rn; 270 dst = (unsigned char*) rn;
232 *(unsigned long*)dst = 0; 271 *(unsigned long*)dst = 0;
233 272
234#ifdef __LITTLE_ENDIAN__ 273#ifdef __LITTLE_ENDIAN__
235 if (copy_from_user(dst, src, count)) 274 if (copy_from_user(dst, src, count))
236 goto fetch_fault; 275 goto fetch_fault;
@@ -241,7 +280,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
241 } 280 }
242#else 281#else
243 dst += 4-count; 282 dst += 4-count;
244 283
245 if (copy_from_user(dst, src, count)) 284 if (copy_from_user(dst, src, count))
246 goto fetch_fault; 285 goto fetch_fault;
247 286
@@ -320,7 +359,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
320 return -EFAULT; 359 return -EFAULT;
321 360
322 /* kernel */ 361 /* kernel */
323 die("delay-slot-insn faulting in handle_unaligned_delayslot", regs, 0); 362 die("delay-slot-insn faulting in handle_unaligned_delayslot",
363 regs, 0);
324 } 364 }
325 365
326 return handle_unaligned_ins(instruction,regs); 366 return handle_unaligned_ins(instruction,regs);
@@ -342,6 +382,13 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
342#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4) 382#define SH_PC_8BIT_OFFSET(instr) ((((signed char)(instr))*2) + 4)
343#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4) 383#define SH_PC_12BIT_OFFSET(instr) ((((signed short)(instr<<4))>>3) + 4)
344 384
385/*
386 * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
387 * opcodes..
388 */
389#ifndef CONFIG_CPU_SH2A
390static int handle_unaligned_notify_count = 10;
391
345static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) 392static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
346{ 393{
347 u_int rm; 394 u_int rm;
@@ -354,7 +401,8 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
354 if (user_mode(regs) && handle_unaligned_notify_count>0) { 401 if (user_mode(regs) && handle_unaligned_notify_count>0) {
355 handle_unaligned_notify_count--; 402 handle_unaligned_notify_count--;
356 403
357 printk("Fixing up unaligned userspace access in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", 404 printk(KERN_NOTICE "Fixing up unaligned userspace access "
405 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
358 current->comm,current->pid,(u16*)regs->pc,instruction); 406 current->comm,current->pid,(u16*)regs->pc,instruction);
359 } 407 }
360 408
@@ -478,32 +526,58 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
478 regs->pc += 2; 526 regs->pc += 2;
479 return ret; 527 return ret;
480} 528}
529#endif /* CONFIG_CPU_SH2A */
530
531#ifdef CONFIG_CPU_HAS_SR_RB
532#define lookup_exception_vector(x) \
533 __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
534#else
535#define lookup_exception_vector(x) \
536 __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
537#endif
481 538
482/* 539/*
483 * Handle various address error exceptions 540 * Handle various address error exceptions:
541 * - instruction address error:
542 * misaligned PC
543 * PC >= 0x80000000 in user mode
544 * - data address error (read and write)
545 * misaligned data access
546 * access to >= 0x80000000 is user mode
547 * Unfortuntaly we can't distinguish between instruction address error
548 * and data address errors caused by read acceses.
484 */ 549 */
485asmlinkage void do_address_error(struct pt_regs *regs, 550asmlinkage void do_address_error(struct pt_regs *regs,
486 unsigned long writeaccess, 551 unsigned long writeaccess,
487 unsigned long address) 552 unsigned long address)
488{ 553{
489 unsigned long error_code; 554 unsigned long error_code = 0;
490 mm_segment_t oldfs; 555 mm_segment_t oldfs;
556 siginfo_t info;
557#ifndef CONFIG_CPU_SH2A
491 u16 instruction; 558 u16 instruction;
492 int tmp; 559 int tmp;
560#endif
493 561
494 asm volatile("stc r2_bank,%0": "=r" (error_code)); 562 /* Intentional ifdef */
563#ifdef CONFIG_CPU_HAS_SR_RB
564 lookup_exception_vector(error_code);
565#endif
495 566
496 oldfs = get_fs(); 567 oldfs = get_fs();
497 568
498 if (user_mode(regs)) { 569 if (user_mode(regs)) {
570 int si_code = BUS_ADRERR;
571
499 local_irq_enable(); 572 local_irq_enable();
500 current->thread.error_code = error_code;
501 current->thread.trap_no = (writeaccess) ? 8 : 7;
502 573
503 /* bad PC is not something we can fix */ 574 /* bad PC is not something we can fix */
504 if (regs->pc & 1) 575 if (regs->pc & 1) {
576 si_code = BUS_ADRALN;
505 goto uspace_segv; 577 goto uspace_segv;
578 }
506 579
580#ifndef CONFIG_CPU_SH2A
507 set_fs(USER_DS); 581 set_fs(USER_DS);
508 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { 582 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
509 /* Argh. Fault on the instruction itself. 583 /* Argh. Fault on the instruction itself.
@@ -518,14 +592,23 @@ asmlinkage void do_address_error(struct pt_regs *regs,
518 592
519 if (tmp==0) 593 if (tmp==0)
520 return; /* sorted */ 594 return; /* sorted */
595#endif
521 596
522 uspace_segv: 597uspace_segv:
523 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); 598 printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
524 force_sig(SIGSEGV, current); 599 "access (PC %lx PR %lx)\n", current->comm, regs->pc,
600 regs->pr);
601
602 info.si_signo = SIGBUS;
603 info.si_errno = 0;
604 info.si_code = si_code;
605 info.si_addr = (void *) address;
606 force_sig_info(SIGBUS, &info, current);
525 } else { 607 } else {
526 if (regs->pc & 1) 608 if (regs->pc & 1)
527 die("unaligned program counter", regs, error_code); 609 die("unaligned program counter", regs, error_code);
528 610
611#ifndef CONFIG_CPU_SH2A
529 set_fs(KERNEL_DS); 612 set_fs(KERNEL_DS);
530 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { 613 if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
531 /* Argh. Fault on the instruction itself. 614 /* Argh. Fault on the instruction itself.
@@ -537,6 +620,12 @@ asmlinkage void do_address_error(struct pt_regs *regs,
537 620
538 handle_unaligned_access(instruction, regs); 621 handle_unaligned_access(instruction, regs);
539 set_fs(oldfs); 622 set_fs(oldfs);
623#else
624 printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
625 "access\n", current->comm);
626
627 force_sig(SIGSEGV, current);
628#endif
540 } 629 }
541} 630}
542 631
@@ -548,7 +637,7 @@ int is_dsp_inst(struct pt_regs *regs)
548{ 637{
549 unsigned short inst; 638 unsigned short inst;
550 639
551 /* 640 /*
552 * Safe guard if DSP mode is already enabled or we're lacking 641 * Safe guard if DSP mode is already enabled or we're lacking
553 * the DSP altogether. 642 * the DSP altogether.
554 */ 643 */
@@ -569,27 +658,49 @@ int is_dsp_inst(struct pt_regs *regs)
569#define is_dsp_inst(regs) (0) 658#define is_dsp_inst(regs) (0)
570#endif /* CONFIG_SH_DSP */ 659#endif /* CONFIG_SH_DSP */
571 660
661#ifdef CONFIG_CPU_SH2A
662asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
663 unsigned long r6, unsigned long r7,
664 struct pt_regs __regs)
665{
666 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
667 siginfo_t info;
668
669 switch (r4) {
670 case TRAP_DIVZERO_ERROR:
671 info.si_code = FPE_INTDIV;
672 break;
673 case TRAP_DIVOVF_ERROR:
674 info.si_code = FPE_INTOVF;
675 break;
676 }
677
678 force_sig_info(SIGFPE, &info, current);
679}
680#endif
681
572/* arch/sh/kernel/cpu/sh4/fpu.c */ 682/* arch/sh/kernel/cpu/sh4/fpu.c */
573extern int do_fpu_inst(unsigned short, struct pt_regs *); 683extern int do_fpu_inst(unsigned short, struct pt_regs *);
574extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, 684extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5,
575 unsigned long r6, unsigned long r7, struct pt_regs regs); 685 unsigned long r6, unsigned long r7, struct pt_regs __regs);
576 686
577asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, 687asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
578 unsigned long r6, unsigned long r7, 688 unsigned long r6, unsigned long r7,
579 struct pt_regs regs) 689 struct pt_regs __regs)
580{ 690{
691 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
581 unsigned long error_code; 692 unsigned long error_code;
582 struct task_struct *tsk = current; 693 struct task_struct *tsk = current;
583 694
584#ifdef CONFIG_SH_FPU_EMU 695#ifdef CONFIG_SH_FPU_EMU
585 unsigned short inst; 696 unsigned short inst = 0;
586 int err; 697 int err;
587 698
588 get_user(inst, (unsigned short*)regs.pc); 699 get_user(inst, (unsigned short*)regs->pc);
589 700
590 err = do_fpu_inst(inst, &regs); 701 err = do_fpu_inst(inst, regs);
591 if (!err) { 702 if (!err) {
592 regs.pc += 2; 703 regs->pc += 2;
593 return; 704 return;
594 } 705 }
595 /* not a FPU inst. */ 706 /* not a FPU inst. */
@@ -597,20 +708,19 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
597 708
598#ifdef CONFIG_SH_DSP 709#ifdef CONFIG_SH_DSP
599 /* Check if it's a DSP instruction */ 710 /* Check if it's a DSP instruction */
600 if (is_dsp_inst(&regs)) { 711 if (is_dsp_inst(regs)) {
601 /* Enable DSP mode, and restart instruction. */ 712 /* Enable DSP mode, and restart instruction. */
602 regs.sr |= SR_DSP; 713 regs->sr |= SR_DSP;
603 return; 714 return;
604 } 715 }
605#endif 716#endif
606 717
607 asm volatile("stc r2_bank, %0": "=r" (error_code)); 718 lookup_exception_vector(error_code);
719
608 local_irq_enable(); 720 local_irq_enable();
609 tsk->thread.error_code = error_code; 721 CHK_REMOTE_DEBUG(regs);
610 tsk->thread.trap_no = TRAP_RESERVED_INST;
611 CHK_REMOTE_DEBUG(&regs);
612 force_sig(SIGILL, tsk); 722 force_sig(SIGILL, tsk);
613 die_if_no_fixup("reserved instruction", &regs, error_code); 723 die_if_no_fixup("reserved instruction", regs, error_code);
614} 724}
615 725
616#ifdef CONFIG_SH_FPU_EMU 726#ifdef CONFIG_SH_FPU_EMU
@@ -658,39 +768,41 @@ static int emulate_branch(unsigned short inst, struct pt_regs* regs)
658 768
659asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, 769asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
660 unsigned long r6, unsigned long r7, 770 unsigned long r6, unsigned long r7,
661 struct pt_regs regs) 771 struct pt_regs __regs)
662{ 772{
773 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
663 unsigned long error_code; 774 unsigned long error_code;
664 struct task_struct *tsk = current; 775 struct task_struct *tsk = current;
665#ifdef CONFIG_SH_FPU_EMU 776#ifdef CONFIG_SH_FPU_EMU
666 unsigned short inst; 777 unsigned short inst = 0;
667 778
668 get_user(inst, (unsigned short *)regs.pc + 1); 779 get_user(inst, (unsigned short *)regs->pc + 1);
669 if (!do_fpu_inst(inst, &regs)) { 780 if (!do_fpu_inst(inst, regs)) {
670 get_user(inst, (unsigned short *)regs.pc); 781 get_user(inst, (unsigned short *)regs->pc);
671 if (!emulate_branch(inst, &regs)) 782 if (!emulate_branch(inst, regs))
672 return; 783 return;
673 /* fault in branch.*/ 784 /* fault in branch.*/
674 } 785 }
675 /* not a FPU inst. */ 786 /* not a FPU inst. */
676#endif 787#endif
677 788
678 asm volatile("stc r2_bank, %0": "=r" (error_code)); 789 lookup_exception_vector(error_code);
790
679 local_irq_enable(); 791 local_irq_enable();
680 tsk->thread.error_code = error_code; 792 CHK_REMOTE_DEBUG(regs);
681 tsk->thread.trap_no = TRAP_RESERVED_INST;
682 CHK_REMOTE_DEBUG(&regs);
683 force_sig(SIGILL, tsk); 793 force_sig(SIGILL, tsk);
684 die_if_no_fixup("illegal slot instruction", &regs, error_code); 794 die_if_no_fixup("illegal slot instruction", regs, error_code);
685} 795}
686 796
687asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, 797asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
688 unsigned long r6, unsigned long r7, 798 unsigned long r6, unsigned long r7,
689 struct pt_regs regs) 799 struct pt_regs __regs)
690{ 800{
801 struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
691 long ex; 802 long ex;
692 asm volatile("stc r2_bank, %0" : "=r" (ex)); 803
693 die_if_kernel("exception", &regs, ex); 804 lookup_exception_vector(ex);
805 die_if_kernel("exception", regs, ex);
694} 806}
695 807
696#if defined(CONFIG_SH_STANDARD_BIOS) 808#if defined(CONFIG_SH_STANDARD_BIOS)
@@ -735,12 +847,16 @@ void *set_exception_table_vec(unsigned int vec, void *handler)
735{ 847{
736 extern void *exception_handling_table[]; 848 extern void *exception_handling_table[];
737 void *old_handler; 849 void *old_handler;
738 850
739 old_handler = exception_handling_table[vec]; 851 old_handler = exception_handling_table[vec];
740 exception_handling_table[vec] = handler; 852 exception_handling_table[vec] = handler;
741 return old_handler; 853 return old_handler;
742} 854}
743 855
856extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
857 unsigned long r6, unsigned long r7,
858 struct pt_regs __regs);
859
744void __init trap_init(void) 860void __init trap_init(void)
745{ 861{
746 set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); 862 set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
@@ -759,7 +875,15 @@ void __init trap_init(void)
759 set_exception_table_evt(0x800, do_fpu_state_restore); 875 set_exception_table_evt(0x800, do_fpu_state_restore);
760 set_exception_table_evt(0x820, do_fpu_state_restore); 876 set_exception_table_evt(0x820, do_fpu_state_restore);
761#endif 877#endif
762 878
879#ifdef CONFIG_CPU_SH2
880 set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
881#endif
882#ifdef CONFIG_CPU_SH2A
883 set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
884 set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
885#endif
886
763 /* Setup VBR for boot cpu */ 887 /* Setup VBR for boot cpu */
764 per_cpu_trap_init(); 888 per_cpu_trap_init();
765} 889}
@@ -784,6 +908,11 @@ void show_trace(struct task_struct *tsk, unsigned long *sp,
784 } 908 }
785 909
786 printk("\n"); 910 printk("\n");
911
912 if (!tsk)
913 tsk = current;
914
915 debug_show_held_locks(tsk);
787} 916}
788 917
789void show_stack(struct task_struct *tsk, unsigned long *sp) 918void show_stack(struct task_struct *tsk, unsigned long *sp)