static int do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) { unsigned int rd = RD_BITS(instr); if ((instr & 0x01f00ff0) == 0x01000090) goto swp; if ((instr & 0x90) != 0x90 || (instr & 0x60) == 0) goto bad; ai_half += 1; 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; swp: printk(KERN_ERR "Alignment trap: not handling swp instruction\n"); bad: return TYPE_ERROR; fault: return TYPE_FAULT; }
static void fixup_store(struct disasm_state *state, struct pt_regs *regs, struct callee_regs *cregs) { /* register write back */ if ((state->aa == 1) || (state->aa == 2)) { set_reg(state->wb_reg, state->src2 + state->src3, regs, cregs); if (state->aa == 3) state->src3 = 0; } else if (state->aa == 3) { if (state->zz == 2) { set_reg(state->wb_reg, state->src2 + (state->src3 << 1), regs, cregs); } else if (!state->zz) { set_reg(state->wb_reg, state->src2 + (state->src3 << 2), regs, cregs); } else { goto fault; } } /* write fix-up */ if (!state->zz) put32_unaligned_check(state->src1, state->src2 + state->src3); else put16_unaligned_check(state->src1, state->src2 + state->src3); return; fault: state->fault = 1; }
static int do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *regs) { unsigned int rd = RD_BITS(instr); if ((instr & 0x4b003fe0) == 0x40000120) /* old value 0x40002120, can't judge swap instr correctly */ goto swp; ai_half += 1; if (LDST_L_BIT(instr)) { unsigned long val; get16_unaligned_check(val, addr); /* signed half-word? */ if (instr & 0x80) val = (signed long)((signed short) val); regs->uregs[rd] = val; } else put16_unaligned_check(regs->uregs[rd], addr); return TYPE_LDST; swp: /* only handle swap word, for swap byte should not active this alignment exception */ get32_unaligned_check(regs->uregs[RD_BITS(instr)], addr); put32_unaligned_check(regs->uregs[RM_BITS(instr)], addr); return TYPE_SWAP; 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); /* 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_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; }