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; if ((instr & 0xfe000000) == 0xe8000000) { /* ARMv7 Thumb-2 32-bit LDRD/STRD */ rd2 = (instr >> 8) & 0xf; load = !!(LDST_L_BIT(instr)); } else if (((rd & 1) == 1) || (rd == 14))
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; unsigned int __ua_flags = uaccess_save_and_enable(); get16t_unaligned_check(val, addr); uaccess_restore(__ua_flags); /* signed half-word? */ if (instr & 0x40) val = (signed long)((signed short) val); regs->uregs[rd] = val; } else { unsigned int __ua_flags = uaccess_save_and_enable(); put16t_unaligned_check(regs->uregs[rd], addr); uaccess_restore(__ua_flags); } 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); if (((rd & 1) == 1) || (rd == 14)) goto bad; ai_dword += 1; if (user_mode(regs)) goto user; if ((instr & 0xf0) == 0xd0) { unsigned long val; get32_unaligned_check(val, addr); regs->uregs[rd] = val; get32_unaligned_check(val, addr + 4); regs->uregs[rd + 1] = val; } else { put32_unaligned_check(regs->uregs[rd], addr); put32_unaligned_check(regs->uregs[rd + 1], addr + 4); } return TYPE_LDST; user: if ((instr & 0xf0) == 0xd0) { unsigned long val; get32t_unaligned_check(val, addr); regs->uregs[rd] = val; get32t_unaligned_check(val, addr + 4); regs->uregs[rd + 1] = val; } else { put32t_unaligned_check(regs->uregs[rd], addr); put32t_unaligned_check(regs->uregs[rd + 1], addr + 4); } return TYPE_LDST; bad: return TYPE_ERROR; fault: return TYPE_FAULT; }
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); 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); 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_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; }