Commit 4b5a9ef5 authored by Magnus Damm's avatar Magnus Damm Committed by Paul Mundt

sh: use opcode_t and enable unaligned code for sh2a

This patch converts the unaligned access handling code to use opcode_t
instead of u16. While at it, enable unaligned access handling for sh2a.
Signed-off-by: default avatarMagnus Damm <damm@igel.co.jp>
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 4252c659
...@@ -179,7 +179,7 @@ static inline void sign_extend(unsigned int count, unsigned char *dst) ...@@ -179,7 +179,7 @@ static inline void sign_extend(unsigned int count, unsigned char *dst)
* (if that instruction is in a branch delay slot) * (if that instruction is in a branch delay slot)
* - return 0 if emulation okay, -EFAULT on existential error * - return 0 if emulation okay, -EFAULT on existential error
*/ */
static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
{ {
int ret, index, count; int ret, index, count;
unsigned long *rm, *rn; unsigned long *rm, *rn;
...@@ -320,11 +320,13 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) ...@@ -320,11 +320,13 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs)
* emulate the instruction in the delay slot * emulate the instruction in the delay slot
* - fetches the instruction from PC+2 * - fetches the instruction from PC+2
*/ */
static inline int handle_unaligned_delayslot(struct pt_regs *regs) static inline int handle_unaligned_delayslot(struct pt_regs *regs,
opcode_t old_instruction)
{ {
u16 instruction; opcode_t instruction;
void *addr = (void *)(regs->pc + instruction_size(old_instruction));
if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) { if (copy_from_user(&instruction, addr, sizeof(instruction))) {
/* the instruction-fetch faulted */ /* the instruction-fetch faulted */
if (user_mode(regs)) if (user_mode(regs))
return -EFAULT; return -EFAULT;
...@@ -334,7 +336,7 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) ...@@ -334,7 +336,7 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
regs, 0); regs, 0);
} }
return handle_unaligned_ins(instruction,regs); return handle_unaligned_ins(instruction, regs);
} }
/* /*
...@@ -357,10 +359,10 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) ...@@ -357,10 +359,10 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs)
* XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
* opcodes.. * opcodes..
*/ */
#ifndef CONFIG_CPU_SH2A
static int handle_unaligned_notify_count = 10; static int handle_unaligned_notify_count = 10;
static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
{ {
u_int rm; u_int rm;
int ret, index; int ret, index;
...@@ -375,7 +377,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -375,7 +377,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
printk(KERN_NOTICE "Fixing up unaligned userspace access " printk(KERN_NOTICE "Fixing up unaligned userspace access "
"in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
current->comm, task_pid_nr(current), current->comm, task_pid_nr(current),
(u16 *)regs->pc, instruction); (void *)regs->pc, instruction);
} }
ret = -EFAULT; ret = -EFAULT;
...@@ -383,19 +385,19 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -383,19 +385,19 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
case 0x0000: case 0x0000:
if (instruction==0x000B) { if (instruction==0x000B) {
/* rts */ /* rts */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) if (ret==0)
regs->pc = regs->pr; regs->pc = regs->pr;
} }
else if ((instruction&0x00FF)==0x0023) { else if ((instruction&0x00FF)==0x0023) {
/* braf @Rm */ /* braf @Rm */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) if (ret==0)
regs->pc += rm + 4; regs->pc += rm + 4;
} }
else if ((instruction&0x00FF)==0x0003) { else if ((instruction&0x00FF)==0x0003) {
/* bsrf @Rm */ /* bsrf @Rm */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) { if (ret==0) {
regs->pr = regs->pc + 4; regs->pr = regs->pc + 4;
regs->pc += rm + 4; regs->pc += rm + 4;
...@@ -416,13 +418,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -416,13 +418,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
case 0x4000: case 0x4000:
if ((instruction&0x00FF)==0x002B) { if ((instruction&0x00FF)==0x002B) {
/* jmp @Rm */ /* jmp @Rm */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) if (ret==0)
regs->pc = rm; regs->pc = rm;
} }
else if ((instruction&0x00FF)==0x000B) { else if ((instruction&0x00FF)==0x000B) {
/* jsr @Rm */ /* jsr @Rm */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) { if (ret==0) {
regs->pr = regs->pc + 4; regs->pr = regs->pc + 4;
regs->pc = rm; regs->pc = rm;
...@@ -449,7 +451,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -449,7 +451,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
case 0x0B00: /* bf lab - no delayslot*/ case 0x0B00: /* bf lab - no delayslot*/
break; break;
case 0x0F00: /* bf/s lab */ case 0x0F00: /* bf/s lab */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) { if (ret==0) {
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
if ((regs->sr & 0x00000001) != 0) if ((regs->sr & 0x00000001) != 0)
...@@ -462,7 +464,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -462,7 +464,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
case 0x0900: /* bt lab - no delayslot */ case 0x0900: /* bt lab - no delayslot */
break; break;
case 0x0D00: /* bt/s lab */ case 0x0D00: /* bt/s lab */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) { if (ret==0) {
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
if ((regs->sr & 0x00000001) == 0) if ((regs->sr & 0x00000001) == 0)
...@@ -476,13 +478,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -476,13 +478,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
break; break;
case 0xA000: /* bra label */ case 0xA000: /* bra label */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) if (ret==0)
regs->pc += SH_PC_12BIT_OFFSET(instruction); regs->pc += SH_PC_12BIT_OFFSET(instruction);
break; break;
case 0xB000: /* bsr label */ case 0xB000: /* bsr label */
ret = handle_unaligned_delayslot(regs); ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) { if (ret==0) {
regs->pr = regs->pc + 4; regs->pr = regs->pc + 4;
regs->pc += SH_PC_12BIT_OFFSET(instruction); regs->pc += SH_PC_12BIT_OFFSET(instruction);
...@@ -493,12 +495,11 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) ...@@ -493,12 +495,11 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs)
/* handle non-delay-slot instruction */ /* handle non-delay-slot instruction */
simple: simple:
ret = handle_unaligned_ins(instruction,regs); ret = handle_unaligned_ins(instruction, regs);
if (ret==0) if (ret==0)
regs->pc += instruction_size(instruction); regs->pc += instruction_size(instruction);
return ret; return ret;
} }
#endif /* CONFIG_CPU_SH2A */
#ifdef CONFIG_CPU_HAS_SR_RB #ifdef CONFIG_CPU_HAS_SR_RB
#define lookup_exception_vector(x) \ #define lookup_exception_vector(x) \
...@@ -526,10 +527,8 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -526,10 +527,8 @@ asmlinkage void do_address_error(struct pt_regs *regs,
unsigned long error_code = 0; unsigned long error_code = 0;
mm_segment_t oldfs; mm_segment_t oldfs;
siginfo_t info; siginfo_t info;
#ifndef CONFIG_CPU_SH2A opcode_t instruction;
u16 instruction;
int tmp; int tmp;
#endif
/* Intentional ifdef */ /* Intentional ifdef */
#ifdef CONFIG_CPU_HAS_SR_RB #ifdef CONFIG_CPU_HAS_SR_RB
...@@ -549,9 +548,9 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -549,9 +548,9 @@ asmlinkage void do_address_error(struct pt_regs *regs,
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, (void *)(regs->pc),
sizeof(instruction))) {
/* Argh. Fault on the instruction itself. /* Argh. Fault on the instruction itself.
This should never happen non-SMP This should never happen non-SMP
*/ */
...@@ -564,8 +563,6 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -564,8 +563,6 @@ 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 "Sending SIGBUS to \"%s\" due to unaligned " printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
"access (PC %lx PR %lx)\n", current->comm, regs->pc, "access (PC %lx PR %lx)\n", current->comm, regs->pc,
...@@ -580,9 +577,9 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -580,9 +577,9 @@ 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, (void *)(regs->pc),
sizeof(instruction))) {
/* Argh. Fault on the instruction itself. /* Argh. Fault on the instruction itself.
This should never happen non-SMP This should never happen non-SMP
*/ */
...@@ -592,12 +589,6 @@ asmlinkage void do_address_error(struct pt_regs *regs, ...@@ -592,12 +589,6 @@ 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
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment