aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorDavid Hildenbrand <david@redhat.com>2019-09-05 14:13:51 +0200
committerDavid Hildenbrand <david@redhat.com>2019-09-23 09:28:29 +0200
commit2bb525e20d72386f49a3b0aacb88a65d5446baac (patch)
tree3db2b7433c3a5850ba77fe1171d705e494f3628b /target
parent087b8193edea9ba74401f9f27ad9ab79598a113a (diff)
s390x/tcg: MVST: Fix storing back the addresses to registers
24 and 31-bit address space handling is wrong when it comes to storing back the addresses to the register. While at it, read gprs 0 implicitly. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: David Hildenbrand <david@redhat.com>
Diffstat (limited to 'target')
-rw-r--r--target/s390x/helper.h2
-rw-r--r--target/s390x/insn-data.def2
-rw-r--r--target/s390x/mem_helper.c26
-rw-r--r--target/s390x/translate.c8
4 files changed, 19 insertions, 19 deletions
diff --git a/target/s390x/helper.h b/target/s390x/helper.h
index e9aff83b05..56e8149866 100644
--- a/target/s390x/helper.h
+++ b/target/s390x/helper.h
@@ -20,7 +20,7 @@ DEF_HELPER_FLAGS_4(mvn, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvo, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mvz, TCG_CALL_NO_WG, void, env, i32, i64, i64)
-DEF_HELPER_4(mvst, i64, env, i64, i64, i64)
+DEF_HELPER_3(mvst, i32, env, i32, i32)
DEF_HELPER_4(ex, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def
index f421184fcd..449eee1662 100644
--- a/target/s390x/insn-data.def
+++ b/target/s390x/insn-data.def
@@ -637,7 +637,7 @@
/* MOVE PAGE */
C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0)
/* MOVE STRING */
- C(0xb255, MVST, RRE, Z, r1_o, r2_o, 0, 0, mvst, 0)
+ C(0xb255, MVST, RRE, Z, 0, 0, 0, 0, mvst, 0)
/* MOVE WITH OPTIONAL SPECIFICATION */
C(0xc800, MVCOS, SSF, MVCOS, la1, a2, 0, 0, mvcos, 0)
/* MOVE WITH OFFSET */
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c
index ec27be174b..a24506676b 100644
--- a/target/s390x/mem_helper.c
+++ b/target/s390x/mem_helper.c
@@ -700,18 +700,18 @@ uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2)
return 0; /* data moved */
}
-/* string copy (c is string terminator) */
-uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
+/* string copy */
+uint32_t HELPER(mvst)(CPUS390XState *env, uint32_t r1, uint32_t r2)
{
+ const uint64_t d = get_address(env, r1);
+ const uint64_t s = get_address(env, r2);
+ const uint8_t c = env->regs[0];
uintptr_t ra = GETPC();
uint32_t len;
- if (c & 0xffffff00ull) {
+ if (env->regs[0] & 0xffffff00ull) {
s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, ra);
}
- c = c & 0xff;
- d = wrap_address(env, d);
- s = wrap_address(env, s);
/* Lest we fail to service interrupts in a timely manner, limit the
amount of work we're willing to do. For now, let's cap at 8k. */
@@ -719,17 +719,13 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s)
uint8_t v = cpu_ldub_data_ra(env, s + len, ra);
cpu_stb_data_ra(env, d + len, v, ra);
if (v == c) {
- /* Complete. Set CC=1 and advance R1. */
- env->cc_op = 1;
- env->retxl = s;
- return d + len;
+ set_address_zero(env, r1, d + len);
+ return 1;
}
}
-
- /* Incomplete. Set CC=3 and signal to advance R1 and R2. */
- env->cc_op = 3;
- env->retxl = s + len;
- return d + len;
+ set_address_zero(env, r1, d + len);
+ set_address_zero(env, r2, s + len);
+ return 3;
}
/* load access registers r1 to r3 from memory at a2 */
diff --git a/target/s390x/translate.c b/target/s390x/translate.c
index 2927247c82..b0a2500e5f 100644
--- a/target/s390x/translate.c
+++ b/target/s390x/translate.c
@@ -3488,9 +3488,13 @@ static DisasJumpType op_mvpg(DisasContext *s, DisasOps *o)
static DisasJumpType op_mvst(DisasContext *s, DisasOps *o)
{
- gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2);
+ TCGv_i32 t1 = tcg_const_i32(get_field(s->fields, r1));
+ TCGv_i32 t2 = tcg_const_i32(get_field(s->fields, r2));
+
+ gen_helper_mvst(cc_op, cpu_env, t1, t2);
+ tcg_temp_free_i32(t1);
+ tcg_temp_free_i32(t2);
set_cc_static(s);
- return_low128(o->in2);
return DISAS_NEXT;
}