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_ldrstr(unsigned long addr, unsigned long instr, struct pt_regs *regs) { unsigned int rd = RD_BITS(instr); ai_word += 1; if ((!LDST_P_BIT(instr) && LDST_W_BIT(instr)) || user_mode(regs)) goto trans; if (LDST_L_BIT(instr)) { unsigned int val; get32_unaligned_check(val, addr); regs->uregs[rd] = val; } else put32_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; trans: if (LDST_L_BIT(instr)) { unsigned int val; get32t_unaligned_check(val, addr); regs->uregs[rd] = val; } else put32t_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; fault: return TYPE_FAULT; }
static int do_alignment_exception(struct pt_regs *regs) { unsigned int instr, rd, rn, correction, nr_regs, regbits; unsigned long eaddr; union { unsigned long un; signed long sn; } offset; if (user_mode(regs)) { set_cr(cr_no_alignment); ai_user += 1; return 0; } ai_sys += 1; instr = *(unsigned long *)instruction_pointer(regs); correction = 4; /* sometimes 8 on ARMv3 */ regs->ARM_pc += correction + 4; rd = RD_BITS(instr); rn = RN_BITS(instr); eaddr = regs->uregs[rn]; switch(CODING_BITS(instr)) { case 0x00000000: if ((instr & 0x0ff00ff0) == 0x01000090) { ai_skipped += 1; printk(KERN_ERR "Unaligned trap: not handling swp instruction\n"); return 1; } if (((instr & 0x0e000090) == 0x00000090) && (instr & 0x60) != 0) { ai_half += 1; if (LDSTH_I_BIT(instr)) offset.un = (instr & 0xf00) >> 4 | (instr & 15); else offset.un = regs->uregs[RM_BITS(instr)]; if (LDST_P_BIT(instr)) { if (LDST_U_BIT(instr)) eaddr += offset.un; else eaddr -= offset.un; } if (LDST_L_BIT(instr)) regs->uregs[rd] = get_unaligned((unsigned short *)eaddr); else put_unaligned(regs->uregs[rd], (unsigned short *)eaddr); /* signed half-word? */ if (instr & 0x40) regs->uregs[rd] = (long)((short) regs->uregs[rd]); if (!LDST_P_BIT(instr)) { if (LDST_U_BIT(instr)) eaddr += offset.un; else eaddr -= offset.un; regs->uregs[rn] = eaddr; } else if (LDST_W_BIT(instr)) regs->uregs[rn] = eaddr; break; }