Skip to content

Commit 0983b31

Browse files
Yoshinori Satopmundt
authored andcommitted
sh: Wire up division and address error exceptions on SH-2A.
SH-2A has special division hardware as opposed to a full-fledged FPU, wire up the exception handlers for this. Signed-off-by: Yoshinori Sato <[email protected]> Signed-off-by: Paul Mundt <[email protected]>
1 parent 9d4436a commit 0983b31

File tree

1 file changed

+79
-9
lines changed

1 file changed

+79
-9
lines changed

arch/sh/kernel/traps.c

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@
3333
#endif
3434

3535
#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
3843
#else
3944
#define TRAP_RESERVED_INST 12
4045
#define TRAP_ILLEGAL_SLOT_INST 13
@@ -479,31 +484,52 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
479484
return ret;
480485
}
481486

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+
482495
/*
483496
* Handle various address error exceptions
484497
*/
485498
asmlinkage void do_address_error(struct pt_regs *regs,
486499
unsigned long writeaccess,
487500
unsigned long address)
488501
{
489-
unsigned long error_code;
502+
unsigned long error_code = 0;
490503
mm_segment_t oldfs;
491504
u16 instruction;
492505
int tmp;
493506

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
495511

496512
oldfs = get_fs();
497513

498514
if (user_mode(regs)) {
499515
local_irq_enable();
500516
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
501525
current->thread.trap_no = (writeaccess) ? 8 : 7;
526+
#endif
502527

503528
/* bad PC is not something we can fix */
504529
if (regs->pc & 1)
505530
goto uspace_segv;
506531

532+
#ifndef CONFIG_CPU_SH2A
507533
set_fs(USER_DS);
508534
if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
509535
/* Argh. Fault on the instruction itself.
@@ -518,6 +544,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
518544

519545
if (tmp==0)
520546
return; /* sorted */
547+
#endif
521548

522549
uspace_segv:
523550
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,
526553
if (regs->pc & 1)
527554
die("unaligned program counter", regs, error_code);
528555

556+
#ifndef CONFIG_CPU_SH2A
529557
set_fs(KERNEL_DS);
530558
if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
531559
/* Argh. Fault on the instruction itself.
@@ -537,6 +565,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
537565

538566
handle_unaligned_access(instruction, regs);
539567
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
540572
}
541573
}
542574

@@ -569,6 +601,29 @@ int is_dsp_inst(struct pt_regs *regs)
569601
#define is_dsp_inst(regs) (0)
570602
#endif /* CONFIG_SH_DSP */
571603

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+
572627
/* arch/sh/kernel/cpu/sh4/fpu.c */
573628
extern int do_fpu_inst(unsigned short, struct pt_regs *);
574629
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,
582637
struct task_struct *tsk = current;
583638

584639
#ifdef CONFIG_SH_FPU_EMU
585-
unsigned short inst;
640+
unsigned short inst = 0;
586641
int err;
587642

588643
get_user(inst, (unsigned short*)regs.pc);
@@ -604,7 +659,8 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
604659
}
605660
#endif
606661

607-
asm volatile("stc r2_bank, %0": "=r" (error_code));
662+
lookup_exception_vector(error_code);
663+
608664
local_irq_enable();
609665
tsk->thread.error_code = error_code;
610666
tsk->thread.trap_no = TRAP_RESERVED_INST;
@@ -663,7 +719,7 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
663719
unsigned long error_code;
664720
struct task_struct *tsk = current;
665721
#ifdef CONFIG_SH_FPU_EMU
666-
unsigned short inst;
722+
unsigned short inst = 0;
667723

668724
get_user(inst, (unsigned short *)regs.pc + 1);
669725
if (!do_fpu_inst(inst, &regs)) {
@@ -675,7 +731,8 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
675731
/* not a FPU inst. */
676732
#endif
677733

678-
asm volatile("stc r2_bank, %0": "=r" (error_code));
734+
lookup_exception_vector(error_code);
735+
679736
local_irq_enable();
680737
tsk->thread.error_code = error_code;
681738
tsk->thread.trap_no = TRAP_RESERVED_INST;
@@ -689,7 +746,8 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
689746
struct pt_regs regs)
690747
{
691748
long ex;
692-
asm volatile("stc r2_bank, %0" : "=r" (ex));
749+
750+
lookup_exception_vector(ex);
693751
die_if_kernel("exception", &regs, ex);
694752
}
695753

@@ -741,6 +799,10 @@ void *set_exception_table_vec(unsigned int vec, void *handler)
741799
return old_handler;
742800
}
743801

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+
744806
void __init trap_init(void)
745807
{
746808
set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
@@ -759,6 +821,14 @@ void __init trap_init(void)
759821
set_exception_table_evt(0x800, do_fpu_state_restore);
760822
set_exception_table_evt(0x820, do_fpu_state_restore);
761823
#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
762832

763833
/* Setup VBR for boot cpu */
764834
per_cpu_trap_init();

0 commit comments

Comments
 (0)