Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1f41fb79 authored by Paul Mackerras's avatar Paul Mackerras Committed by Michael Ellerman
Browse files

powerpc: Emulate load/store floating double pair instructions



This adds lfdp[x] and stfdp[x] to the set of instructions that
analyse_instr() and emulate_step() understand.

Signed-off-by: default avatarPaul Mackerras <paulus@ozlabs.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent e61ccc7b
Loading
Loading
Loading
Loading
+52 −16
Original line number Diff line number Diff line
@@ -415,9 +415,9 @@ static int do_fp_load(int rn, unsigned long ea, int nb, struct pt_regs *regs)
	int err;
	union {
		float f;
		double d;
		unsigned long l;
		u8 b[sizeof(double)];
		double d[2];
		unsigned long l[2];
		u8 b[2 * sizeof(double)];
	} u;

	if (!address_ok(regs, ea, nb))
@@ -427,11 +427,19 @@ static int do_fp_load(int rn, unsigned long ea, int nb, struct pt_regs *regs)
		return err;
	preempt_disable();
	if (nb == 4)
		conv_sp_to_dp(&u.f, &u.d);
		conv_sp_to_dp(&u.f, &u.d[0]);
	if (regs->msr & MSR_FP)
		put_fpr(rn, &u.d);
		put_fpr(rn, &u.d[0]);
	else
		current->thread.TS_FPR(rn) = u.l;
		current->thread.TS_FPR(rn) = u.l[0];
	if (nb == 16) {
		/* lfdp */
		rn |= 1;
		if (regs->msr & MSR_FP)
			put_fpr(rn, &u.d[1]);
		else
			current->thread.TS_FPR(rn) = u.l[1];
	}
	preempt_enable();
	return 0;
}
@@ -441,20 +449,27 @@ static int do_fp_store(int rn, unsigned long ea, int nb, struct pt_regs *regs)
{
	union {
		float f;
		double d;
		unsigned long l;
		u8 b[sizeof(double)];
		double d[2];
		unsigned long l[2];
		u8 b[2 * sizeof(double)];
	} u;

	if (!address_ok(regs, ea, nb))
		return -EFAULT;
	preempt_disable();
	if (regs->msr & MSR_FP)
		get_fpr(rn, &u.d);
		get_fpr(rn, &u.d[0]);
	else
		u.l = current->thread.TS_FPR(rn);
		u.l[0] = current->thread.TS_FPR(rn);
	if (nb == 4)
		conv_dp_to_sp(&u.d, &u.f);
		conv_dp_to_sp(&u.d[0], &u.f);
	if (nb == 16) {
		rn |= 1;
		if (regs->msr & MSR_FP)
			get_fpr(rn, &u.d[1]);
		else
			u.l[1] = current->thread.TS_FPR(rn);
	}
	preempt_enable();
	return copy_mem_out(u.b, ea, nb);
}
@@ -1938,7 +1953,17 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
		case 759:	/* stfdux */
			op->type = MKOP(STORE_FP, u, 8);
			break;
#endif

#ifdef __powerpc64__
		case 791:	/* lfdpx */
			op->type = MKOP(LOAD_FP, 0, 16);
			break;

		case 919:	/* stfdpx */
			op->type = MKOP(STORE_FP, 0, 16);
			break;
#endif /* __powerpc64 */
#endif /* CONFIG_PPC_FPU */

#ifdef __powerpc64__
		case 660:	/* stdbrx */
@@ -1956,7 +1981,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
			op->val = byterev_4(regs->gpr[rd]);
			break;

		case 725:
		case 725:	/* stswi */
			if (rb == 0)
				rb = 32;	/* # bytes to store */
			op->type = MKOP(STORE_MULTI, 0, rb);
@@ -2246,9 +2271,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#endif

#ifdef CONFIG_VSX
	case 57:	/* lxsd, lxssp */
	case 57:	/* lfdp, lxsd, lxssp */
		op->ea = dsform_ea(instr, regs);
		switch (instr & 3) {
		case 0:		/* lfdp */
			if (rd & 1)
				break;		/* reg must be even */
			op->type = MKOP(LOAD_FP, 0, 16);
			break;
		case 2:		/* lxsd */
			op->reg = rd + 32;
			op->type = MKOP(LOAD_VSX, 0, 8);
@@ -2283,8 +2313,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#endif

#ifdef CONFIG_VSX
	case 61:	/* lxv, stxsd, stxssp, stxv */
	case 61:	/* stfdp, lxv, stxsd, stxssp, stxv */
		switch (instr & 7) {
		case 0:		/* stfdp with LSB of DS field = 0 */
		case 4:		/* stfdp with LSB of DS field = 1 */
			op->ea = dsform_ea(instr, regs);
			op->type = MKOP(STORE_FP, 0, 16);
			break;

		case 1:		/* lxv */
			op->ea = dqform_ea(instr, regs);
			if (instr & 8)