33
33
#endif
34
34
35
35
#ifdef CONFIG_CPU_SH2
36
- #define TRAP_RESERVED_INST 4
37
- #define TRAP_ILLEGAL_SLOT_INST 6
36
+ # define TRAP_RESERVED_INST 4
37
+ # define TRAP_ILLEGAL_SLOT_INST 6
38
+ # define TRAP_ADDRESS_ERROR 9
39
+ # ifdef CONFIG_CPU_SH2A
40
+ # define TRAP_DIVZERO_ERROR 17
41
+ # define TRAP_DIVOVF_ERROR 18
42
+ # endif
38
43
#else
39
44
#define TRAP_RESERVED_INST 12
40
45
#define TRAP_ILLEGAL_SLOT_INST 13
@@ -479,31 +484,52 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
479
484
return ret ;
480
485
}
481
486
487
+ #ifdef CONFIG_CPU_HAS_SR_RB
488
+ #define lookup_exception_vector (x ) \
489
+ __asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
490
+ #else
491
+ #define lookup_exception_vector (x ) \
492
+ __asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
493
+ #endif
494
+
482
495
/*
483
496
* Handle various address error exceptions
484
497
*/
485
498
asmlinkage void do_address_error (struct pt_regs * regs ,
486
499
unsigned long writeaccess ,
487
500
unsigned long address )
488
501
{
489
- unsigned long error_code ;
502
+ unsigned long error_code = 0 ;
490
503
mm_segment_t oldfs ;
491
504
u16 instruction ;
492
505
int tmp ;
493
506
494
- asm volatile ("stc r2_bank,%0" : "=r" (error_code ));
507
+ /* Intentional ifdef */
508
+ #ifdef CONFIG_CPU_HAS_SR_RB
509
+ lookup_exception_vector (error_code );
510
+ #endif
495
511
496
512
oldfs = get_fs ();
497
513
498
514
if (user_mode (regs )) {
499
515
local_irq_enable ();
500
516
current -> thread .error_code = error_code ;
517
+ #ifdef CONFIG_CPU_SH2
518
+ /*
519
+ * On the SH-2, we only have a single vector for address
520
+ * errors, there's no differentiating between a load error
521
+ * and a store error.
522
+ */
523
+ current -> thread .trap_no = 9 ;
524
+ #else
501
525
current -> thread .trap_no = (writeaccess ) ? 8 : 7 ;
526
+ #endif
502
527
503
528
/* bad PC is not something we can fix */
504
529
if (regs -> pc & 1 )
505
530
goto uspace_segv ;
506
531
532
+ #ifndef CONFIG_CPU_SH2A
507
533
set_fs (USER_DS );
508
534
if (copy_from_user (& instruction , (u16 * )(regs -> pc ), 2 )) {
509
535
/* Argh. Fault on the instruction itself.
@@ -518,6 +544,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
518
544
519
545
if (tmp == 0 )
520
546
return ; /* sorted */
547
+ #endif
521
548
522
549
uspace_segv :
523
550
printk (KERN_NOTICE "Killing process \"%s\" due to unaligned access\n" , current -> comm );
@@ -526,6 +553,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
526
553
if (regs -> pc & 1 )
527
554
die ("unaligned program counter" , regs , error_code );
528
555
556
+ #ifndef CONFIG_CPU_SH2A
529
557
set_fs (KERNEL_DS );
530
558
if (copy_from_user (& instruction , (u16 * )(regs -> pc ), 2 )) {
531
559
/* Argh. Fault on the instruction itself.
@@ -537,6 +565,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
537
565
538
566
handle_unaligned_access (instruction , regs );
539
567
set_fs (oldfs );
568
+ #else
569
+ printk (KERN_NOTICE "Killing process \"%s\" due to unaligned access\n" , current -> comm );
570
+ force_sig (SIGSEGV , current );
571
+ #endif
540
572
}
541
573
}
542
574
@@ -569,6 +601,29 @@ int is_dsp_inst(struct pt_regs *regs)
569
601
#define is_dsp_inst (regs ) (0)
570
602
#endif /* CONFIG_SH_DSP */
571
603
604
+ #ifdef CONFIG_CPU_SH2A
605
+ asmlinkage void do_divide_error (unsigned long r4 , unsigned long r5 ,
606
+ unsigned long r6 , unsigned long r7 ,
607
+ struct pt_regs regs )
608
+ {
609
+ siginfo_t info ;
610
+
611
+ current -> thread .trap_no = r4 ;
612
+ current -> thread .error_code = 0 ;
613
+
614
+ switch (r4 ) {
615
+ case TRAP_DIVZERO_ERROR :
616
+ info .si_code = FPE_INTDIV ;
617
+ break ;
618
+ case TRAP_DIVOVF_ERROR :
619
+ info .si_code = FPE_INTOVF ;
620
+ break ;
621
+ }
622
+
623
+ force_sig_info (SIGFPE , & info , current );
624
+ }
625
+ #endif
626
+
572
627
/* arch/sh/kernel/cpu/sh4/fpu.c */
573
628
extern int do_fpu_inst (unsigned short , struct pt_regs * );
574
629
extern asmlinkage void do_fpu_state_restore (unsigned long r4 , unsigned long r5 ,
@@ -582,7 +637,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
582
637
struct task_struct * tsk = current ;
583
638
584
639
#ifdef CONFIG_SH_FPU_EMU
585
- unsigned short inst ;
640
+ unsigned short inst = 0 ;
586
641
int err ;
587
642
588
643
get_user (inst , (unsigned short * )regs .pc );
@@ -604,7 +659,8 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
604
659
}
605
660
#endif
606
661
607
- asm volatile ("stc r2_bank, %0" : "=r" (error_code ));
662
+ lookup_exception_vector (error_code );
663
+
608
664
local_irq_enable ();
609
665
tsk -> thread .error_code = error_code ;
610
666
tsk -> thread .trap_no = TRAP_RESERVED_INST ;
@@ -663,7 +719,7 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
663
719
unsigned long error_code ;
664
720
struct task_struct * tsk = current ;
665
721
#ifdef CONFIG_SH_FPU_EMU
666
- unsigned short inst ;
722
+ unsigned short inst = 0 ;
667
723
668
724
get_user (inst , (unsigned short * )regs .pc + 1 );
669
725
if (!do_fpu_inst (inst , & regs )) {
@@ -675,7 +731,8 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
675
731
/* not a FPU inst. */
676
732
#endif
677
733
678
- asm volatile ("stc r2_bank, %0" : "=r" (error_code ));
734
+ lookup_exception_vector (error_code );
735
+
679
736
local_irq_enable ();
680
737
tsk -> thread .error_code = error_code ;
681
738
tsk -> thread .trap_no = TRAP_RESERVED_INST ;
@@ -689,7 +746,8 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
689
746
struct pt_regs regs )
690
747
{
691
748
long ex ;
692
- asm volatile ("stc r2_bank, %0" : "=r" (ex ));
749
+
750
+ lookup_exception_vector (ex );
693
751
die_if_kernel ("exception" , & regs , ex );
694
752
}
695
753
@@ -741,6 +799,10 @@ void *set_exception_table_vec(unsigned int vec, void *handler)
741
799
return old_handler ;
742
800
}
743
801
802
+ extern asmlinkage void address_error_handler (unsigned long r4 , unsigned long r5 ,
803
+ unsigned long r6 , unsigned long r7 ,
804
+ struct pt_regs regs );
805
+
744
806
void __init trap_init (void )
745
807
{
746
808
set_exception_table_vec (TRAP_RESERVED_INST , do_reserved_inst );
@@ -759,6 +821,14 @@ void __init trap_init(void)
759
821
set_exception_table_evt (0x800 , do_fpu_state_restore );
760
822
set_exception_table_evt (0x820 , do_fpu_state_restore );
761
823
#endif
824
+
825
+ #ifdef CONFIG_CPU_SH2
826
+ set_exception_table_vec (TRAP_ADDRESS_ERROR , address_error_handler );
827
+ #endif
828
+ #ifdef CONFIG_CPU_SH2A
829
+ set_exception_table_vec (TRAP_DIVZERO_ERROR , do_divide_error );
830
+ set_exception_table_vec (TRAP_DIVOVF_ERROR , do_divide_error );
831
+ #endif
762
832
763
833
/* Setup VBR for boot cpu */
764
834
per_cpu_trap_init ();
0 commit comments