From ee0d0be16819896cc6c8018cbe171a632b61489c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 17 May 2015 01:28:03 +0200 Subject: [PATCH 01/34] target-s390x: fix CC computation for EX instruction Commit 7a6c7067f optimized CC computation by only saving cc_op before calling helpers as they either don't touch the CC or generate a new static value. This however doesn't work for the EX instruction as the helper changes or not the CC value depending on the actual executed instruction (e.g. MVC vs CLC). This patches force a CC computation before calling the helper. This fixes random memory corruption occuring in guests. Signed-off-by: Aurelien Jarno [agraf: remove set_cc_static in op_ex as suggested by rth] Signed-off-by: Alexander Graf --- target-s390x/translate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fbffd3066d..497733dbcc 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2101,13 +2101,12 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) TCGv_i64 tmp; update_psw_addr(s); - update_cc_op(s); + gen_op_calc_cc(s); tmp = tcg_const_i64(s->next_pc); gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); tcg_temp_free_i64(tmp); - set_cc_static(s); return NO_EXIT; } From 2aaa1940684a3bf2b381fd2a8ff26c287a05109d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 15:39:58 +0200 Subject: [PATCH 02/34] target-s390x: fix CC computation for LOAD POSITIVE instructions LOAD POSITIVE instructions (LPR, LPGR and LPGFR) set the following condition code: 0: Result zero; no overflow 1: -- 2: Result greater than zero; no overflow 3: Overflow The current code wrongly returns 1 instead of 2 in case of a result greater than 0. This patches fixes that. This fixes the marshalling of the value '0L' in Python. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/cc_helper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c index 00bc883a8a..bfce3f1e60 100644 --- a/target-s390x/cc_helper.c +++ b/target-s390x/cc_helper.c @@ -195,7 +195,7 @@ static uint32_t cc_calc_abs_64(int64_t dst) if ((uint64_t)dst == 0x8000000000000000ULL) { return 3; } else if (dst) { - return 1; + return 2; } else { return 0; } @@ -296,7 +296,7 @@ static uint32_t cc_calc_abs_32(int32_t dst) if ((uint32_t)dst == 0x80000000UL) { return 3; } else if (dst) { - return 1; + return 2; } else { return 0; } From d30107814c8d02f1896bd57249aef1b5aaed38c9 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 15:39:59 +0200 Subject: [PATCH 03/34] target-s390x: optimize (negative-) abs computation Now that movcond exists, it's easy to write (negative-) absolute value using TCG code instead of an helper. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/helper.h | 2 -- target-s390x/int_helper.c | 22 ---------------------- target-s390x/translate.c | 16 ++++++++++++++-- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 8d2c8596bb..c4ec3f1001 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -17,8 +17,6 @@ DEF_HELPER_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) -DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64) -DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64) 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) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index cb8dd98542..f53723dea2 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -135,28 +135,6 @@ int32_t HELPER(nabs_i32)(int32_t val) } } -/* absolute value 64-bit */ -uint64_t HELPER(abs_i64)(int64_t val) -{ - HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); - - if (val < 0) { - return -val; - } else { - return val; - } -} - -/* negative absolute value 64-bit */ -int64_t HELPER(nabs_i64)(int64_t val) -{ - if (val < 0) { - return val; - } else { - return -val; - } -} - /* count leading zeros, for find leftmost one */ uint64_t HELPER(clz)(uint64_t v) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 497733dbcc..0c6d1f6a37 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1310,7 +1310,13 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, static ExitStatus op_abs(DisasContext *s, DisasOps *o) { - gen_helper_abs_i64(o->out, o->in2); + TCGv_i64 z, n; + z = tcg_const_i64(0); + n = tcg_temp_new_i64(); + tcg_gen_neg_i64(n, o->in2); + tcg_gen_movcond_i64(TCG_COND_LT, o->out, o->in2, z, n, o->in2); + tcg_temp_free_i64(n); + tcg_temp_free_i64(z); return NO_EXIT; } @@ -2680,7 +2686,13 @@ static ExitStatus op_msdb(DisasContext *s, DisasOps *o) static ExitStatus op_nabs(DisasContext *s, DisasOps *o) { - gen_helper_nabs_i64(o->out, o->in2); + TCGv_i64 z, n; + z = tcg_const_i64(0); + n = tcg_temp_new_i64(); + tcg_gen_neg_i64(n, o->in2); + tcg_gen_movcond_i64(TCG_COND_GE, o->out, o->in2, z, n, o->in2); + tcg_temp_free_i64(n); + tcg_temp_free_i64(z); return NO_EXIT; } From a91a1b20a23424412a3e7bb184422ec30ae64453 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 15:40:00 +0200 Subject: [PATCH 04/34] target-s390x: remove unused helpers Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/helper.h | 2 -- target-s390x/int_helper.c | 20 -------------------- 2 files changed, 22 deletions(-) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index c4ec3f1001..e6f2afb44f 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -15,8 +15,6 @@ DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_4(mvpg, void, env, i64, i64, i64) DEF_HELPER_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) -DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32) -DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32) 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) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c index f53723dea2..2c2b3f622c 100644 --- a/target-s390x/int_helper.c +++ b/target-s390x/int_helper.c @@ -115,26 +115,6 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, return ret; } -/* absolute value 32-bit */ -uint32_t HELPER(abs_i32)(int32_t val) -{ - if (val < 0) { - return -val; - } else { - return val; - } -} - -/* negative absolute value 32-bit */ -int32_t HELPER(nabs_i32)(int32_t val) -{ - if (val < 0) { - return val; - } else { - return -val; - } -} - /* count leading zeros, for find leftmost one */ uint64_t HELPER(clz)(uint64_t v) { From 9cb32c442e11d16b747fa07e29dd29b5d8227b57 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 23:42:25 +0200 Subject: [PATCH 05/34] target-s390x: add a tod2time function Add a tod2time function similar to the time2tod one, instead of open coding the conversion. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 5 +++++ target-s390x/misc_helper.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index a71abaeef7..3140f75333 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -995,6 +995,11 @@ static inline uint64_t time2tod(uint64_t ns) { return (ns << 9) / 125; } +/* Converts s390's clock format to ns */ +static inline uint64_t tod2time(uint64_t t) { + return (t * 125) >> 9; +} + static inline void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, uint64_t param64) { diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index e1007fa35b..230bafdba2 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -294,7 +294,7 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) /* difference between now and then */ time -= clock_value(env); /* nanoseconds */ - time = (time * 125) >> 9; + time = tod2time(time); timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); } @@ -314,7 +314,7 @@ void HELPER(spt)(CPUS390XState *env, uint64_t time) } /* nanoseconds */ - time = (time * 125) >> 9; + time = tod2time(time); timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); } From c941f07485e56e4b2653048e166b720428307acb Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 23:42:26 +0200 Subject: [PATCH 06/34] target-s390x: simplify SCKC helper The clock comparator and the QEMU timer work the same way, triggering at a given time, they just differ by the origin and the scale. It is therefore possible to go from one to another without using the current clock value. This spares two calls to qemu_clock_get_ns, which probably return slightly different values, possibly reducing the accuracy. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/misc_helper.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 230bafdba2..120807f20b 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -291,12 +291,13 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) return; } - /* difference between now and then */ - time -= clock_value(env); + /* difference between origins */ + time -= env->tod_offset; + /* nanoseconds */ time = tod2time(time); - timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); + timer_mod(env->tod_timer, env->tod_basetime + time); } /* Store Clock Comparator */ From d9d55f1108f45c866098731d95fef88409ff1e94 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 23:42:27 +0200 Subject: [PATCH 07/34] target-s390x: streamline STCK helper Now that clock_value is only used in one place, we can inline it in the STCK helper. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/misc_helper.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 120807f20b..fa105fa058 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -268,7 +268,8 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1) tlb_flush_page(cs, TARGET_PAGE_SIZE); } -static inline uint64_t clock_value(CPUS390XState *env) +/* Store Clock */ +uint64_t HELPER(stck)(CPUS390XState *env) { uint64_t time; @@ -278,12 +279,6 @@ static inline uint64_t clock_value(CPUS390XState *env) return time; } -/* Store Clock */ -uint64_t HELPER(stck)(CPUS390XState *env) -{ - return clock_value(env); -} - /* Set Clock Comparator */ void HELPER(sckc)(CPUS390XState *env, uint64_t time) { From aa9e14e684506e8ddf02bd5cff720520827bf244 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 23:42:28 +0200 Subject: [PATCH 08/34] target-s390x: implement STCKC helper The STCKC instruction just returns the last written clock comparator value and KVM already provides the corresponding variable. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/misc_helper.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index fa105fa058..57aee9589c 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -286,6 +286,8 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) return; } + env->ckc = time; + /* difference between origins */ time -= env->tod_offset; @@ -298,8 +300,7 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time) /* Store Clock Comparator */ uint64_t HELPER(stckc)(CPUS390XState *env) { - /* XXX implement */ - return 0; + return env->ckc; } /* Set CPU Timer */ From b8ae94bd398ff772f40fb232887ecbcbd244c3d4 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 18 May 2015 23:42:29 +0200 Subject: [PATCH 09/34] target-s390x: implement STPT helper Save the timer target value in the SPT helper, so that the STPT helper can compute the remaining time. This allow the Linux kernel to correctly do time accounting. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/misc_helper.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 57aee9589c..3ec7268b72 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -313,14 +313,15 @@ void HELPER(spt)(CPUS390XState *env, uint64_t time) /* nanoseconds */ time = tod2time(time); - timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time); + env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time; + + timer_mod(env->cpu_timer, env->cputm); } /* Store CPU Timer */ uint64_t HELPER(stpt)(CPUS390XState *env) { - /* XXX implement */ - return 0; + return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)); } /* Store System Information */ From aa752a4afc2a4b7ede58a960a9d553b3fd9e6882 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Tue, 26 May 2015 11:09:44 +0200 Subject: [PATCH 10/34] target-s390x: fix LOAD MULTIPLE instruction on page boundary When consecutive memory locations are on page boundary a page fault might occur when using the LOAD MULTIPLE instruction. In that case real hardware doesn't load any register. This is an important detail in case the base register is in the list of registers to be loaded. If a page fault occurs this register might be overwritten and when the instruction is later restarted the wrong base register value is useD. Fix this by first loading the first and last value from memory, hence triggering all possible page faults, and then the remaining registers. This fixes random segmentation faults seen in the guest. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/translate.c | 134 +++++++++++++++++++++++++++++---------- 1 file changed, 102 insertions(+), 32 deletions(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 0c6d1f6a37..63885f8b6c 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2440,21 +2440,45 @@ static ExitStatus op_lm32(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - TCGv_i64 t = tcg_temp_new_i64(); - TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t1, t2; - while (1) { - tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); - store_reg32_i64(r1, t); - if (r1 == r3) { - break; - } - tcg_gen_add_i64(o->in2, o->in2, t4); - r1 = (r1 + 1) & 15; + /* Only one register to read. */ + t1 = tcg_temp_new_i64(); + if (unlikely(r1 == r3)) { + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t1); + tcg_temp_free(t1); + return NO_EXIT; } - tcg_temp_free_i64(t); - tcg_temp_free_i64(t4); + /* First load the values of the first and last registers to trigger + possible page faults. */ + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15)); + tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s)); + store_reg32_i64(r1, t1); + store_reg32_i64(r3, t2); + + /* Only two registers to read. */ + if (((r1 + 1) & 15) == r3) { + tcg_temp_free(t2); + tcg_temp_free(t1); + return NO_EXIT; + } + + /* Then load the remaining registers. Page fault can't occur. */ + r3 = (r3 - 1) & 15; + tcg_gen_movi_i64(t2, 4); + while (r1 != r3) { + r1 = (r1 + 1) & 15; + tcg_gen_add_i64(o->in2, o->in2, t2); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t1); + } + tcg_temp_free(t2); + tcg_temp_free(t1); + return NO_EXIT; } @@ -2462,21 +2486,45 @@ static ExitStatus op_lmh(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - TCGv_i64 t = tcg_temp_new_i64(); - TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t1, t2; - while (1) { - tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); - store_reg32h_i64(r1, t); - if (r1 == r3) { - break; - } - tcg_gen_add_i64(o->in2, o->in2, t4); - r1 = (r1 + 1) & 15; + /* Only one register to read. */ + t1 = tcg_temp_new_i64(); + if (unlikely(r1 == r3)) { + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t1); + tcg_temp_free(t1); + return NO_EXIT; } - tcg_temp_free_i64(t); - tcg_temp_free_i64(t4); + /* First load the values of the first and last registers to trigger + possible page faults. */ + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15)); + tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s)); + store_reg32h_i64(r1, t1); + store_reg32h_i64(r3, t2); + + /* Only two registers to read. */ + if (((r1 + 1) & 15) == r3) { + tcg_temp_free(t2); + tcg_temp_free(t1); + return NO_EXIT; + } + + /* Then load the remaining registers. Page fault can't occur. */ + r3 = (r3 - 1) & 15; + tcg_gen_movi_i64(t2, 4); + while (r1 != r3) { + r1 = (r1 + 1) & 15; + tcg_gen_add_i64(o->in2, o->in2, t2); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t1); + } + tcg_temp_free(t2); + tcg_temp_free(t1); + return NO_EXIT; } @@ -2484,18 +2532,40 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - TCGv_i64 t8 = tcg_const_i64(8); + TCGv_i64 t1, t2; - while (1) { + /* Only one register to read. */ + if (unlikely(r1 == r3)) { tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); - if (r1 == r3) { - break; - } - tcg_gen_add_i64(o->in2, o->in2, t8); - r1 = (r1 + 1) & 15; + return NO_EXIT; } - tcg_temp_free_i64(t8); + /* First load the values of the first and last registers to trigger + possible page faults. */ + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(t2, o->in2, 8 * ((r3 - r1) & 15)); + tcg_gen_qemu_ld64(regs[r3], t2, get_mem_index(s)); + tcg_gen_mov_i64(regs[r1], t1); + tcg_temp_free(t2); + + /* Only two registers to read. */ + if (((r1 + 1) & 15) == r3) { + tcg_temp_free(t1); + return NO_EXIT; + } + + /* Then load the remaining registers. Page fault can't occur. */ + r3 = (r3 - 1) & 15; + tcg_gen_movi_i64(t1, 8); + while (r1 != r3) { + r1 = (r1 + 1) & 15; + tcg_gen_add_i64(o->in2, o->in2, t1); + tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); + } + tcg_temp_free(t1); + return NO_EXIT; } From 9bebf9863bd16cc824231ad71959a338dc1819ac Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:22 +0200 Subject: [PATCH 11/34] target-s390x: fix PSW value on dynamical exception from helpers runtime_exception computes the psw.addr value using the actual exception address and the instruction length computed by calling the get_ilen function. However as explained above the get_ilen code, it returns the actual instruction length, and not the ILC. Therefore there is no need to multiply the value by 2. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/misc_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c index 3ec7268b72..b375ab724b 100644 --- a/target-s390x/misc_helper.c +++ b/target-s390x/misc_helper.c @@ -61,7 +61,7 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, /* Advance past the insn. */ t = cpu_ldub_code(env, env->psw.addr); env->int_pgm_ilen = t = get_ilen(t); - env->psw.addr += 2 * t; + env->psw.addr += t; cpu_loop_exit(cs); } From 1f65958d9c21fd3b461f6b645e7884866313c1f3 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:23 +0200 Subject: [PATCH 12/34] target-s390x: fix MMU index computation The cpu_mmu_index function wrongly looks at PSW P bit to determine the MMU index, while this bit actually only control the use of priviledge instructions. The addressing mode is detected by looking at the PSW ASC bits instead. This used to work more or less correctly up to kernel 3.6 as the kernel was running in primary space and userland in secondary space. Since kernel 3.7 the default is to run the kernel in home space and userland in primary space. While the current QEMU code seems to work it open some security issues, like accessing the lowcore memory in R/W mode from a userspace process once it has been accessed by the kernel (it is then cached by the QEMU TLB). At the same time change the MMU_USER_IDX value so that it matches the value used in recent kernels. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index 3140f75333..adb9a84237 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -48,7 +48,7 @@ #define MMU_MODE1_SUFFIX _secondary #define MMU_MODE2_SUFFIX _home -#define MMU_USER_IDX 1 +#define MMU_USER_IDX 0 #define MAX_EXT_QUEUE 16 #define MAX_IO_QUEUE 16 @@ -304,11 +304,18 @@ static inline CPU_DoubleU *get_freg(CPUS390XState *cs, int nr) static inline int cpu_mmu_index (CPUS390XState *env) { - if (env->psw.mask & PSW_MASK_PSTATE) { + switch (env->psw.mask & PSW_MASK_ASC) { + case PSW_ASC_PRIMARY: + return 0; + case PSW_ASC_SECONDARY: return 1; + case PSW_ASC_HOME: + return 2; + case PSW_ASC_ACCREG: + /* Fallthrough: access register mode is not yet supported */ + default: + abort(); } - - return 0; } static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, From 2daea9c16ffe61377b6e5426d9c52014bf538df3 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:24 +0200 Subject: [PATCH 13/34] target-s390x: define default NaN values Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- fpu/softfloat-specialize.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index fa1214a4b8..6dd41d8978 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -113,7 +113,7 @@ const float16 float16_default_nan = const_float16(0xFE00); #if defined(TARGET_SPARC) const float32 float32_default_nan = const_float32(0x7FFFFFFF); #elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \ - defined(TARGET_XTENSA) + defined(TARGET_XTENSA) || defined(TARGET_S390X) const float32 float32_default_nan = const_float32(0x7FC00000); #elif SNAN_BIT_IS_ONE const float32 float32_default_nan = const_float32(0x7FBFFFFF); @@ -126,7 +126,8 @@ const float32 float32_default_nan = const_float32(0xFFC00000); *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) const float64 float64_default_nan = const_float64(LIT64( 0x7FFFFFFFFFFFFFFF )); -#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) || \ + defined(TARGET_S390X) const float64 float64_default_nan = const_float64(LIT64( 0x7FF8000000000000 )); #elif SNAN_BIT_IS_ONE const float64 float64_default_nan = const_float64(LIT64(0x7FF7FFFFFFFFFFFF)); @@ -155,6 +156,9 @@ const floatx80 floatx80_default_nan #if SNAN_BIT_IS_ONE #define float128_default_nan_high LIT64(0x7FFF7FFFFFFFFFFF) #define float128_default_nan_low LIT64(0xFFFFFFFFFFFFFFFF) +#elif defined(TARGET_S390X) +#define float128_default_nan_high LIT64( 0x7FFF800000000000 ) +#define float128_default_nan_low LIT64( 0x0000000000000000 ) #else #define float128_default_nan_high LIT64( 0xFFFF800000000000 ) #define float128_default_nan_low LIT64( 0x0000000000000000 ) From f821135cdd4df09b1362666ddfbdfd162b905b1f Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:25 +0200 Subject: [PATCH 14/34] target-s390x: silence NaNs for LOAD LENGTHENED and LOAD ROUNDED LOAD LENGTHENED and LOAD ROUNDED are considered as FP operations and thus need to convert input sNaN into corresponding qNaN. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/fpu_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index b946ec1d51..96eabb6fc2 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -265,7 +265,7 @@ uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) { float64 ret = float32_to_float64(f2, &env->fpu_status); handle_exceptions(env, GETPC()); - return ret; + return float64_maybe_silence_nan(ret); } /* convert 128-bit float to 64-bit float */ @@ -273,7 +273,7 @@ uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al) { float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); handle_exceptions(env, GETPC()); - return ret; + return float64_maybe_silence_nan(ret); } /* convert 64-bit float to 128-bit float */ @@ -281,7 +281,7 @@ uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) { float128 ret = float64_to_float128(f2, &env->fpu_status); handle_exceptions(env, GETPC()); - return RET128(ret); + return RET128(float128_maybe_silence_nan(ret)); } /* convert 32-bit float to 128-bit float */ @@ -289,7 +289,7 @@ uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) { float128 ret = float32_to_float128(f2, &env->fpu_status); handle_exceptions(env, GETPC()); - return RET128(ret); + return RET128(float128_maybe_silence_nan(ret)); } /* convert 64-bit float to 32-bit float */ @@ -297,7 +297,7 @@ uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2) { float32 ret = float64_to_float32(f2, &env->fpu_status); handle_exceptions(env, GETPC()); - return ret; + return float32_maybe_silence_nan(ret); } /* convert 128-bit float to 32-bit float */ @@ -305,7 +305,7 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al) { float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); handle_exceptions(env, GETPC()); - return ret; + return float32_maybe_silence_nan(ret); } /* 32-bit FP compare */ From 4a33565f9f46145d8cc701ab623b18bf423c469e Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:26 +0200 Subject: [PATCH 15/34] target-s390x: detect tininess before rounding for FP operations The s390x floating point unit detects tininess before rounding, so set the softfloat fp_status up appropriately. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/cpu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c index d2f9836e86..7f17823e40 100644 --- a/target-s390x/cpu.c +++ b/target-s390x/cpu.c @@ -118,6 +118,10 @@ static void s390_cpu_initial_reset(CPUState *s) env->pfault_token = -1UL; + /* tininess for underflow is detected before rounding */ + set_float_detect_tininess(float_tininess_before_rounding, + &env->fpu_status); + /* Reset state inside the kernel that we cannot access yet from QEMU. */ if (kvm_enabled()) { kvm_s390_reset_vcpu(cpu); @@ -143,6 +147,10 @@ static void s390_cpu_full_reset(CPUState *s) env->pfault_token = -1UL; + /* tininess for underflow is detected before rounding */ + set_float_detect_tininess(float_tininess_before_rounding, + &env->fpu_status); + /* Reset state inside the kernel that we cannot access yet from QEMU. */ if (kvm_enabled()) { kvm_s390_reset_vcpu(cpu); From 92892330e78ffca7bebf03f4f7161c5bbd6602d2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:30 +0200 Subject: [PATCH 16/34] target-s390x: move a few instructions to the correct facility LY is part of the long-displacement facility. RISBHG and RISBLG are part of the high-word facility. STCMH is part of the z/Architecture. Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 72c3a2edda..e10aa6bfc3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -336,7 +336,7 @@ /* LOAD */ C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0) C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0) - C(0xe358, LY, RXY_a, Z, 0, a2, new, r1_32, ld32s, 0) + C(0xe358, LY, RXY_a, LD, 0, a2, new, r1_32, ld32s, 0) C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0) C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0) C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0) @@ -595,8 +595,8 @@ /* ROTATE THEN INSERT SELECTED BITS */ C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) - C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) - C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0) + C(0xec5d, RISBHG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) + C(0xec51, RISBLG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) /* ROTATE_THEN SELECTED BITS */ C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0) @@ -670,7 +670,7 @@ /* STORE CHARACTERS UNDER MASK */ D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) - D(0xeb2c, STCMH, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 32) + D(0xeb2c, STCMH, RSY_b, Z, r1_o, a2, 0, 0, stcm, 0, 32) /* STORE HALFWORD */ C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) From a1c7610a68795d66249c25166220324d4d0b9289 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 25 May 2015 01:47:31 +0200 Subject: [PATCH 17/34] target-s390x: implement LAY and LAEY instructions This complete the general-instructions-extension facility, enable it. Signed-off-by: Aurelien Jarno [agraf: remove facility bit] Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e10aa6bfc3..750706246d 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -357,6 +357,9 @@ /* LOAD ADDRESS */ C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0) C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0) +/* LOAD ADDRESS EXTENDED */ + C(0x5100, LAE, RX_a, Z, 0, a2, 0, r1, mov2e, 0) + C(0xe375, LAEY, RXY_a, GIE, 0, a2, 0, r1, mov2e, 0) /* LOAD ADDRESS RELATIVE LONG */ C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0) /* LOAD AND ADD */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 63885f8b6c..d508bc2b54 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2596,6 +2596,41 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mov2e(DisasContext *s, DisasOps *o) +{ + int b2 = get_field(s->fields, b2); + TCGv ar1 = tcg_temp_new_i64(); + + o->out = o->in2; + o->g_out = o->g_in2; + TCGV_UNUSED_I64(o->in2); + o->g_in2 = false; + + switch (s->tb->flags & FLAG_MASK_ASC) { + case PSW_ASC_PRIMARY >> 32: + tcg_gen_movi_i64(ar1, 0); + break; + case PSW_ASC_ACCREG >> 32: + tcg_gen_movi_i64(ar1, 1); + break; + case PSW_ASC_SECONDARY >> 32: + if (b2) { + tcg_gen_ld32u_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[b2])); + } else { + tcg_gen_movi_i64(ar1, 0); + } + break; + case PSW_ASC_HOME >> 32: + tcg_gen_movi_i64(ar1, 2); + break; + } + + tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1])); + tcg_temp_free_i64(ar1); + + return NO_EXIT; +} + static ExitStatus op_movx(DisasContext *s, DisasOps *o) { o->out = o->in1; From 111d7f4a69751d333bac32526cd252add6b071d3 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:41 +0200 Subject: [PATCH 18/34] target-s390x: fix exception for invalid operation code When an operation code is not recognized (ie invalid instruction) an operation exception should be generated instead of a specification exception. The latter is for valid opcode, with invalid operands or modifiers. This give a very basic GDB support in the guest, as it uses the invalid opcode 0x0001 to generate a trap. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index d508bc2b54..c7ebd21ec8 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -320,7 +320,7 @@ static void gen_program_exception(DisasContext *s, int code) static inline void gen_illegal_opcode(DisasContext *s) { - gen_program_exception(s, PGM_SPECIFICATION); + gen_program_exception(s, PGM_OPERATION); } #ifndef CONFIG_USER_ONLY From 1dedb9b76f061c8da730002f6c21a1fa2b76b106 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:42 +0200 Subject: [PATCH 19/34] target-s390x: fix CLGIT instruction The COMPARE LOGICAL IMMEDIATE AND TRAP instruction should compare the numbers as unsigned, as its name implies. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 750706246d..3955443fbf 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -231,7 +231,7 @@ D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1) D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1) - D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 0) + D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 1) /* CONVERT TO DECIMAL */ C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0) From 74266b4a5837b46477034a39acc2be3a3afba431 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:43 +0200 Subject: [PATCH 20/34] target-s390x: change CHRL and CGHRL format to RIL-b Change to match the PoP. In practice both format RIL-a and RIL-b have the same fields. They differ on the way we decode the fields, and it's done correctly in QEMU. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 3955443fbf..75672a03f0 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -159,8 +159,8 @@ C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64) C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64) /* COMPARE HALFWORD RELATIVE LONG */ - C(0xc605, CHRL, RIL_a, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) - C(0xc604, CGHRL, RIL_a, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) + C(0xc605, CHRL, RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) + C(0xc604, CGHRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) /* COMPARE LOGICAL */ C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) From f7c2114067cc32eb8d8f79b7374a641ec5f4eb72 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:44 +0200 Subject: [PATCH 21/34] target-s390x: move STORE CLOCK FAST to the correct facility STORE CLOCK FAST should be in the SCF facility. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 75672a03f0..c09f8a12c3 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -815,7 +815,7 @@ C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0) /* STORE CLOCK */ C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0) - C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0) + C(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0) /* STORE CLOCK EXTENDED */ C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0) /* STORE CLOCK COMPARATOR */ From 9182886d797a20925d801a3378ca5330c0d91dfb Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:45 +0200 Subject: [PATCH 22/34] target-s390x: move SET DFP ROUNDING MODE to the correct facility It belongs to the DFP rounding facility. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index c09f8a12c3..83256842a8 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -622,7 +622,7 @@ C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0) C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0) /* SET DFP ROUNDING MODE */ - C(0xb2b9, SRNMT, S, DFP, 0, 0, 0, 0, srnm, 0) + C(0xb2b9, SRNMT, S, DFPR, 0, 0, 0, 0, srnm, 0) /* SHIFT LEFT SINGLE */ D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31) From ed0bcecec105137567f461e5b57834e72c851855 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:46 +0200 Subject: [PATCH 23/34] target-s390x: implement LOAD FP INTEGER instructions This is needed to pass the gcc.c-torture/execute/ieee/20010114-2.c test in the gcc testsuite. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/fpu_helper.c | 31 +++++++++++++++++++++++++++++++ target-s390x/helper.h | 3 +++ target-s390x/insn-data.def | 4 ++++ target-s390x/translate.c | 25 +++++++++++++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c index 96eabb6fc2..45b7ddfbe3 100644 --- a/target-s390x/fpu_helper.c +++ b/target-s390x/fpu_helper.c @@ -552,6 +552,37 @@ uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3) return ret; } +/* round to integer 32-bit */ +uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float32 ret = float32_round_to_int(f2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* round to integer 64-bit */ +uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float64 ret = float64_round_to_int(f2, &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return ret; +} + +/* round to integer 128-bit */ +uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3) +{ + int hold = swap_round_mode(env, m3); + float128 ret = float128_round_to_int(make_float128(ah, al), + &env->fpu_status); + set_float_rounding_mode(hold, &env->fpu_status); + handle_exceptions(env, GETPC()); + return RET128(ret); +} + /* 32-bit FP multiply and add */ uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, uint64_t f2, uint64_t f3) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index e6f2afb44f..cb0b421cd8 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -60,6 +60,9 @@ DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) +DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32) +DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 83256842a8..a12939de66 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -479,6 +479,10 @@ C(0xb29d, LFPC, S, Z, 0, m2_32u, 0, 0, sfpc, 0) /* LOAD FPC AND SIGNAL */ C(0xb2bd, LFAS, S, IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0) +/* LOAD FP INTEGER */ + C(0xb357, FIEBR, RRF_e, Z, 0, e2, new, e1, fieb, 0) + C(0xb35f, FIDBR, RRF_e, Z, 0, f2_o, f1, 0, fidb, 0) + C(0xb347, FIXBR, RRF_e, Z, 0, x2_o, x1, 0, fixb, 0) /* LOAD LENGTHENED */ C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c7ebd21ec8..b0dbfe8da7 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -2116,6 +2116,31 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_fieb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_fieb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_fidb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_fidb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_fixb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m3); + return_low128(o->out2); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + static ExitStatus op_flogr(DisasContext *s, DisasOps *o) { /* We'll use the original input for cc computation, since we get to From 54f007750978ffbb98ce933077e0d1741e0202b0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:47 +0200 Subject: [PATCH 24/34] target-s390x: implement TRANSLATE AND TEST instruction It is part of the basic zArchitecture instructions. Allow it to be call from EXECUTE. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/helper.h | 1 + target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 24 ++++++++++++++++++++++++ target-s390x/translate.c | 10 ++++++++++ 4 files changed, 37 insertions(+) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index cb0b421cd8..48b015eab3 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -77,6 +77,7 @@ DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_4(trt, i32, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index a12939de66..e401754046 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -759,6 +759,8 @@ /* TRANSLATE */ C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) +/* TRANSLATE AND TEST */ + C(0xdd00, TRT, SS_a, Z, la1, a2, 0, 0, trt, 0) /* UNPACK */ /* Really format SS_b, but we pack both lengths into one argument diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 0e8cd0f489..e19e1aa961 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -509,6 +509,9 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, case 0xc00: helper_tr(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2)); + case 0xd00: + cc = helper_trt(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); break; default: goto abort; @@ -801,6 +804,27 @@ void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, } } +uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans) +{ + uint32_t cc = 0; + int i; + + for (i = 0; i <= len; i++) { + uint8_t byte = cpu_ldub_data(env, array + i); + uint8_t sbyte = cpu_ldub_data(env, trans + byte); + + if (sbyte != 0) { + env->regs[1] = array + i; + env->regs[2] = (env->regs[2] & ~0xff) | sbyte; + cc = (i == len) ? 2 : 1; + break; + } + } + + return cc; +} + #if !defined(CONFIG_USER_ONLY) void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index b0dbfe8da7..003598df6b 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3787,6 +3787,16 @@ static ExitStatus op_tr(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_trt(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_unpk(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From 3f4de6756cd87b508b37c7ffa93f7b827832c4eb Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:48 +0200 Subject: [PATCH 25/34] target-s390x: implement TRANSLATE EXTENDED instruction It is part of the basic zArchitecture instructions. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/helper.h | 1 + target-s390x/insn-data.def | 2 ++ target-s390x/mem_helper.c | 39 ++++++++++++++++++++++++++++++++++++++ target-s390x/translate.c | 9 +++++++++ 4 files changed, 51 insertions(+) diff --git a/target-s390x/helper.h b/target-s390x/helper.h index 48b015eab3..7e048ecb00 100644 --- a/target-s390x/helper.h +++ b/target-s390x/helper.h @@ -77,6 +77,7 @@ DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_4(tre, i64, env, i64, i64, i64) DEF_HELPER_4(trt, i32, env, i32, i64, i64) DEF_HELPER_4(cksm, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e401754046..e638b0ba83 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -761,6 +761,8 @@ C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0) /* TRANSLATE AND TEST */ C(0xdd00, TRT, SS_a, Z, la1, a2, 0, 0, trt, 0) +/* TRANSLATE EXTENDED */ + C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0) /* UNPACK */ /* Really format SS_b, but we pack both lengths into one argument diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index e19e1aa961..30a2a6dfd5 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -804,6 +804,45 @@ void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, } } +uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, + uint64_t len, uint64_t trans) +{ + uint8_t end = env->regs[0] & 0xff; + uint64_t l = len; + uint64_t i; + + if (!(env->psw.mask & PSW_MASK_64)) { + array &= 0x7fffffff; + l = (uint32_t)l; + } + + /* 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. */ + if (l > 0x2000) { + l = 0x2000; + env->cc_op = 3; + } else { + env->cc_op = 0; + } + + for (i = 0; i < l; i++) { + uint8_t byte, new_byte; + + byte = cpu_ldub_data(env, array + i); + + if (byte == end) { + env->cc_op = 1; + break; + } + + new_byte = cpu_ldub_data(env, trans + byte); + cpu_stb_data(env, array + i, new_byte); + } + + env->retxl = len - i; + return array + i; +} + uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array, uint64_t trans) { diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 003598df6b..c8ef24a08e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -3787,6 +3787,15 @@ static ExitStatus op_tr(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_tre(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_trt(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From df46283ce7be962002a30140a91ffbb56832cc2d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:49 +0200 Subject: [PATCH 26/34] target-s390x: implement LPDFR and LNDFR instructions This complete the floating point support sign handling facility. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index e638b0ba83..41b5f43d53 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -451,6 +451,7 @@ C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32) C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64) C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128) + C(0xb371, LNDFR, RRE, FPSSH, 0, f2_o, f1, 0, nabsf64, 0) /* LOAD ON CONDITION */ C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0) C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0) @@ -464,6 +465,7 @@ C(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32) C(0xb310, LPDBR, RRE, Z, 0, f2_o, f1, 0, absf64, f64) C(0xb340, LPXBR, RRE, Z, 0, x2_o, x1, 0, absf128, f128) + C(0xb370, LPDFR, RRE, FPSSH, 0, f2_o, f1, 0, absf64, 0) /* LOAD REVERSED */ C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0) C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0) From 375ee58bedcda359011fe7fa99e0647f66f9ffa0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:50 +0200 Subject: [PATCH 27/34] target-s390x: implement miscellaneous-instruction-extensions facility RISBGN is the same as RISBG, but without setting the condition code. CLT and CLGT are the same as CLRT and CLGRT, but using memory for the second operand. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 3 +++ target-s390x/translate.c | 1 + 2 files changed, 4 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 41b5f43d53..ddc6337584 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -230,6 +230,8 @@ /* COMPARE LOGICAL AND TRAP */ D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1) D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1) + D(0xeb23, CLT, RSY_b, MIE, r1_32u, m2_32u, 0, 0, ct, 0, 1) + D(0xeb2b, CLGT, RSY_b, MIE, r1_o, m2_64, 0, 0, ct, 0, 1) D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1) D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 1) @@ -604,6 +606,7 @@ /* ROTATE THEN INSERT SELECTED BITS */ C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64) + C(0xec59, RISBGN, RIE_f, MIE, 0, r2, r1, 0, risbg, 0) C(0xec5d, RISBHG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) C(0xec51, RISBLG, RIE_f, HW, 0, r2, r1, 0, risbg, 0) /* ROTATE_THEN SELECTED BITS */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index c8ef24a08e..fbf7f91ec0 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1119,6 +1119,7 @@ typedef enum DisasFacility { FAC_HFP_MA, /* HFP multiply-and-add/subtract */ FAC_HW, /* high-word */ FAC_IEEEE_SIM, /* IEEE exception sumilation */ + FAC_MIE, /* miscellaneous-instruction-extensions */ FAC_LOC, /* load/store on condition */ FAC_LD, /* long displacement */ FAC_PC, /* population count */ From 782a8479522f8e4a596f968e4acad5c10b77e061 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:51 +0200 Subject: [PATCH 28/34] target-s390x: implement load-and-trap facility At the same time move the trap code from op_ct into gen_trap and use it for all new functions. The value needs to be stored back to register before the exception, but also before the brcond (as we don't use temp locals). That's why we can't use wout helper. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 10 +++++ target-s390x/translate.c | 80 +++++++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index ddc6337584..7bf686b354 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -389,6 +389,9 @@ C(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32) C(0xb312, LTDBR, RRE, Z, 0, f2_o, 0, f1, mov2, f64) C(0xb342, LTXBR, RRE, Z, 0, x2_o, 0, x1, movx, f128) +/* LOAD AND TRAP */ + C(0xe39f, LAT, RXY_a, LAT, 0, m2_32u, r1, 0, lat, 0) + C(0xe385, LGAT, RXY_a, LAT, 0, a2, r1, 0, lgat, 0) /* LOAD BYTE */ C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0) C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) @@ -414,9 +417,13 @@ /* LOAD HALFWORD RELATIVE LONG */ C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) +/* LOAG HIGH AND TRAP */ + C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0) /* LOAD LOGICAL */ C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0) C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0) +/* LOAD LOGICAL AND TRAP */ + C(0xe39d, LLGFAT, RXY_a, LAT, 0, a2, r1, 0, llgfat, 0) /* LOAD LOGICAL RELATIVE LONG */ C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0) /* LOAD LOGICAL CHARACTER */ @@ -442,6 +449,9 @@ /* LOAD LOGICAL THIRTY ONE BITS */ C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0) C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0) +/* LOAD LOGICAL THIRTY ONE BITS AND TRAP */ + C(0xe39c, LLGTAT, RXY_a, LAT, 0, m2_32u, r1, 0, llgtat, 0) + /* LOAD FPR FROM GR */ C(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0) /* LOAD GR FROM FPR */ diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fbf7f91ec0..9e53c9812e 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -323,6 +323,20 @@ static inline void gen_illegal_opcode(DisasContext *s) gen_program_exception(s, PGM_OPERATION); } +static inline void gen_trap(DisasContext *s) +{ + TCGv_i32 t; + + /* Set DXC to 0xff. */ + t = tcg_temp_new_i32(); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ori_i32(t, t, 0xff00); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_temp_free_i32(t); + + gen_program_exception(s, PGM_DATA); +} + #ifndef CONFIG_USER_ONLY static void check_privileged(DisasContext *s) { @@ -1120,6 +1134,7 @@ typedef enum DisasFacility { FAC_HW, /* high-word */ FAC_IEEEE_SIM, /* IEEE exception sumilation */ FAC_MIE, /* miscellaneous-instruction-extensions */ + FAC_LAT, /* load-and-trap */ FAC_LOC, /* load/store on condition */ FAC_LD, /* long displacement */ FAC_PC, /* population count */ @@ -1968,7 +1983,6 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) { int m3 = get_field(s->fields, m3); TCGLabel *lab = gen_new_label(); - TCGv_i32 t; TCGCond c; c = tcg_invert_cond(ltgt_cond[m3]); @@ -1977,15 +1991,8 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) } tcg_gen_brcond_i64(c, o->in1, o->in2, lab); - /* Set DXC to 0xff. */ - t = tcg_temp_new_i32(); - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_gen_ori_i32(t, t, 0xff00); - tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i32(t); - /* Trap. */ - gen_program_exception(s, PGM_DATA); + gen_trap(s); gen_set_label(lab); return NO_EXIT; @@ -2351,6 +2358,61 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_lat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + store_reg32_i64(get_field(s->fields, r1), o->in2); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_lgat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s)); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_lfhat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + store_reg32h_i64(get_field(s->fields, r1), o->in2); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_llgfat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s)); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_llgtat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + static ExitStatus op_loc(DisasContext *s, DisasOps *o) { DisasCompare c; From a1f12d855b6ec79a640fa6a74d12884f1646ecfe Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:52 +0200 Subject: [PATCH 29/34] target-s390x: implement high-word facility Besides RISBHG and RISBLG, all high-word instructions are not implemented. Fix that. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Signed-off-by: Alexander Graf --- target-s390x/insn-data.def | 47 +++++++++++++++++++++++++++++++++++ target-s390x/translate.c | 51 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def index 7bf686b354..1223670721 100644 --- a/target-s390x/insn-data.def +++ b/target-s390x/insn-data.def @@ -34,6 +34,9 @@ C(0xb34a, AXBR, RRE, Z, 0, x2_o, x1, 0, axb, f128) C(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32) C(0xed1a, ADB, RXE, Z, f1_o, m2_64, f1, 0, adb, f64) +/* ADD HIGH */ + C(0xb9c8, AHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, adds32) + C(0xb9d8, AHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, adds32) /* ADD IMMEDIATE */ C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32) C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32) @@ -41,6 +44,8 @@ C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64) C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64) C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64) +/* ADD IMMEDIATE HIGH */ + C(0xcc08, AIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, adds32) /* ADD HALFWORD */ C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32) C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32) @@ -58,6 +63,9 @@ C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, add, addu64) C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, add, addu64) C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, add, addu64) +/* ADD LOGICAL HIGH */ + C(0xb9ca, ALHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, addu32) + C(0xb9da, ALHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, addu32) /* ADD LOGICAL IMMEDIATE */ C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32) C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64) @@ -66,6 +74,9 @@ C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32) C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64) C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64) +/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */ + C(0xcc0a, ALSIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, addu32) + C(0xcc0b, ALSIHN, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, 0) /* ADD LOGICAL WITH CARRY */ C(0xb998, ALCR, RRE, Z, r1, r2, new, r1_32, addc, addc32) C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc, addc64) @@ -111,6 +122,8 @@ /* BRANCH RELATIVE ON COUNT */ C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0) C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0) +/* BRANCH RELATIVE ON COUNT HIGH */ + C(0xcc06, BRCTH, RIL_b, HW, 0, 0, 0, 0, bcth, 0) /* BRANCH ON INDEX */ D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0) D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1) @@ -161,6 +174,12 @@ /* COMPARE HALFWORD RELATIVE LONG */ C(0xc605, CHRL, RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32) C(0xc604, CGHRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64) +/* COMPARE HIGH */ + C(0xb9cd, CHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmps32) + C(0xb9dd, CHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmps32) + C(0xe3cd, CHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmps32) +/* COMPARE IMMEDIATE HIGH */ + C(0xcc0d, CIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmps32) /* COMPARE LOGICAL */ C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32) @@ -171,6 +190,10 @@ C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64) C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64) C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0) +/* COMPARE LOGICAL HIGH */ + C(0xb9cf, CLHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmpu32) + C(0xb9df, CLHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmpu32) + C(0xe3cf, CLHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmpu32) /* COMPARE LOGICAL IMMEDIATE */ C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32) C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64) @@ -179,6 +202,8 @@ C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64) C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64) C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL IMMEDIATE HIGH */ + C(0xcc0f, CLIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmpu32) /* COMPARE LOGICAL RELATIVE LONG */ C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32) C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64) @@ -397,6 +422,8 @@ C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0) C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0) C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0) +/* LOAD BYTE HIGH */ + C(0xe3c0, LBH, RXY_a, HW, 0, a2, new, r1_32h, ld8s, 0) /* LOAD COMPLEMENT */ C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32) C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64) @@ -411,12 +438,16 @@ C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0) C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0) C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0) +/* LOAD HALFWORD HIGH */ + C(0xe3c4, LHH, RXY_a, HW, 0, a2, new, r1_32h, ld16s, 0) /* LOAD HALFWORD IMMEDIATE */ C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0) C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0) /* LOAD HALFWORD RELATIVE LONG */ C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0) C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0) +/* LOAD HIGH */ + C(0xe3ca, LFH, RXY_a, HW, 0, a2, new, r1_32h, ld32u, 0) /* LOAG HIGH AND TRAP */ C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0) /* LOAD LOGICAL */ @@ -431,11 +462,15 @@ C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0) C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0) C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0) +/* LOAD LOGICAL CHARACTER HIGH */ + C(0xe3c2, LLCH, RXY_a, HW, 0, a2, new, r1_32h, ld8u, 0) /* LOAD LOGICAL HALFWORD */ C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0) C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0) C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0) C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0) +/* LOAD LOGICAL HALFWORD HIGH */ + C(0xe3c6, LLHH, RXY_a, HW, 0, a2, new, r1_32h, ld16u, 0) /* LOAD LOGICAL HALFWORD RELATIVE LONG */ C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0) C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0) @@ -689,6 +724,8 @@ /* STORE CHARACTER */ C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0) C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0) +/* STORE CHARACTER HIGH */ + C(0xe3c3, STCH, RXY_a, HW, r1_sr32, a2, 0, 0, st8, 0) /* STORE CHARACTERS UNDER MASK */ D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0) D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0) @@ -696,8 +733,12 @@ /* STORE HALFWORD */ C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0) C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0) +/* STORE HALFWORD HIGH */ + C(0xe3c7, STHH, RXY_a, HW, r1_sr32, a2, 0, 0, st16, 0) /* STORE HALFWORD RELATIVE LONG */ C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0) +/* STORE HIGH */ + C(0xe3cb, STFH, RXY_a, HW, r1_sr32, a2, 0, 0, st32, 0) /* STORE ON CONDITION */ D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0) D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1) @@ -737,6 +778,9 @@ /* SUBTRACT HALFWORD */ C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32) C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32) +/* SUBTRACT HIGH */ + C(0xb9c9, SHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subs32) + C(0xb9d9, SHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subs32) /* SUBTRACT LOGICAL */ C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32) C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32) @@ -747,6 +791,9 @@ C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, sub, subu64) C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, sub, subu64) C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, sub, subu64) +/* SUBTRACT LOCICAL HIGH */ + C(0xb9cb, SLHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subu32) + C(0xb9db, SLHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subu32) /* SUBTRACT LOGICAL IMMEDIATE */ C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32) C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64) diff --git a/target-s390x/translate.c b/target-s390x/translate.c index 9e53c9812e..9b877148c6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -1482,6 +1482,30 @@ static ExitStatus op_bct32(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bcth(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int imm = get_field(s->fields, i2); + DisasCompare c; + TCGv_i64 t; + + c.cond = TCG_COND_NE; + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_shri_i64(t, regs[r1], 32); + tcg_gen_subi_i64(t, t, 1); + store_reg32h_i64(r1, t); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_const_i32(0); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, 1, imm, o->in2); +} + static ExitStatus op_bct64(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); @@ -4212,6 +4236,12 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_wout_r1_32 0 +static void wout_r1_32h(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg32h_i64(get_field(f, r1), o->out); +} +#define SPEC_wout_r1_32h 0 + static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) { int r1 = get_field(f, r1); @@ -4382,6 +4412,13 @@ static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in1_r2 0 +static void in1_r2_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in1, regs[get_field(f, r2)], 32); +} +#define SPEC_in1_r2_sr32 0 + static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r3)); @@ -4595,6 +4632,13 @@ static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_r3 0 +static void in2_r3_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in2, regs[get_field(f, r3)], 32); +} +#define SPEC_in2_r3_sr32 0 + static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); @@ -4609,6 +4653,13 @@ static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_r2_32u 0 +static void in2_r2_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in2, regs[get_field(f, r2)], 32); +} +#define SPEC_in2_r2_sr32 0 + static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_freg32_i64(get_field(f, r2)); From 4decd76d71d6972a59bf0a16d0dea0c83490d001 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:53 +0200 Subject: [PATCH 30/34] target-s390x: add a cpu_mmu_idx_to_asc function Use constants to define the MMU indexes, and add a function to do the reverse conversion of cpu_mmu_index. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/cpu.h | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h index adb9a84237..584e74b89a 100644 --- a/target-s390x/cpu.h +++ b/target-s390x/cpu.h @@ -302,15 +302,20 @@ static inline CPU_DoubleU *get_freg(CPUS390XState *cs, int nr) #define CR0_LOWPROT 0x0000000010000000ULL #define CR0_EDAT 0x0000000000800000ULL +/* MMU */ +#define MMU_PRIMARY_IDX 0 +#define MMU_SECONDARY_IDX 1 +#define MMU_HOME_IDX 2 + static inline int cpu_mmu_index (CPUS390XState *env) { switch (env->psw.mask & PSW_MASK_ASC) { case PSW_ASC_PRIMARY: - return 0; + return MMU_PRIMARY_IDX; case PSW_ASC_SECONDARY: - return 1; + return MMU_SECONDARY_IDX; case PSW_ASC_HOME: - return 2; + return MMU_HOME_IDX; case PSW_ASC_ACCREG: /* Fallthrough: access register mode is not yet supported */ default: @@ -318,6 +323,20 @@ static inline int cpu_mmu_index (CPUS390XState *env) } } +static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx) +{ + switch (mmu_idx) { + case MMU_PRIMARY_IDX: + return PSW_ASC_PRIMARY; + case MMU_SECONDARY_IDX: + return PSW_ASC_SECONDARY; + case MMU_HOME_IDX: + return PSW_ASC_HOME; + default: + abort(); + } +} + static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, target_ulong *cs_base, int *flags) { From c255ac601231e8c53007e10d640722ac58eb77cc Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:54 +0200 Subject: [PATCH 31/34] target-s390x: support non current ASC in s390_cpu_handle_mmu_fault s390_cpu_handle_mmu_fault currently looks at the current ASC mode defined in PSW mask instead of the MMU index. This prevent emulating easily instructions using a specific ASC mode. Fix that by using the MMU index converted back to ASC using the just added cpu_mmu_idx_to_asc function. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/helper.c b/target-s390x/helper.c index 6b47766494..90d273c098 100644 --- a/target-s390x/helper.c +++ b/target-s390x/helper.c @@ -112,7 +112,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, { S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; - uint64_t asc = env->psw.mask & PSW_MASK_ASC; + uint64_t asc = cpu_mmu_idx_to_asc(mmu_idx); target_ulong vaddr, raddr; int prot; From a3084e8055067b3fe8ed653a609021d2ab368564 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:55 +0200 Subject: [PATCH 32/34] target-s390x: use softmmu functions for mvcp/mvcs mvcp and mvcs helper get access to the physical memory by a call to mmu_translate for the virtual to real conversion and then using ldb_phys and stb_phys to physically access the data. In practice this is quite slow because it bypasses the QEMU softmmu TLB and because stb_phys calls try to invalidate the corresponding memory for each access. Instead use cpu_ldb_{primary,secondary} for the loads and cpu_stb_{primary,secondary} for the stores. Ideally this should be further optimized by a call to memcpy, but that already improves the boot time of a guest by a factor 1.8. Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/mem_helper.c | 55 +++++++++++++++------------------------ 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 30a2a6dfd5..04500ab06a 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -1015,59 +1015,46 @@ uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2) return cc; } -static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1, - uint64_t mode1, uint64_t a2, uint64_t mode2) +uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { - CPUState *cs = CPU(s390_env_get_cpu(env)); - target_ulong src, dest; - int flags, cc = 0, i; + int cc = 0, i; - if (!l) { - return 0; - } else if (l > 256) { + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + + if (l > 256) { /* max 256 */ l = 256; cc = 3; } - if (mmu_translate(env, a1, 1, mode1, &dest, &flags, true)) { - cpu_loop_exit(CPU(s390_env_get_cpu(env))); - } - dest |= a1 & ~TARGET_PAGE_MASK; - - if (mmu_translate(env, a2, 0, mode2, &src, &flags, true)) { - cpu_loop_exit(CPU(s390_env_get_cpu(env))); - } - src |= a2 & ~TARGET_PAGE_MASK; - /* XXX replace w/ memcpy */ for (i = 0; i < l; i++) { - /* XXX be more clever */ - if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || - (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { - mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2); - break; - } - stb_phys(cs->as, dest + i, ldub_phys(cs->as, src + i)); + cpu_stb_secondary(env, a1 + i, cpu_ldub_primary(env, a2 + i)); } return cc; } -uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) -{ - HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", - __func__, l, a1, a2); - - return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); -} - uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { + int cc = 0, i; + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", __func__, l, a1, a2); - return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); + if (l > 256) { + /* max 256 */ + l = 256; + cc = 3; + } + + /* XXX replace w/ memcpy */ + for (i = 0; i < l; i++) { + cpu_stb_primary(env, a1 + i, cpu_ldub_secondary(env, a2 + i)); + } + + return cc; } /* invalidate pte */ From 068593deea6cc61b06243a33c7fcfadb1650b654 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 3 Jun 2015 23:09:56 +0200 Subject: [PATCH 33/34] target-s390x: fix MVC instruction when areas overlap The MVC instruction and the memmove C funtion do not have the same semantic when memory areas overlap: MVC: When the operands overlap, the result is obtained as if the operands were processed one byte at a time and each result byte were stored immediately after fetching the necessary operand byte. memmove: Copying takes place as though the bytes in src are first copied into a temporary array that does not overlap src or dest, and the bytes are then copied from the temporary array to dest. The behaviour is therefore the same when the destination is at a lower address than the source, but not in the other case. This is actually a trick for propagating a value to an area. While the current code detects that and call memset in that case, it only does for 1-byte value. This trick can and is used for propagating two or more bytes to an area. In the softmmu case, the call to mvc_fast_memmove is correct as the above tests verify that source and destination are each within a page, and both in a different page. The part doing the move 8 bytes by 8 bytes is wrong and we need to check that if the source and destination overlap, they do with a distance of minimum 8 bytes before copying 8 bytes at a time. In the user code, we should check check that the destination is at a lower address than source or than the end of the source is at a lower address than the destination before calling memmove. In the opposite case we fallback to the same code as the softmmu one. Note that l represents (length - 1). Signed-off-by: Aurelien Jarno Reviewed-by: Richard Henderson Signed-off-by: Alexander Graf --- target-s390x/mem_helper.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c index 04500ab06a..b4e5d44011 100644 --- a/target-s390x/mem_helper.c +++ b/target-s390x/mem_helper.c @@ -213,21 +213,22 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) if (dest == (src + 1)) { memset(g2h(dest), cpu_ldub_data(env, src), l + 1); return; - } else { + /* mvc and memmove do not behave the same when areas overlap! */ + } else if ((dest < src) || (src + l < dest)) { memmove(g2h(dest), g2h(src), l + 1); return; } #endif /* handle the parts that fit into 8-byte loads/stores */ - if (dest != (src + 1)) { + if ((dest + 8 <= src) || (src + 8 <= dest)) { for (i = 0; i < l_64; i++) { cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x)); x += 8; } } - /* slow version crossing pages with byte accesses */ + /* slow version with byte accesses which always work */ for (i = x; i <= l; i++) { cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i)); } From 9814fed0afa73f5c37f04e02ec17c915a5d59303 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 4 Jun 2015 00:52:44 +0200 Subject: [PATCH 34/34] target-s390x: Only access allocated storage keys We allocate ram_size / PAGE_SIZE storage keys, so we need to make sure that we only access that many. Unfortunately the code can overrun this array by one, potentially overwriting unrelated memory. Fix it by limiting storage keys to their scope. Signed-off-by: Alexander Graf Reviewed-by: Aurelien Jarno --- target-s390x/mmu_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-s390x/mmu_helper.c b/target-s390x/mmu_helper.c index e8dcd0c18f..815ff42dde 100644 --- a/target-s390x/mmu_helper.c +++ b/target-s390x/mmu_helper.c @@ -358,7 +358,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, /* Convert real address -> absolute address */ *raddr = mmu_real2abs(env, *raddr); - if (*raddr <= ram_size) { + if (*raddr < ram_size) { sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE]; if (*flags & PAGE_READ) { *sk |= SK_R;