|
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