|
@@ -257,3 +257,130 @@ union offset_union {
|
|
|
"2: "ins" %1, [%2]\n" \
|
|
|
"3:\n" \
|
|
|
" .pushsection .fixup,\"ax\"\n" \
|
|
|
+ " .align 2\n" \
|
|
|
+ "4: mov %0, #1\n" \
|
|
|
+ " b 3b\n" \
|
|
|
+ " .popsection\n" \
|
|
|
+ " .pushsection __ex_table,\"a\"\n" \
|
|
|
+ " .align 3\n" \
|
|
|
+ " .long 1b, 4b\n" \
|
|
|
+ " .long 2b, 4b\n" \
|
|
|
+ " .popsection\n" \
|
|
|
+ : "=r" (err), "=&r" (v), "=&r" (a) \
|
|
|
+ : "0" (err), "1" (v), "2" (a)); \
|
|
|
+ if (err) \
|
|
|
+ goto fault; \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
+#define put16_unaligned_check(val,addr) \
|
|
|
+ __put16_unaligned_check("strb",val,addr)
|
|
|
+
|
|
|
+#define put16t_unaligned_check(val,addr) \
|
|
|
+ __put16_unaligned_check("strbt",val,addr)
|
|
|
+
|
|
|
+#define __put32_unaligned_check(ins,val,addr) \
|
|
|
+ do { \
|
|
|
+ unsigned int err = 0, v = val, a = addr; \
|
|
|
+ __asm__( FIRST_BYTE_32 \
|
|
|
+ ARM( "1: "ins" %1, [%2], #1\n" ) \
|
|
|
+ THUMB( "1: "ins" %1, [%2]\n" ) \
|
|
|
+ THUMB( " add %2, %2, #1\n" ) \
|
|
|
+ " mov %1, %1, "NEXT_BYTE"\n" \
|
|
|
+ ARM( "2: "ins" %1, [%2], #1\n" ) \
|
|
|
+ THUMB( "2: "ins" %1, [%2]\n" ) \
|
|
|
+ THUMB( " add %2, %2, #1\n" ) \
|
|
|
+ " mov %1, %1, "NEXT_BYTE"\n" \
|
|
|
+ ARM( "3: "ins" %1, [%2], #1\n" ) \
|
|
|
+ THUMB( "3: "ins" %1, [%2]\n" ) \
|
|
|
+ THUMB( " add %2, %2, #1\n" ) \
|
|
|
+ " mov %1, %1, "NEXT_BYTE"\n" \
|
|
|
+ "4: "ins" %1, [%2]\n" \
|
|
|
+ "5:\n" \
|
|
|
+ " .pushsection .fixup,\"ax\"\n" \
|
|
|
+ " .align 2\n" \
|
|
|
+ "6: mov %0, #1\n" \
|
|
|
+ " b 5b\n" \
|
|
|
+ " .popsection\n" \
|
|
|
+ " .pushsection __ex_table,\"a\"\n" \
|
|
|
+ " .align 3\n" \
|
|
|
+ " .long 1b, 6b\n" \
|
|
|
+ " .long 2b, 6b\n" \
|
|
|
+ " .long 3b, 6b\n" \
|
|
|
+ " .long 4b, 6b\n" \
|
|
|
+ " .popsection\n" \
|
|
|
+ : "=r" (err), "=&r" (v), "=&r" (a) \
|
|
|
+ : "0" (err), "1" (v), "2" (a)); \
|
|
|
+ if (err) \
|
|
|
+ goto fault; \
|
|
|
+ } while (0)
|
|
|
+
|
|
|
+#define put32_unaligned_check(val,addr) \
|
|
|
+ __put32_unaligned_check("strb", val, addr)
|
|
|
+
|
|
|
+#define put32t_unaligned_check(val,addr) \
|
|
|
+ __put32_unaligned_check("strbt", val, addr)
|
|
|
+
|
|
|
+static void
|
|
|
+do_alignment_finish_ldst(unsigned long addr, unsigned long instr, struct pt_regs *regs, union offset_union offset)
|
|
|
+{
|
|
|
+ if (!LDST_U_BIT(instr))
|
|
|
+ offset.un = -offset.un;
|
|
|
+
|
|
|
+ if (!LDST_P_BIT(instr))
|
|
|
+ addr += offset.un;
|
|
|
+
|
|
|
+ if (!LDST_P_BIT(instr) || LDST_W_BIT(instr))
|
|
|
+ regs->uregs[RN_BITS(instr)] = addr;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs)
|
|
|
+{
|
|
|
+ unsigned int rd = RD_BITS(instr);
|
|
|
+
|
|
|
+ ai_half += 1;
|
|
|
+
|
|
|
+ if (user_mode(regs))
|
|
|
+ goto user;
|
|
|
+
|
|
|
+ if (LDST_L_BIT(instr)) {
|
|
|
+ unsigned long val;
|
|
|
+ get16_unaligned_check(val, addr);
|
|
|
+
|
|
|
+ /* signed half-word? */
|
|
|
+ if (instr & 0x40)
|
|
|
+ val = (signed long)((signed short) val);
|
|
|
+
|
|
|
+ regs->uregs[rd] = val;
|
|
|
+ } else
|
|
|
+ put16_unaligned_check(regs->uregs[rd], addr);
|
|
|
+
|
|
|
+ return TYPE_LDST;
|
|
|
+
|
|
|
+ user:
|
|
|
+ if (LDST_L_BIT(instr)) {
|
|
|
+ unsigned long val;
|
|
|
+ get16t_unaligned_check(val, addr);
|
|
|
+
|
|
|
+ /* signed half-word? */
|
|
|
+ if (instr & 0x40)
|
|
|
+ val = (signed long)((signed short) val);
|
|
|
+
|
|
|
+ regs->uregs[rd] = val;
|
|
|
+ } else
|
|
|
+ put16t_unaligned_check(regs->uregs[rd], addr);
|
|
|
+
|
|
|
+ return TYPE_LDST;
|
|
|
+
|
|
|
+ fault:
|
|
|
+ return TYPE_FAULT;
|
|
|
+}
|
|
|
+
|
|
|
+static int
|
|
|
+do_alignment_ldrdstrd(unsigned long addr, unsigned long instr,
|
|
|
+ struct pt_regs *regs)
|
|
|
+{
|
|
|
+ unsigned int rd = RD_BITS(instr);
|
|
|
+ unsigned int rd2;
|
|
|
+ int load;
|
|
|
+
|