static tilepro_bundle_bits rewrite_load_store_unaligned( struct single_step_state *state, tilepro_bundle_bits bundle, struct pt_regs *regs, enum mem_op mem_op, int size, int sign_ext) { unsigned char __user *addr; int val_reg, addr_reg, err, val; int align_ctl; align_ctl = unaligned_fixup; switch (task_thread_info(current)->align_ctl) { case PR_UNALIGN_NOPRINT: align_ctl = 1; break; case PR_UNALIGN_SIGBUS: align_ctl = 0; break; } /* Get address and value registers */ if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { addr_reg = get_SrcA_Y2(bundle); val_reg = get_SrcBDest_Y2(bundle); } else if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { addr_reg = get_SrcA_X1(bundle); val_reg = get_Dest_X1(bundle); } else { addr_reg = get_SrcA_X1(bundle); val_reg = get_SrcB_X1(bundle); } /* * If registers are not GPRs, don't try to handle it. * * FIXME: we could handle non-GPR loads by getting the real value * from memory, writing it to the single step buffer, using a * temp_reg to hold a pointer to that memory, then executing that * instruction and resetting temp_reg. For non-GPR stores, it's a * little trickier; we could use the single step buffer for that * too, but we'd have to add some more state bits so that we could * call back in here to copy that value to the real target. For * now, we just handle the simple case. */ if ((val_reg >= PTREGS_NR_GPRS && (val_reg != TREG_ZERO || mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR)) || addr_reg >= PTREGS_NR_GPRS) return bundle; /* If it's aligned, don't handle it specially */ addr = (void __user *)regs->regs[addr_reg]; if (((unsigned long)addr % size) == 0) return bundle; /* * Return SIGBUS with the unaligned address, if requested. * Note that we return SIGBUS even for completely invalid addresses * as long as they are in fact unaligned; this matches what the * tilepro hardware would be doing, if it could provide us with the * actual bad address in an SPR, which it doesn't. */ if (align_ctl == 0) { siginfo_t info = { .si_signo = SIGBUS, .si_code = BUS_ADRALN, .si_addr = addr }; trace_unhandled_signal("unaligned trap", regs, (unsigned long)addr, SIGBUS); force_sig_info(info.si_signo, &info, current); return (tilepro_bundle_bits) 0; }
static void find_regs(tilegx_bundle_bits bundle, uint64_t *rd, uint64_t *ra, uint64_t *rb, uint64_t *clob1, uint64_t *clob2, uint64_t *clob3, bool *r_alias) { int i; uint64_t reg; uint64_t reg_map = 0, alias_reg_map = 0, map; bool alias = false; /* * Parse fault bundle, find potential used registers and mark * corresponding bits in reg_map and alias_map. These 2 bit maps * are used to find the scratch registers and determine if there * is register alias. */ if (bundle & TILEGX_BUNDLE_MODE_MASK) { /* Y Mode Bundle. */ reg = get_SrcA_Y2(bundle); reg_map |= 1ULL << reg; *ra = reg; reg = get_SrcBDest_Y2(bundle); reg_map |= 1ULL << reg; if (rd) { /* Load. */ *rd = reg; alias_reg_map = (1ULL << *rd) | (1ULL << *ra); } else { /* Store. */ *rb = reg; alias_reg_map = (1ULL << *ra) | (1ULL << *rb); } if (!is_bundle_y1_nop(bundle)) { reg = get_SrcA_Y1(bundle); reg_map |= (1ULL << reg); map = (1ULL << reg); reg = get_SrcB_Y1(bundle); reg_map |= (1ULL << reg); map |= (1ULL << reg); reg = get_Dest_Y1(bundle); reg_map |= (1ULL << reg); map |= (1ULL << reg); if (map & alias_reg_map) alias = true; } if (!is_bundle_y0_nop(bundle)) { reg = get_SrcA_Y0(bundle); reg_map |= (1ULL << reg); map = (1ULL << reg); reg = get_SrcB_Y0(bundle); reg_map |= (1ULL << reg); map |= (1ULL << reg); reg = get_Dest_Y0(bundle); reg_map |= (1ULL << reg); map |= (1ULL << reg); if (map & alias_reg_map) alias = true; } } else { /* X Mode Bundle. */ reg = get_SrcA_X1(bundle); reg_map |= (1ULL << reg); *ra = reg; if (rd) { /* Load. */ reg = get_Dest_X1(bundle); reg_map |= (1ULL << reg); *rd = reg; alias_reg_map = (1ULL << *rd) | (1ULL << *ra); } else { /* Store. */ reg = get_SrcB_X1(bundle); reg_map |= (1ULL << reg); *rb = reg; alias_reg_map = (1ULL << *ra) | (1ULL << *rb); } if (!is_bundle_x0_nop(bundle)) { reg = get_SrcA_X0(bundle); reg_map |= (1ULL << reg); map = (1ULL << reg); reg = get_SrcB_X0(bundle); reg_map |= (1ULL << reg); map |= (1ULL << reg); reg = get_Dest_X0(bundle); reg_map |= (1ULL << reg); map |= (1ULL << reg); if (map & alias_reg_map) alias = true; } } /* * "alias" indicates if the unalign access registers have collision * with others in the same bundle. We jsut simply test all register * operands case (RRR), ignored the case with immidate. If a bundle * has no register alias, we may do fixup in a simple or fast manner. * So if an immidata field happens to hit with a register, we may end * up fall back to the generic handling. */ *r_alias = alias; /* Flip bits on reg_map. */ reg_map ^= -1ULL; /* Scan reg_map lower 54(TREG_SP) bits to find 3 set bits. */ for (i = 0; i < TREG_SP; i++) { if (reg_map & (0x1ULL << i)) { if (*clob1 == -1) { *clob1 = i; } else if (*clob2 == -1) { *clob2 = i; } else if (*clob3 == -1) { *clob3 = i; return; } } } }