提交 0983b318 编写于 作者: Y Yoshinori Sato 提交者: Paul Mundt

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: NYoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: NPaul Mundt <lethal@linux-sh.org>
上级 9d4436a6
...@@ -33,8 +33,13 @@ ...@@ -33,8 +33,13 @@
#endif #endif
#ifdef CONFIG_CPU_SH2 #ifdef CONFIG_CPU_SH2
#define TRAP_RESERVED_INST 4 # define TRAP_RESERVED_INST 4
#define TRAP_ILLEGAL_SLOT_INST 6 # define TRAP_ILLEGAL_SLOT_INST 6
# define TRAP_ADDRESS_ERROR 9
# ifdef CONFIG_CPU_SH2A
# define TRAP_DIVZERO_ERROR 17
# define TRAP_DIVOVF_ERROR 18
# endif
#else #else
#define TRAP_RESERVED_INST 12 #define TRAP_RESERVED_INST 12
#define TRAP_ILLEGAL_SLOT_INST 13 #define TRAP_ILLEGAL_SLOT_INST 13
...@@ -479,6 +484,14 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -479,6 +484,14 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
return ret; return ret;
} }
#ifdef CONFIG_CPU_HAS_SR_RB
#define lookup_exception_vector(x) \
__asm__ __volatile__ ("stc r2_bank, %0\n\t" : "=r" ((x)))
#else
#define lookup_exception_vector(x) \
__asm__ __volatile__ ("mov r4, %0\n\t" : "=r" ((x)))
#endif
/* /*
* Handle various address error exceptions * Handle various address error exceptions
*/ */
...@@ -486,24 +499,37 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -486,24 +499,37 @@ asmlinkage void do_address_error(struct pt_regs *regs,
unsigned long writeaccess, unsigned long writeaccess,
unsigned long address) unsigned long address)
{ {
unsigned long error_code; unsigned long error_code = 0;
mm_segment_t oldfs; mm_segment_t oldfs;
u16 instruction; u16 instruction;
int tmp; int tmp;
asm volatile("stc r2_bank,%0": "=r" (error_code)); /* Intentional ifdef */
#ifdef CONFIG_CPU_HAS_SR_RB
lookup_exception_vector(error_code);
#endif
oldfs = get_fs(); oldfs = get_fs();
if (user_mode(regs)) { if (user_mode(regs)) {
local_irq_enable(); local_irq_enable();
current->thread.error_code = error_code; current->thread.error_code = error_code;
#ifdef CONFIG_CPU_SH2
/*
* On the SH-2, we only have a single vector for address
* errors, there's no differentiating between a load error
* and a store error.
*/
current->thread.trap_no = 9;
#else
current->thread.trap_no = (writeaccess) ? 8 : 7; current->thread.trap_no = (writeaccess) ? 8 : 7;
#endif
/* bad PC is not something we can fix */ /* bad PC is not something we can fix */
if (regs->pc & 1) if (regs->pc & 1)
goto uspace_segv; goto uspace_segv;
#ifndef CONFIG_CPU_SH2A
set_fs(USER_DS); set_fs(USER_DS);
if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
/* Argh. Fault on the instruction itself. /* Argh. Fault on the instruction itself.
...@@ -518,6 +544,7 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -518,6 +544,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
if (tmp==0) if (tmp==0)
return; /* sorted */ return; /* sorted */
#endif
uspace_segv: uspace_segv:
printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm); 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,6 +553,7 @@ asmlinkage void do_address_error(struct pt_regs *regs,
if (regs->pc & 1) if (regs->pc & 1)
die("unaligned program counter", regs, error_code); die("unaligned program counter", regs, error_code);
#ifndef CONFIG_CPU_SH2A
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) {
/* Argh. Fault on the instruction itself. /* Argh. Fault on the instruction itself.
...@@ -537,6 +565,10 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -537,6 +565,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
handle_unaligned_access(instruction, regs); handle_unaligned_access(instruction, regs);
set_fs(oldfs); set_fs(oldfs);
#else
printk(KERN_NOTICE "Killing process \"%s\" due to unaligned access\n", current->comm);
force_sig(SIGSEGV, current);
#endif
} }
} }
...@@ -569,6 +601,29 @@ int is_dsp_inst(struct pt_regs *regs) ...@@ -569,6 +601,29 @@ int is_dsp_inst(struct pt_regs *regs)
#define is_dsp_inst(regs) (0) #define is_dsp_inst(regs) (0)
#endif /* CONFIG_SH_DSP */ #endif /* CONFIG_SH_DSP */
#ifdef CONFIG_CPU_SH2A
asmlinkage void do_divide_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
siginfo_t info;
current->thread.trap_no = r4;
current->thread.error_code = 0;
switch (r4) {
case TRAP_DIVZERO_ERROR:
info.si_code = FPE_INTDIV;
break;
case TRAP_DIVOVF_ERROR:
info.si_code = FPE_INTOVF;
break;
}
force_sig_info(SIGFPE, &info, current);
}
#endif
/* arch/sh/kernel/cpu/sh4/fpu.c */ /* arch/sh/kernel/cpu/sh4/fpu.c */
extern int do_fpu_inst(unsigned short, struct pt_regs *); extern int do_fpu_inst(unsigned short, struct pt_regs *);
extern asmlinkage void do_fpu_state_restore(unsigned long r4, unsigned long r5, 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,7 +637,7 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
struct task_struct *tsk = current; struct task_struct *tsk = current;
#ifdef CONFIG_SH_FPU_EMU #ifdef CONFIG_SH_FPU_EMU
unsigned short inst; unsigned short inst = 0;
int err; int err;
get_user(inst, (unsigned short*)regs.pc); get_user(inst, (unsigned short*)regs.pc);
...@@ -604,7 +659,8 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, ...@@ -604,7 +659,8 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
} }
#endif #endif
asm volatile("stc r2_bank, %0": "=r" (error_code)); lookup_exception_vector(error_code);
local_irq_enable(); local_irq_enable();
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_no = TRAP_RESERVED_INST; tsk->thread.trap_no = TRAP_RESERVED_INST;
...@@ -663,7 +719,7 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, ...@@ -663,7 +719,7 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
unsigned long error_code; unsigned long error_code;
struct task_struct *tsk = current; struct task_struct *tsk = current;
#ifdef CONFIG_SH_FPU_EMU #ifdef CONFIG_SH_FPU_EMU
unsigned short inst; unsigned short inst = 0;
get_user(inst, (unsigned short *)regs.pc + 1); get_user(inst, (unsigned short *)regs.pc + 1);
if (!do_fpu_inst(inst, &regs)) { if (!do_fpu_inst(inst, &regs)) {
...@@ -675,7 +731,8 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5, ...@@ -675,7 +731,8 @@ asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
/* not a FPU inst. */ /* not a FPU inst. */
#endif #endif
asm volatile("stc r2_bank, %0": "=r" (error_code)); lookup_exception_vector(error_code);
local_irq_enable(); local_irq_enable();
tsk->thread.error_code = error_code; tsk->thread.error_code = error_code;
tsk->thread.trap_no = TRAP_RESERVED_INST; tsk->thread.trap_no = TRAP_RESERVED_INST;
...@@ -689,7 +746,8 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, ...@@ -689,7 +746,8 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
struct pt_regs regs) struct pt_regs regs)
{ {
long ex; long ex;
asm volatile("stc r2_bank, %0" : "=r" (ex));
lookup_exception_vector(ex);
die_if_kernel("exception", &regs, ex); die_if_kernel("exception", &regs, ex);
} }
...@@ -741,6 +799,10 @@ void *set_exception_table_vec(unsigned int vec, void *handler) ...@@ -741,6 +799,10 @@ void *set_exception_table_vec(unsigned int vec, void *handler)
return old_handler; return old_handler;
} }
extern asmlinkage void address_error_handler(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs);
void __init trap_init(void) void __init trap_init(void)
{ {
set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst); set_exception_table_vec(TRAP_RESERVED_INST, do_reserved_inst);
...@@ -760,6 +822,14 @@ void __init trap_init(void) ...@@ -760,6 +822,14 @@ void __init trap_init(void)
set_exception_table_evt(0x820, do_fpu_state_restore); set_exception_table_evt(0x820, do_fpu_state_restore);
#endif #endif
#ifdef CONFIG_CPU_SH2
set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_handler);
#endif
#ifdef CONFIG_CPU_SH2A
set_exception_table_vec(TRAP_DIVZERO_ERROR, do_divide_error);
set_exception_table_vec(TRAP_DIVOVF_ERROR, do_divide_error);
#endif
/* Setup VBR for boot cpu */ /* Setup VBR for boot cpu */
per_cpu_trap_init(); per_cpu_trap_init();
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册