sh: Add unaligned memory access for PC relative intructions
authorPhil Edworthy <Phil.Edworthy@renesas.com>
Wed, 24 Aug 2011 10:43:59 +0000 (10:43 +0000)
committerPaul Mundt <lethal@linux-sh.org>
Mon, 29 Aug 2011 06:32:10 +0000 (15:32 +0900)
This adds unaligned memory access support for the following instructions:
  mov.w @(disp,PC),Rn
  mov.l @(disp,PC),Rn

These instructions are often used on SH2A toolchains.

Signed-off-by: Phil Edworthy <phil.edworthy@renesas.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/kernel/traps_32.c

index 61fa4a5bc72b79b07d56df4563e3ce2817d0b425..7bbef95c9d1b4eb8daa1ffd055d57ea5e8bc6af2 100644 (file)
@@ -316,6 +316,35 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
                        break;
                }
                break;
+
+       case 9: /* mov.w @(disp,PC),Rn */
+               srcu = (unsigned char __user *)regs->pc;
+               srcu += 4;
+               srcu += (instruction & 0x00FF) << 1;
+               dst = (unsigned char *)rn;
+               *(unsigned long *)dst = 0;
+
+#if !defined(__LITTLE_ENDIAN__)
+               dst += 2;
+#endif
+
+               if (ma->from(dst, srcu, 2))
+                       goto fetch_fault;
+               sign_extend(2, dst);
+               ret = 0;
+               break;
+
+       case 0xd: /* mov.l @(disp,PC),Rn */
+               srcu = (unsigned char __user *)(regs->pc & ~0x3);
+               srcu += 4;
+               srcu += (instruction & 0x00FF) << 2;
+               dst = (unsigned char *)rn;
+               *(unsigned long *)dst = 0;
+
+               if (ma->from(dst, srcu, 4))
+                       goto fetch_fault;
+               ret = 0;
+               break;
        }
        return ret;
 
@@ -496,6 +525,9 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
                }
                break;
 
+       case 0x9000: /* mov.w @(disp,Rm),Rn */
+               goto simple;
+
        case 0xA000: /* bra label */
                ret = handle_delayslot(regs, instruction, ma);
                if (ret==0)
@@ -509,6 +541,9 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
                        regs->pc += SH_PC_12BIT_OFFSET(instruction);
                }
                break;
+
+       case 0xD000: /* mov.l @(disp,Rm),Rn */
+               goto simple;
        }
        return ret;