* (if that instruction is in a branch delay slot)
* - 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;
unsigned long *rm, *rn;
* emulate the instruction in the delay slot
* - 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 */
if (user_mode(regs))
return -EFAULT;
regs, 0);
}
- return handle_unaligned_ins(instruction,regs);
+ return handle_unaligned_ins(instruction, regs);
}
/*
* XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit
* opcodes..
*/
-#ifndef CONFIG_CPU_SH2A
+
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;
int ret, index;
printk(KERN_NOTICE "Fixing up unaligned userspace access "
"in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
current->comm, task_pid_nr(current),
- (u16 *)regs->pc, instruction);
+ (void *)regs->pc, instruction);
}
ret = -EFAULT;
case 0x0000:
if (instruction==0x000B) {
/* rts */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0)
regs->pc = regs->pr;
}
else if ((instruction&0x00FF)==0x0023) {
/* braf @Rm */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0)
regs->pc += rm + 4;
}
else if ((instruction&0x00FF)==0x0003) {
/* bsrf @Rm */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) {
regs->pr = regs->pc + 4;
regs->pc += rm + 4;
case 0x4000:
if ((instruction&0x00FF)==0x002B) {
/* jmp @Rm */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0)
regs->pc = rm;
}
else if ((instruction&0x00FF)==0x000B) {
/* jsr @Rm */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) {
regs->pr = regs->pc + 4;
regs->pc = rm;
case 0x0B00: /* bf lab - no delayslot*/
break;
case 0x0F00: /* bf/s lab */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) {
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
if ((regs->sr & 0x00000001) != 0)
case 0x0900: /* bt lab - no delayslot */
break;
case 0x0D00: /* bt/s lab */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) {
#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
if ((regs->sr & 0x00000001) == 0)
break;
case 0xA000: /* bra label */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0)
regs->pc += SH_PC_12BIT_OFFSET(instruction);
break;
case 0xB000: /* bsr label */
- ret = handle_unaligned_delayslot(regs);
+ ret = handle_unaligned_delayslot(regs, instruction);
if (ret==0) {
regs->pr = regs->pc + 4;
regs->pc += SH_PC_12BIT_OFFSET(instruction);
/* handle non-delay-slot instruction */
simple:
- ret = handle_unaligned_ins(instruction,regs);
+ ret = handle_unaligned_ins(instruction, regs);
if (ret==0)
regs->pc += instruction_size(instruction);
return ret;
}
-#endif /* CONFIG_CPU_SH2A */
#ifdef CONFIG_CPU_HAS_SR_RB
#define lookup_exception_vector(x) \
unsigned long error_code = 0;
mm_segment_t oldfs;
siginfo_t info;
-#ifndef CONFIG_CPU_SH2A
- u16 instruction;
+ opcode_t instruction;
int tmp;
-#endif
/* Intentional ifdef */
#ifdef CONFIG_CPU_HAS_SR_RB
goto uspace_segv;
}
-#ifndef CONFIG_CPU_SH2A
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.
This should never happen non-SMP
*/
if (tmp==0)
return; /* sorted */
-#endif
-
uspace_segv:
printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
"access (PC %lx PR %lx)\n", current->comm, regs->pc,
if (regs->pc & 1)
die("unaligned program counter", regs, error_code);
-#ifndef CONFIG_CPU_SH2A
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.
This should never happen non-SMP
*/
handle_unaligned_access(instruction, regs);
set_fs(oldfs);
-#else
- printk(KERN_NOTICE "Killing process \"%s\" due to unaligned "
- "access\n", current->comm);
-
- force_sig(SIGSEGV, current);
-#endif
}
}