diff options
Diffstat (limited to 'arch/sh/kernel/traps.c')
-rw-r--r-- | arch/sh/kernel/traps.c | 235 |
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 | ||
105 | static 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 | ||
135 | static 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 | ||
155 | static inline void do_bug_verbose(struct pt_regs *regs) | ||
156 | { | ||
157 | } | ||
158 | #endif /* CONFIG_DEBUG_BUGVERBOSE */ | ||
159 | #endif /* CONFIG_BUG */ | ||
160 | |||
161 | void 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 | ||
390 | static int handle_unaligned_notify_count = 10; | ||
391 | |||
345 | static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) | 392 | static 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 | */ |
485 | asmlinkage void do_address_error(struct pt_regs *regs, | 550 | asmlinkage 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: | 597 | uspace_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 | ||
662 | asmlinkage 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 */ |
573 | extern int do_fpu_inst(unsigned short, struct pt_regs *); | 683 | extern int do_fpu_inst(unsigned short, struct pt_regs *); |
574 | extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, | 684 | extern 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 | ||
577 | asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, | 687 | asmlinkage 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, ®s); | 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(®s)) { | 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(®s); | ||
612 | force_sig(SIGILL, tsk); | 722 | force_sig(SIGILL, tsk); |
613 | die_if_no_fixup("reserved instruction", ®s, 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 | ||
659 | asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, | 769 | asmlinkage 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, ®s)) { | 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, ®s)) | 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(®s); | ||
683 | force_sig(SIGILL, tsk); | 793 | force_sig(SIGILL, tsk); |
684 | die_if_no_fixup("illegal slot instruction", ®s, error_code); | 794 | die_if_no_fixup("illegal slot instruction", regs, error_code); |
685 | } | 795 | } |
686 | 796 | ||
687 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | 797 | asmlinkage 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", ®s, 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 | ||
856 | extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5, | ||
857 | unsigned long r6, unsigned long r7, | ||
858 | struct pt_regs __regs); | ||
859 | |||
744 | void __init trap_init(void) | 860 | void __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 | ||
789 | void show_stack(struct task_struct *tsk, unsigned long *sp) | 918 | void show_stack(struct task_struct *tsk, unsigned long *sp) |