|
36 | 36 |
|
37 | 37 | #ifdef CONFIG_SH_KGDB |
38 | 38 | #include <asm/kgdb.h> |
39 | | -#define CHK_REMOTE_DEBUG(regs) \ |
40 | | -{ \ |
41 | | - if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \ |
42 | | - { \ |
43 | | - (*kgdb_debug_hook)(regs); \ |
44 | | - } \ |
| 39 | +#define CHK_REMOTE_DEBUG(regs) \ |
| 40 | +{ \ |
| 41 | + if (kgdb_debug_hook && !user_mode(regs))\ |
| 42 | + (*kgdb_debug_hook)(regs); \ |
45 | 43 | } |
46 | 44 | #else |
47 | 45 | #define CHK_REMOTE_DEBUG(regs) |
48 | 46 | #endif |
49 | 47 |
|
50 | | -#define DO_ERROR(trapnr, signr, str, name, tsk) \ |
51 | | -asmlinkage void do_##name(unsigned long r4, unsigned long r5, \ |
52 | | - unsigned long r6, unsigned long r7, \ |
53 | | - struct pt_regs regs) \ |
54 | | -{ \ |
55 | | - unsigned long error_code; \ |
56 | | - \ |
57 | | - /* Check if it's a DSP instruction */ \ |
58 | | - if (is_dsp_inst(®s)) { \ |
59 | | - /* Enable DSP mode, and restart instruction. */ \ |
60 | | - regs.sr |= SR_DSP; \ |
61 | | - return; \ |
62 | | - } \ |
63 | | - \ |
64 | | - asm volatile("stc r2_bank, %0": "=r" (error_code)); \ |
65 | | - local_irq_enable(); \ |
66 | | - tsk->thread.error_code = error_code; \ |
67 | | - tsk->thread.trap_no = trapnr; \ |
68 | | - CHK_REMOTE_DEBUG(®s); \ |
69 | | - force_sig(signr, tsk); \ |
70 | | - die_if_no_fixup(str,®s,error_code); \ |
71 | | -} |
72 | | - |
73 | 48 | #ifdef CONFIG_CPU_SH2 |
74 | 49 | #define TRAP_RESERVED_INST 4 |
75 | 50 | #define TRAP_ILLEGAL_SLOT_INST 6 |
@@ -575,8 +550,117 @@ int is_dsp_inst(struct pt_regs *regs) |
575 | 550 | #define is_dsp_inst(regs) (0) |
576 | 551 | #endif /* CONFIG_SH_DSP */ |
577 | 552 |
|
578 | | -DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current) |
579 | | -DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current) |
| 553 | +extern int do_fpu_inst(unsigned short, struct pt_regs*); |
| 554 | + |
| 555 | +asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, |
| 556 | + unsigned long r6, unsigned long r7, |
| 557 | + struct pt_regs regs) |
| 558 | +{ |
| 559 | + unsigned long error_code; |
| 560 | + struct task_struct *tsk = current; |
| 561 | + |
| 562 | +#ifdef CONFIG_SH_FPU_EMU |
| 563 | + unsigned short inst; |
| 564 | + int err; |
| 565 | + |
| 566 | + get_user(inst, (unsigned short*)regs.pc); |
| 567 | + |
| 568 | + err = do_fpu_inst(inst, ®s); |
| 569 | + if (!err) { |
| 570 | + regs.pc += 2; |
| 571 | + return; |
| 572 | + } |
| 573 | + /* not a FPU inst. */ |
| 574 | +#endif |
| 575 | + |
| 576 | +#ifdef CONFIG_SH_DSP |
| 577 | + /* Check if it's a DSP instruction */ |
| 578 | + if (is_dsp_inst(®s)) { |
| 579 | + /* Enable DSP mode, and restart instruction. */ |
| 580 | + regs.sr |= SR_DSP; |
| 581 | + return; |
| 582 | + } |
| 583 | +#endif |
| 584 | + |
| 585 | + asm volatile("stc r2_bank, %0": "=r" (error_code)); |
| 586 | + local_irq_enable(); |
| 587 | + tsk->thread.error_code = error_code; |
| 588 | + tsk->thread.trap_no = TRAP_RESERVED_INST; |
| 589 | + CHK_REMOTE_DEBUG(®s); |
| 590 | + force_sig(SIGILL, tsk); |
| 591 | + die_if_no_fixup("reserved instruction", ®s, error_code); |
| 592 | +} |
| 593 | + |
| 594 | +#ifdef CONFIG_SH_FPU_EMU |
| 595 | +static int emulate_branch(unsigned short inst, struct pt_regs* regs) |
| 596 | +{ |
| 597 | + /* |
| 598 | + * bfs: 8fxx: PC+=d*2+4; |
| 599 | + * bts: 8dxx: PC+=d*2+4; |
| 600 | + * bra: axxx: PC+=D*2+4; |
| 601 | + * bsr: bxxx: PC+=D*2+4 after PR=PC+4; |
| 602 | + * braf:0x23: PC+=Rn*2+4; |
| 603 | + * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4; |
| 604 | + * jmp: 4x2b: PC=Rn; |
| 605 | + * jsr: 4x0b: PC=Rn after PR=PC+4; |
| 606 | + * rts: 000b: PC=PR; |
| 607 | + */ |
| 608 | + if ((inst & 0xfd00) == 0x8d00) { |
| 609 | + regs->pc += SH_PC_8BIT_OFFSET(inst); |
| 610 | + return 0; |
| 611 | + } |
| 612 | + |
| 613 | + if ((inst & 0xe000) == 0xa000) { |
| 614 | + regs->pc += SH_PC_12BIT_OFFSET(inst); |
| 615 | + return 0; |
| 616 | + } |
| 617 | + |
| 618 | + if ((inst & 0xf0df) == 0x0003) { |
| 619 | + regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4; |
| 620 | + return 0; |
| 621 | + } |
| 622 | + |
| 623 | + if ((inst & 0xf0df) == 0x400b) { |
| 624 | + regs->pc = regs->regs[(inst & 0x0f00) >> 8]; |
| 625 | + return 0; |
| 626 | + } |
| 627 | + |
| 628 | + if ((inst & 0xffff) == 0x000b) { |
| 629 | + regs->pc = regs->pr; |
| 630 | + return 0; |
| 631 | + } |
| 632 | + |
| 633 | + return 1; |
| 634 | +} |
| 635 | +#endif |
| 636 | + |
| 637 | +asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, |
| 638 | + unsigned long r6, unsigned long r7, |
| 639 | + struct pt_regs regs) |
| 640 | +{ |
| 641 | + unsigned long error_code; |
| 642 | + struct task_struct *tsk = current; |
| 643 | +#ifdef CONFIG_SH_FPU_EMU |
| 644 | + unsigned short inst; |
| 645 | + |
| 646 | + get_user(inst, (unsigned short *)regs.pc + 1); |
| 647 | + if (!do_fpu_inst(inst, ®s)) { |
| 648 | + get_user(inst, (unsigned short *)regs.pc); |
| 649 | + if (!emulate_branch(inst, ®s)) |
| 650 | + return; |
| 651 | + /* fault in branch.*/ |
| 652 | + } |
| 653 | + /* not a FPU inst. */ |
| 654 | +#endif |
| 655 | + |
| 656 | + asm volatile("stc r2_bank, %0": "=r" (error_code)); |
| 657 | + local_irq_enable(); |
| 658 | + tsk->thread.error_code = error_code; |
| 659 | + tsk->thread.trap_no = TRAP_RESERVED_INST; |
| 660 | + CHK_REMOTE_DEBUG(®s); |
| 661 | + force_sig(SIGILL, tsk); |
| 662 | + die_if_no_fixup("illegal slot instruction", ®s, error_code); |
| 663 | +} |
580 | 664 |
|
581 | 665 | asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, |
582 | 666 | unsigned long r6, unsigned long r7, |
@@ -634,14 +718,16 @@ void __init trap_init(void) |
634 | 718 | exception_handling_table[TRAP_ILLEGAL_SLOT_INST] |
635 | 719 | = (void *)do_illegal_slot_inst; |
636 | 720 |
|
637 | | -#ifdef CONFIG_CPU_SH4 |
638 | | - if (!(cpu_data->flags & CPU_HAS_FPU)) { |
639 | | - /* For SH-4 lacking an FPU, treat floating point instructions |
640 | | - as reserved. */ |
641 | | - /* entry 64 corresponds to EXPEVT=0x800 */ |
642 | | - exception_handling_table[64] = (void *)do_reserved_inst; |
643 | | - exception_handling_table[65] = (void *)do_illegal_slot_inst; |
644 | | - } |
| 721 | +#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \ |
| 722 | + defined(CONFIG_SH_FPU_EMU) |
| 723 | + /* |
| 724 | + * For SH-4 lacking an FPU, treat floating point instructions as |
| 725 | + * reserved. They'll be handled in the math-emu case, or faulted on |
| 726 | + * otherwise. |
| 727 | + */ |
| 728 | + /* entry 64 corresponds to EXPEVT=0x800 */ |
| 729 | + exception_handling_table[64] = (void *)do_reserved_inst; |
| 730 | + exception_handling_table[65] = (void *)do_illegal_slot_inst; |
645 | 731 | #endif |
646 | 732 |
|
647 | 733 | /* Setup VBR for boot cpu */ |
|
0 commit comments