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

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
...@@ -415,9 +415,9 @@ static int do_fp_load(int rn, unsigned long ea, int nb, struct pt_regs *regs) ...@@ -415,9 +415,9 @@ static int do_fp_load(int rn, unsigned long ea, int nb, struct pt_regs *regs)
int err; int err;
union { union {
float f; float f;
double d; double d[2];
unsigned long l; unsigned long l[2];
u8 b[sizeof(double)]; u8 b[2 * sizeof(double)];
} u; } u;
if (!address_ok(regs, ea, nb)) 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) ...@@ -427,11 +427,19 @@ static int do_fp_load(int rn, unsigned long ea, int nb, struct pt_regs *regs)
return err; return err;
preempt_disable(); preempt_disable();
if (nb == 4) 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) if (regs->msr & MSR_FP)
put_fpr(rn, &u.d); put_fpr(rn, &u.d[0]);
else 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(); preempt_enable();
return 0; return 0;
} }
...@@ -441,20 +449,27 @@ static int do_fp_store(int rn, unsigned long ea, int nb, struct pt_regs *regs) ...@@ -441,20 +449,27 @@ static int do_fp_store(int rn, unsigned long ea, int nb, struct pt_regs *regs)
{ {
union { union {
float f; float f;
double d; double d[2];
unsigned long l; unsigned long l[2];
u8 b[sizeof(double)]; u8 b[2 * sizeof(double)];
} u; } u;
if (!address_ok(regs, ea, nb)) if (!address_ok(regs, ea, nb))
return -EFAULT; return -EFAULT;
preempt_disable(); preempt_disable();
if (regs->msr & MSR_FP) if (regs->msr & MSR_FP)
get_fpr(rn, &u.d); get_fpr(rn, &u.d[0]);
else else
u.l = current->thread.TS_FPR(rn); u.l[0] = current->thread.TS_FPR(rn);
if (nb == 4) 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(); preempt_enable();
return copy_mem_out(u.b, ea, nb); return copy_mem_out(u.b, ea, nb);
} }
...@@ -1938,7 +1953,17 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, ...@@ -1938,7 +1953,17 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
case 759: /* stfdux */ case 759: /* stfdux */
op->type = MKOP(STORE_FP, u, 8); op->type = MKOP(STORE_FP, u, 8);
break; 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__ #ifdef __powerpc64__
case 660: /* stdbrx */ case 660: /* stdbrx */
...@@ -1956,7 +1981,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, ...@@ -1956,7 +1981,7 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
op->val = byterev_4(regs->gpr[rd]); op->val = byterev_4(regs->gpr[rd]);
break; break;
case 725: case 725: /* stswi */
if (rb == 0) if (rb == 0)
rb = 32; /* # bytes to store */ rb = 32; /* # bytes to store */
op->type = MKOP(STORE_MULTI, 0, rb); op->type = MKOP(STORE_MULTI, 0, rb);
...@@ -2246,9 +2271,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, ...@@ -2246,9 +2271,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#endif #endif
#ifdef CONFIG_VSX #ifdef CONFIG_VSX
case 57: /* lxsd, lxssp */ case 57: /* lfdp, lxsd, lxssp */
op->ea = dsform_ea(instr, regs); op->ea = dsform_ea(instr, regs);
switch (instr & 3) { 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 */ case 2: /* lxsd */
op->reg = rd + 32; op->reg = rd + 32;
op->type = MKOP(LOAD_VSX, 0, 8); op->type = MKOP(LOAD_VSX, 0, 8);
...@@ -2283,8 +2313,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, ...@@ -2283,8 +2313,14 @@ int analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
#endif #endif
#ifdef CONFIG_VSX #ifdef CONFIG_VSX
case 61: /* lxv, stxsd, stxssp, stxv */ case 61: /* stfdp, lxv, stxsd, stxssp, stxv */
switch (instr & 7) { 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 */ case 1: /* lxv */
op->ea = dqform_ea(instr, regs); op->ea = dqform_ea(instr, regs);
if (instr & 8) if (instr & 8)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment