Beispiel #1
0
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;
	}
Beispiel #2
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;
			}
		}
	}
}