From f79f1ca4a20d4070179903bbaafc13f5f90b7873 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 18 May 2017 19:26:40 +0200 Subject: [PATCH 01/70] target/s390x: Add support for the TEST BLOCK instruction TEST BLOCK was likely once used to execute basic memory tests, but nowadays it's just a (slow) way to clear a page. Reviewed-by: Aurelien Jarno Reviewed-by: David Hildenbrand Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth Message-Id: <1495128400-23759-1-git-send-email-thuth@redhat.com> Signed-off-by: Richard Henderson --- target/s390x/cpu.h | 1 + target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 28 ++++++++++++++++++++++++++++ target/s390x/mmu_helper.c | 2 +- target/s390x/translate.c | 11 +++++++++++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index c74b4193ee..f463113116 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -1084,6 +1084,7 @@ struct sysib_322 { #define SIGP_ORDER_MASK 0x000000ff void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); +target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr); int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags, bool exc); int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 0b70770e4e..1fae19126e 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -102,6 +102,7 @@ DEF_HELPER_FLAGS_4(lctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(lctlg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32) +DEF_HELPER_FLAGS_2(testblock, TCG_CALL_NO_WG, i32, env, i64) DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 55a7c529b4..cac0f51ac6 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -918,6 +918,8 @@ /* STORE USING REAL ADDRESS */ C(0xb246, STURA, RRE, Z, r1_o, r2_o, 0, 0, stura, 0) C(0xb925, STURG, RRE, Z, r1_o, r2_o, 0, 0, sturg, 0) +/* TEST BLOCK */ + C(0xb22c, TB, RRE, Z, 0, r2_o, 0, 0, testblock, 0) /* TEST PROTECTION */ C(0xe501, TPROT, SSE, Z, la1, a2, 0, 0, tprot, 0) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index f6e5bcec5d..0c6a0d9612 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/address-spaces.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" @@ -973,6 +974,33 @@ void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) } } +uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) +{ + CPUState *cs = CPU(s390_env_get_cpu(env)); + uint64_t abs_addr; + int i; + + real_addr = fix_address(env, real_addr); + abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK; + if (!address_space_access_valid(&address_space_memory, abs_addr, + TARGET_PAGE_SIZE, true)) { + program_interrupt(env, PGM_ADDRESSING, 4); + return 1; + } + + /* Check low-address protection */ + if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) { + program_interrupt(env, PGM_PROTECTION, 4); + return 1; + } + + for (i = 0; i < TARGET_PAGE_SIZE; i += 8) { + stq_phys(cs->as, abs_addr + i, 0); + } + + return 0; +} + uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) { /* XXX implement */ diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index b11a02706c..31eb9efa9b 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -108,7 +108,7 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, * Translate real address to absolute (= physical) * address by taking care of the prefix mapping. */ -static target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr) +target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr) { if (raddr < 0x2000) { return raddr + env->psa; /* Map the lowcore. */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 628fb8685d..837d90cd07 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4062,6 +4062,16 @@ static ExitStatus op_tcxb(DisasContext *s, DisasOps *o) } #ifndef CONFIG_USER_ONLY + +static ExitStatus op_testblock(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + potential_page_fault(s); + gen_helper_testblock(cc_op, cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_tprot(DisasContext *s, DisasOps *o) { potential_page_fault(s); @@ -4069,6 +4079,7 @@ static ExitStatus op_tprot(DisasContext *s, DisasOps *o) set_cc_static(s); return NO_EXIT; } + #endif static ExitStatus op_tr(DisasContext *s, DisasOps *o) From 23cf9659b40449367e044ad95b42651537c29643 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 18 May 2017 12:10:53 -0700 Subject: [PATCH 02/70] target/s390x: Use cpu_loop_exit_restore for tlb_fill Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 0c6a0d9612..e3325a4f63 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -41,15 +41,9 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) { - int ret; - - ret = s390_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); + int ret = s390_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx); if (unlikely(ret != 0)) { - if (likely(retaddr)) { - /* now we have a real cpu fault */ - cpu_restore_state(cs, retaddr); - } - cpu_loop_exit(cs); + cpu_loop_exit_restore(cs, retaddr); } } From a5cfc2235b10dca0d2033ec3523c272268836b02 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:39:39 -0700 Subject: [PATCH 03/70] target/s390x: Move helper_ex to end of file This will avoid needing forward declarations in following patches. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 161 +++++++++++++++++++------------------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index e3325a4f63..90b62fab16 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -436,86 +436,6 @@ static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, return cc; } -/* execute instruction - this instruction executes an insn modified with the contents of r1 - it does not change the executed instruction in memory - it does not change the program counter - in other words: tricky... - currently implemented by interpreting the cases it is most commonly used in -*/ -uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, - uint64_t addr, uint64_t ret) -{ - S390CPU *cpu = s390_env_get_cpu(env); - uint16_t insn = cpu_lduw_code(env, addr); - - HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, - insn); - if ((insn & 0xf0ff) == 0xd000) { - uint32_t l, insn2, b1, b2, d1, d2; - - l = v1 & 0xff; - insn2 = cpu_ldl_code(env, addr + 2); - b1 = (insn2 >> 28) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d1 = (insn2 >> 16) & 0xfff; - d2 = insn2 & 0xfff; - switch (insn & 0xf00) { - case 0x200: - helper_mvc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - case 0x400: - cc = helper_nc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - case 0x500: - cc = helper_clc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - case 0x600: - cc = helper_oc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - case 0x700: - cc = helper_xc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - case 0xc00: - helper_tr(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - case 0xd00: - cc = helper_trt(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; - default: - goto abort; - } - } else if ((insn & 0xff00) == 0x0a00) { - /* supervisor call */ - HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); - env->psw.addr = ret - 4; - env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilen = 4; - helper_exception(env, EXCP_SVC); - } else if ((insn & 0xff00) == 0xbf00) { - uint32_t insn2, r1, r3, b2, d2; - - insn2 = cpu_ldl_code(env, addr + 2); - r1 = (insn2 >> 20) & 0xf; - r3 = (insn2 >> 16) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d2 = insn2 & 0xfff; - cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); - } else { - abort: - cpu_abort(CPU(cpu), "EXECUTE on instruction prefix 0x%x not implemented\n", - insn); - } - return cc; -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { @@ -1262,3 +1182,84 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) return ret; } #endif + +/* execute instruction + this instruction executes an insn modified with the contents of r1 + it does not change the executed instruction in memory + it does not change the program counter + in other words: tricky... + currently implemented by interpreting the cases it is most commonly used. +*/ +uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, + uint64_t addr, uint64_t ret) +{ + S390CPU *cpu = s390_env_get_cpu(env); + uint16_t insn = cpu_lduw_code(env, addr); + + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, + insn); + if ((insn & 0xf0ff) == 0xd000) { + uint32_t l, insn2, b1, b2, d1, d2; + + l = v1 & 0xff; + insn2 = cpu_ldl_code(env, addr + 2); + b1 = (insn2 >> 28) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d1 = (insn2 >> 16) & 0xfff; + d2 = insn2 & 0xfff; + switch (insn & 0xf00) { + case 0x200: + helper_mvc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0x400: + cc = helper_nc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0x500: + cc = helper_clc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0x600: + cc = helper_oc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0x700: + cc = helper_xc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0xc00: + helper_tr(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + case 0xd00: + cc = helper_trt(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2)); + break; + default: + goto abort; + } + } else if ((insn & 0xff00) == 0x0a00) { + /* supervisor call */ + HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); + env->psw.addr = ret - 4; + env->int_svc_code = (insn | v1) & 0xff; + env->int_svc_ilen = 4; + helper_exception(env, EXCP_SVC); + } else if ((insn & 0xff00) == 0xbf00) { + uint32_t insn2, r1, r3, b2, d2; + + insn2 = cpu_ldl_code(env, addr + 2); + r1 = (insn2 >> 20) & 0xf; + r3 = (insn2 >> 16) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d2 = insn2 & 0xfff; + cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); + } else { + abort: + cpu_abort(CPU(cpu), + "EXECUTE on instruction prefix 0x%x not implemented\n", + insn); + } + return cc; +} From 349d078a269cdfcc26e2e84fa99127080eff0d12 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 09:41:29 -0700 Subject: [PATCH 04/70] target/s390x: Use unwind data for helper_nc Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 31 ++++++++++++++++++------------- target/s390x/translate.c | 1 - 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 90b62fab16..7d6133b7cf 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -119,23 +119,28 @@ static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src, } /* and on array */ -uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest, - uint64_t src) +static uint32_t do_helper_nc(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src, uintptr_t ra) { - int i; - unsigned char x; - uint32_t cc = 0; + uint32_t i; + uint8_t c = 0; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); + for (i = 0; i <= l; i++) { - x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i); - if (x) { - cc = 1; - } - cpu_stb_data(env, dest + i, x); + uint8_t x = cpu_ldub_data_ra(env, src + i, ra); + x &= cpu_ldub_data_ra(env, dest + i, ra); + c |= x; + cpu_stb_data_ra(env, dest + i, x, ra); } - return cc; + return c != 0; +} + +uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + return do_helper_nc(env, l, dest, src, GETPC()); } /* xor on array */ @@ -1213,8 +1218,8 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, get_address(env, 0, b2, d2)); break; case 0x400: - cc = helper_nc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); + cc = do_helper_nc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); break; case 0x500: cc = helper_clc(env, l, get_address(env, 0, b1, d1), diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 837d90cd07..afa2c6b341 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3048,7 +3048,6 @@ static ExitStatus op_nabsf128(DisasContext *s, DisasOps *o) static ExitStatus op_nc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); - potential_page_fault(s); gen_helper_nc(cc_op, cpu_env, l, o->addr1, o->in2); tcg_temp_free_i32(l); set_cc_static(s); From 6fc2606e5843456b3f053335ff692997aa937f65 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 09:42:18 -0700 Subject: [PATCH 05/70] target/s390x: Use unwind data for helper_oc Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 31 ++++++++++++++++++------------- target/s390x/translate.c | 1 - 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 7d6133b7cf..b4b50d1fab 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -171,23 +171,28 @@ uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest, } /* or on array */ -uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, - uint64_t src) +static uint32_t do_helper_oc(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src, uintptr_t ra) { - int i; - unsigned char x; - uint32_t cc = 0; + uint32_t i; + uint8_t c = 0; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); + for (i = 0; i <= l; i++) { - x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i); - if (x) { - cc = 1; - } - cpu_stb_data(env, dest + i, x); + uint8_t x = cpu_ldub_data_ra(env, src + i, ra); + x |= cpu_ldub_data_ra(env, dest + i, ra); + c |= x; + cpu_stb_data_ra(env, dest + i, x, ra); } - return cc; + return c != 0; +} + +uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + return do_helper_oc(env, l, dest, src, GETPC()); } /* memmove */ @@ -1226,8 +1231,8 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, get_address(env, 0, b2, d2)); break; case 0x600: - cc = helper_oc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); + cc = do_helper_oc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); break; case 0x700: cc = helper_xc(env, l, get_address(env, 0, b1, d1), diff --git a/target/s390x/translate.c b/target/s390x/translate.c index afa2c6b341..b1c1047525 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3082,7 +3082,6 @@ static ExitStatus op_negf128(DisasContext *s, DisasOps *o) static ExitStatus op_oc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); - potential_page_fault(s); gen_helper_oc(cc_op, cpu_env, l, o->addr1, o->in2); tcg_temp_free_i32(l); set_cc_static(s); From 9c009e88e362dea1ca5791d31f7dbc72c7f61344 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 09:53:31 -0700 Subject: [PATCH 06/70] target/s390x: Use unwind data for helper_xc Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 44 +++++++++++++++++++++------------------ target/s390x/translate.c | 1 - 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b4b50d1fab..b71437a106 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -57,7 +57,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, #endif /* Reduce the length so that addr + len doesn't cross a page boundary. */ -static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr) +static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr) { #ifndef CONFIG_USER_ONLY if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) { @@ -68,7 +68,7 @@ static inline uint64_t adj_len_to_page(uint64_t len, uint64_t addr) } static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, - uint32_t l) + uint32_t l, uintptr_t ra) { int mmu_idx = cpu_mmu_index(env, false); @@ -76,14 +76,14 @@ static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, void *p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx); if (p) { /* Access to the whole page in write mode granted. */ - int l_adj = adj_len_to_page(l, dest); + uint32_t l_adj = adj_len_to_page(l, dest); memset(p, byte, l_adj); dest += l_adj; l -= l_adj; } else { /* We failed to get access to the whole page. The next write access will likely fill the QEMU TLB for the next iteration. */ - cpu_stb_data(env, dest, byte); + cpu_stb_data_ra(env, dest, byte, ra); dest++; l--; } @@ -100,7 +100,7 @@ static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src, void *dest_p = tlb_vaddr_to_host(env, dest, MMU_DATA_STORE, mmu_idx); if (src_p && dest_p) { /* Access to both whole pages granted. */ - int l_adj = adj_len_to_page(l, src); + uint32_t l_adj = adj_len_to_page(l, src); l_adj = adj_len_to_page(l_adj, dest); memmove(dest_p, src_p, l_adj); src += l_adj; @@ -144,30 +144,34 @@ uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest, } /* xor on array */ -uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest, - uint64_t src) +static uint32_t do_helper_xc(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src, uintptr_t ra) { - int i; - unsigned char x; - uint32_t cc = 0; + uint32_t i; + uint8_t c = 0; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); /* xor with itself is the same as memset(0) */ if (src == dest) { - fast_memset(env, dest, 0, l + 1); + fast_memset(env, dest, 0, l + 1, ra); return 0; } for (i = 0; i <= l; i++) { - x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i); - if (x) { - cc = 1; - } - cpu_stb_data(env, dest + i, x); + uint8_t x = cpu_ldub_data_ra(env, src + i, ra); + x ^= cpu_ldub_data_ra(env, dest + i, ra); + c |= x; + cpu_stb_data_ra(env, dest + i, x, ra); } - return cc; + return c != 0; +} + +uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src) +{ + return do_helper_xc(env, l, dest, src, GETPC()); } /* or on array */ @@ -206,7 +210,7 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) /* mvc with source pointing to the byte after the destination is the same as memset with the first source byte */ if (dest == (src + 1)) { - fast_memset(env, dest, cpu_ldub_data(env, src), l + 1); + fast_memset(env, dest, cpu_ldub_data(env, src), l + 1, 0); return; } @@ -1235,8 +1239,8 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, get_address(env, 0, b2, d2), 0); break; case 0x700: - cc = helper_xc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); + cc = do_helper_xc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); break; case 0xc00: helper_tr(env, l, get_address(env, 0, b1, d1), diff --git a/target/s390x/translate.c b/target/s390x/translate.c index b1c1047525..2c263085d7 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4165,7 +4165,6 @@ static ExitStatus op_xc(DisasContext *s, DisasOps *o) /* But in general we'll defer to a helper. */ o->in2 = get_address(s, 0, b2, d2); t32 = tcg_const_i32(l); - potential_page_fault(s); gen_helper_xc(cc_op, cpu_env, t32, o->addr1, o->in2); tcg_temp_free_i32(t32); set_cc_static(s); From d3696812e34a97784bd5405f38388a9f40126010 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 09:59:53 -0700 Subject: [PATCH 07/70] target/s390x: Use unwind data for helper_mvc Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 30 ++++++++++++++++++------------ target/s390x/translate.c | 1 - 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b71437a106..78a9ac11f1 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -91,7 +91,7 @@ static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, } static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src, - uint32_t l) + uint32_t l, uintptr_t ra) { int mmu_idx = cpu_mmu_index(env, false); @@ -110,7 +110,7 @@ static void fast_memmove(CPUS390XState *env, uint64_t dest, uint64_t src, /* We failed to get access to one or both whole pages. The next read or write access will likely fill the QEMU TLB for the next iteration. */ - cpu_stb_data(env, dest, cpu_ldub_data(env, src)); + cpu_stb_data_ra(env, dest, cpu_ldub_data_ra(env, src, ra), ra); src++; dest++; l--; @@ -200,32 +200,38 @@ uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, } /* memmove */ -void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +static void do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src, uintptr_t ra) { - int i = 0; + uint32_t i; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); /* mvc with source pointing to the byte after the destination is the same as memset with the first source byte */ - if (dest == (src + 1)) { - fast_memset(env, dest, cpu_ldub_data(env, src), l + 1, 0); + if (dest == src + 1) { + fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra); return; } /* mvc and memmove do not behave the same when areas overlap! */ - if ((dest < src) || (src + l < dest)) { - fast_memmove(env, dest, src, l + 1); + if (dest < src || src + l < dest) { + fast_memmove(env, dest, src, l + 1, ra); return; } /* slow version with byte accesses which always work */ for (i = 0; i <= l; i++) { - cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i)); + cpu_stb_data_ra(env, dest + i, cpu_ldub_data_ra(env, src + i, ra), ra); } } +void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +{ + do_helper_mvc(env, l, dest, src, GETPC()); +} + /* compare unsigned byte arrays */ uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) { @@ -388,7 +394,7 @@ void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) { /* XXX missing r0 handling */ env->cc_op = 0; - fast_memmove(env, r1, r2, TARGET_PAGE_SIZE); + fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, 0); } /* string copy (c is string terminator) */ @@ -1223,8 +1229,8 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, d2 = insn2 & 0xfff; switch (insn & 0xf00) { case 0x200: - helper_mvc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); + do_helper_mvc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); break; case 0x400: cc = do_helper_nc(env, l, get_address(env, 0, b1, d1), diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 2c263085d7..a9502cc850 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2871,7 +2871,6 @@ static ExitStatus op_movx(DisasContext *s, DisasOps *o) static ExitStatus op_mvc(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); - potential_page_fault(s); gen_helper_mvc(cpu_env, l, o->addr1, o->in2); tcg_temp_free_i32(l); return NO_EXIT; From e79f56f4d636354be1f42b8a862632cac9101c23 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 10:06:23 -0700 Subject: [PATCH 08/70] target/s390x: Use unwind data for helper_clc Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 29 +++++++++++++++++------------ target/s390x/translate.c | 1 - 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 78a9ac11f1..50689bb612 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -233,32 +233,37 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) } /* compare unsigned byte arrays */ -uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) +static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1, + uint64_t s2, uintptr_t ra) { - int i; - unsigned char x, y; - uint32_t cc; + uint32_t i; + uint32_t cc = 0; HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", __func__, l, s1, s2); + for (i = 0; i <= l; i++) { - x = cpu_ldub_data(env, s1 + i); - y = cpu_ldub_data(env, s2 + i); + uint8_t x = cpu_ldub_data_ra(env, s1 + i, ra); + uint8_t y = cpu_ldub_data_ra(env, s2 + i, ra); HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); if (x < y) { cc = 1; - goto done; + break; } else if (x > y) { cc = 2; - goto done; + break; } } - cc = 0; - done: + HELPER_LOG("\n"); return cc; } +uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) +{ + return do_helper_clc(env, l, s1, s2, GETPC()); +} + /* compare logical under mask */ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, uint64_t addr) @@ -1237,8 +1242,8 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, get_address(env, 0, b2, d2), 0); break; case 0x500: - cc = helper_clc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); + cc = do_helper_clc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); break; case 0x600: cc = do_helper_oc(env, l, get_address(env, 0, b1, d1), diff --git a/target/s390x/translate.c b/target/s390x/translate.c index a9502cc850..c47b8187f9 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1906,7 +1906,6 @@ static ExitStatus op_clc(DisasContext *s, DisasOps *o) tcg_gen_qemu_ld64(cc_dst, o->in2, get_mem_index(s)); break; default: - potential_page_fault(s); vl = tcg_const_i32(l); gen_helper_clc(cc_op, cpu_env, vl, o->addr1, o->in2); tcg_temp_free_i32(vl); From 868b5cbd919d60da827f14609013c34948f0a425 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 10:10:58 -0700 Subject: [PATCH 09/70] target/s390x: Use unwind data for helper_clm Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 11 ++++++----- target/s390x/translate.c | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 50689bb612..3e75cae5af 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -268,16 +268,16 @@ uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, uint64_t addr) { - uint8_t r, d; - uint32_t cc; + uintptr_t ra = GETPC(); + uint32_t cc = 0; HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, mask, addr); - cc = 0; + while (mask) { if (mask & 8) { - d = cpu_ldub_data(env, addr); - r = (r1 & 0xff000000UL) >> 24; + uint8_t d = cpu_ldub_data_ra(env, addr, ra); + uint8_t r = extract32(r1, 24, 8); HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, addr); if (r < d) { @@ -292,6 +292,7 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, mask = (mask << 1) & 0xf; r1 <<= 8; } + HELPER_LOG("\n"); return cc; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index c47b8187f9..d4c5fa3123 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1933,7 +1933,6 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o) TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_extrl_i64_i32(t1, o->in1); - potential_page_fault(s); gen_helper_clm(cc_op, cpu_env, t1, m3, o->in2); set_cc_static(s); tcg_temp_free_i32(t1); From 4663e82244c550c8eeaa605f8fb6556cdc2fcc8f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 10:13:22 -0700 Subject: [PATCH 10/70] target/s390x: Use unwind data for helper_srst Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 3 ++- target/s390x/translate.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 3e75cae5af..33d83e52a5 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -327,6 +327,7 @@ static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, uint64_t str) { + uintptr_t ra = GETPC(); uint32_t len; uint8_t v, c = r0; @@ -344,7 +345,7 @@ uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, env->cc_op = 2; return end; } - v = cpu_ldub_data(env, str + len); + v = cpu_ldub_data_ra(env, str + len, ra); if (v == c) { /* Character found. Set R1 to the location; R2 is unmodified. */ env->cc_op = 1; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index d4c5fa3123..9fc5b3101f 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3977,7 +3977,6 @@ static ExitStatus op_stmh(DisasContext *s, DisasOps *o) static ExitStatus op_srst(DisasContext *s, DisasOps *o) { - potential_page_fault(s); gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2); set_cc_static(s); return_low128(o->in2); From 3cc8ca3dab6e1c46e37999bc4719f4eb950be53c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 10:16:24 -0700 Subject: [PATCH 11/70] target/s390x: Use unwind data for helper_clst Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 5 +++-- target/s390x/translate.c | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 33d83e52a5..af2801e76a 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -362,6 +362,7 @@ uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, /* unsigned string compare (c is string terminator) */ uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) { + uintptr_t ra = GETPC(); uint32_t len; c = c & 0xff; @@ -371,8 +372,8 @@ uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) /* 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. */ for (len = 0; len < 0x2000; ++len) { - uint8_t v1 = cpu_ldub_data(env, s1 + len); - uint8_t v2 = cpu_ldub_data(env, s2 + len); + uint8_t v1 = cpu_ldub_data_ra(env, s1 + len, ra); + uint8_t v2 = cpu_ldub_data_ra(env, s2 + len, ra); if (v1 == v2) { if (v1 == c) { /* Equal. CC=0, and don't advance the registers. */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 9fc5b3101f..b87755e69d 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1942,7 +1942,6 @@ static ExitStatus op_clm(DisasContext *s, DisasOps *o) static ExitStatus op_clst(DisasContext *s, DisasOps *o) { - potential_page_fault(s); gen_helper_clst(o->in1, cpu_env, regs[0], o->in1, o->in2); set_cc_static(s); return_low128(o->in2); From 7cf96fca4caf2f387b9ba4d74b04d6748d3c3207 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:15:25 -0700 Subject: [PATCH 12/70] target/s390x: Use unwind data for helper_mvpg Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/mem_helper.c | 9 +++++---- target/s390x/translate.c | 3 +-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 1fae19126e..ea35834fc6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -12,7 +12,7 @@ DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) -DEF_HELPER_4(mvpg, void, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, 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_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index af2801e76a..1c36a47ae1 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -398,11 +398,12 @@ uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) } /* move page */ -void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) +uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) { - /* XXX missing r0 handling */ - env->cc_op = 0; - fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, 0); + /* ??? missing r0 handling, which includes access keys, but more + importantly optional suppression of the exception! */ + fast_memmove(env, r1, r2, TARGET_PAGE_SIZE, GETPC()); + return 0; /* data moved */ } /* string copy (c is string terminator) */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index b87755e69d..ae29889278 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2921,8 +2921,7 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) { - potential_page_fault(s); - gen_helper_mvpg(cpu_env, regs[0], o->in1, o->in2); + gen_helper_mvpg(cc_op, cpu_env, regs[0], o->in1, o->in2); set_cc_static(s); return NO_EXIT; } From 08a4cb793fdf5aa59ee4964f61afbe13d4fa82f1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:17:50 -0700 Subject: [PATCH 13/70] target/s390x: Use unwind data for helper_mvst Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 5 +++-- target/s390x/translate.c | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 1c36a47ae1..e4bfc6e48a 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -409,6 +409,7 @@ uint32_t HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) /* string copy (c is string terminator) */ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) { + uintptr_t ra = GETPC(); uint32_t len; c = c & 0xff; @@ -418,8 +419,8 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t 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. */ for (len = 0; len < 0x2000; ++len) { - uint8_t v = cpu_ldub_data(env, s + len); - cpu_stb_data(env, d + len, v); + 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; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index ae29889278..d41a0fdce6 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2928,7 +2928,6 @@ static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) static ExitStatus op_mvst(DisasContext *s, DisasOps *o) { - potential_page_fault(s); gen_helper_mvst(o->in1, cpu_env, regs[0], o->in1, o->in2); set_cc_static(s); return_low128(o->in2); From 9393c020bfd8581af8263c88d6e271950d52cb05 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:20:48 -0700 Subject: [PATCH 14/70] target/s390x: Use unwind data for helper_lam Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 3 ++- target/s390x/translate.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index e4bfc6e48a..88e817a432 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -469,10 +469,11 @@ static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { + uintptr_t ra = GETPC(); int i; for (i = r1;; i = (i + 1) % 16) { - env->aregs[i] = cpu_ldl_data(env, a2); + env->aregs[i] = cpu_ldl_data_ra(env, a2, ra); a2 += 4; if (i == r3) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index d41a0fdce6..16477fc094 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2626,7 +2626,6 @@ static ExitStatus op_lam(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - potential_page_fault(s); gen_helper_lam(cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From 44cf6c2e4bf80eef647f3a05bd6ff13df69a9c7f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:23:15 -0700 Subject: [PATCH 15/70] target/s390x: Use unwind data for helper_stam Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 3 ++- target/s390x/translate.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 88e817a432..2acc984f85 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -485,10 +485,11 @@ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) /* store access registers r1 to r3 in memory at a2 */ void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { + uintptr_t ra = GETPC(); int i; for (i = r1;; i = (i + 1) % 16) { - cpu_stl_data(env, a2, env->aregs[i]); + cpu_stl_data_ra(env, a2, env->aregs[i], ra); a2 += 4; if (i == r3) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 16477fc094..4ae949ad99 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3867,7 +3867,6 @@ static ExitStatus op_stam(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - potential_page_fault(s); gen_helper_stam(cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From 7390fb79fdff5e697962ed001ee418a9cd553585 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:26:27 -0700 Subject: [PATCH 16/70] target/s390x: Use unwind data for helper_mvcl Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 7 ++++--- target/s390x/translate.c | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 2acc984f85..49cfc9baaf 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -501,6 +501,7 @@ void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) /* move long */ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) { + uintptr_t ra = GETPC(); uint64_t destlen = env->regs[r1 + 1] & 0xffffff; uint64_t dest = get_address_31fix(env, r1); uint64_t srclen = env->regs[r2 + 1] & 0xffffff; @@ -522,12 +523,12 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) } for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = cpu_ldub_data(env, src); - cpu_stb_data(env, dest, v); + v = cpu_ldub_data_ra(env, src, ra); + cpu_stb_data_ra(env, dest, v, ra); } for (; destlen; dest++, destlen--) { - cpu_stb_data(env, dest, pad); + cpu_stb_data_ra(env, dest, pad, ra); } env->regs[r1 + 1] = destlen; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 4ae949ad99..e3c5ba109f 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2876,7 +2876,6 @@ static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); - potential_page_fault(s); gen_helper_mvcl(cc_op, cpu_env, r1, r2); tcg_temp_free_i32(r1); tcg_temp_free_i32(r2); From 453e4c077de2896ac2417f1fa7a9e182e7211819 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:28:30 -0700 Subject: [PATCH 17/70] target/s390x: Use unwind data for helper_mvcle Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 7 ++++--- target/s390x/translate.c | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 49cfc9baaf..8a095ad428 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -544,6 +544,7 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { + uintptr_t ra = GETPC(); uint64_t destlen = env->regs[r1 + 1]; uint64_t dest = env->regs[r1]; uint64_t srclen = env->regs[r3 + 1]; @@ -572,12 +573,12 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = cpu_ldub_data(env, src); - cpu_stb_data(env, dest, v); + v = cpu_ldub_data_ra(env, src, ra); + cpu_stb_data_ra(env, dest, v, ra); } for (; destlen; dest++, destlen--) { - cpu_stb_data(env, dest, pad); + cpu_stb_data_ra(env, dest, pad, ra); } env->regs[r1 + 1] = destlen; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index e3c5ba109f..eaa3adcc78 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2887,7 +2887,6 @@ static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - potential_page_fault(s); gen_helper_mvcle(cc_op, cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From 4546137957c250278fbb94f6fb3bce3de22788bc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:30:39 -0700 Subject: [PATCH 18/70] target/s390x: Use unwind data for helper_clcle Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 6 +++--- target/s390x/translate.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 8a095ad428..f5a30448fa 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -595,12 +595,12 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { + uintptr_t ra = GETPC(); uint64_t destlen = env->regs[r1 + 1]; uint64_t dest = get_address_31fix(env, r1); uint64_t srclen = env->regs[r3 + 1]; uint64_t src = get_address_31fix(env, r3); uint8_t pad = a2 & 0xff; - uint8_t v1 = 0, v2 = 0; uint32_t cc = 0; if (!(destlen || srclen)) { @@ -612,8 +612,8 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } for (; destlen || srclen; src++, dest++, destlen--, srclen--) { - v1 = srclen ? cpu_ldub_data(env, src) : pad; - v2 = destlen ? cpu_ldub_data(env, dest) : pad; + uint8_t v1 = srclen ? cpu_ldub_data_ra(env, src, ra) : pad; + uint8_t v2 = destlen ? cpu_ldub_data_ra(env, dest, ra) : pad; if (v1 != v2) { cc = (v1 < v2) ? 1 : 2; break; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index eaa3adcc78..600b76d2a1 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1920,7 +1920,6 @@ static ExitStatus op_clcle(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - potential_page_fault(s); gen_helper_clcle(cc_op, cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From 498644e99f3c3aa41cf563a958b19a683cc18336 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:34:43 -0700 Subject: [PATCH 19/70] target/s390x: Use unwind data for helper_cksm Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 11 ++++++----- target/s390x/translate.c | 1 - 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index f5a30448fa..d4ee364e4d 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -633,6 +633,7 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, uint64_t src, uint64_t src_len) { + uintptr_t ra = GETPC(); uint64_t max_len, len; uint64_t cksm = (uint32_t)r1; @@ -642,21 +643,21 @@ uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, /* Process full words as available. */ for (len = 0; len + 4 <= max_len; len += 4, src += 4) { - cksm += (uint32_t)cpu_ldl_data(env, src); + cksm += (uint32_t)cpu_ldl_data_ra(env, src, ra); } switch (max_len - len) { case 1: - cksm += cpu_ldub_data(env, src) << 24; + cksm += cpu_ldub_data_ra(env, src, ra) << 24; len += 1; break; case 2: - cksm += cpu_lduw_data(env, src) << 16; + cksm += cpu_lduw_data_ra(env, src, ra) << 16; len += 2; break; case 3: - cksm += cpu_lduw_data(env, src) << 16; - cksm += cpu_ldub_data(env, src + 2) << 8; + cksm += cpu_lduw_data_ra(env, src, ra) << 16; + cksm += cpu_ldub_data_ra(env, src + 2, ra) << 8; len += 3; break; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 600b76d2a1..40965ea5a4 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1871,7 +1871,6 @@ static ExitStatus op_cksm(DisasContext *s, DisasOps *o) int r2 = get_field(s->fields, r2); TCGv_i64 len = tcg_temp_new_i64(); - potential_page_fault(s); gen_helper_cksm(len, cpu_env, o->in1, o->in2, regs[r2 + 1]); set_cc_static(s); return_low128(o->out); From 84e1b98ba6444e69aeb989c38b3fd4e457ad31d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:37:55 -0700 Subject: [PATCH 20/70] target/s390x: Use unwind data for helper_unpk Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 9 +++++---- target/s390x/translate.c | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index d4ee364e4d..0701e10b00 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -679,6 +679,7 @@ uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) { + uintptr_t ra = GETPC(); int len_dest = len >> 4; int len_src = len & 0xf; uint8_t b; @@ -688,8 +689,8 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, src += len_src; /* last byte is special, it only flips the nibbles */ - b = cpu_ldub_data(env, src); - cpu_stb_data(env, dest, (b << 4) | (b >> 4)); + b = cpu_ldub_data_ra(env, src, ra); + cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra); src--; len_src--; @@ -699,7 +700,7 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, uint8_t cur_byte = 0; if (len_src > 0) { - cur_byte = cpu_ldub_data(env, src); + cur_byte = cpu_ldub_data_ra(env, src, ra); } len_dest--; @@ -718,7 +719,7 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, /* zone bits */ cur_byte |= 0xf0; - cpu_stb_data(env, dest, cur_byte); + cpu_stb_data_ra(env, dest, cur_byte, ra); } } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 40965ea5a4..10262f5ad8 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4099,7 +4099,6 @@ static ExitStatus op_trt(DisasContext *s, DisasOps *o) static ExitStatus op_unpk(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); - potential_page_fault(s); gen_helper_unpk(cpu_env, l, o->addr1, o->in2); tcg_temp_free_i32(l); return NO_EXIT; From 981a8ea0c549df539962bf8c6253f73dde3cf1cc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:43:08 -0700 Subject: [PATCH 21/70] target/s390x: Use unwind data for helper_tr Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 27 ++++++++++++++++----------- target/s390x/translate.c | 1 - 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 0701e10b00..b37a963bc5 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -723,17 +723,22 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, } } +static void do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans, uintptr_t ra) +{ + uint32_t i; + + for (i = 0; i <= len; i++) { + uint8_t byte = cpu_ldub_data_ra(env, array + i, ra); + uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra); + cpu_stb_data_ra(env, array + i, new_byte, ra); + } +} + void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, uint64_t trans) { - int i; - - for (i = 0; i <= len; i++) { - uint8_t byte = cpu_ldub_data(env, array + i); - uint8_t new_byte = cpu_ldub_data(env, trans + byte); - - cpu_stb_data(env, array + i, new_byte); - } + return do_helper_tr(env, len, array, trans, GETPC()); } uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, @@ -1265,9 +1270,9 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, get_address(env, 0, b2, d2), 0); break; case 0xc00: - helper_tr(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); - break; + do_helper_tr(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + return cc; case 0xd00: cc = helper_trt(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2)); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 10262f5ad8..e4da94d7c3 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4070,7 +4070,6 @@ static ExitStatus op_tprot(DisasContext *s, DisasOps *o) static ExitStatus op_tr(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); - potential_page_fault(s); gen_helper_tr(cpu_env, l, o->addr1, o->in2); tcg_temp_free_i32(l); set_cc_static(s); From d46cd62ff80708364b87d010a55655a48ca9f0bb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 19 May 2017 11:46:25 -0700 Subject: [PATCH 22/70] target/s390x: Use unwind data for helper_tre Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 15 ++++++++------- target/s390x/translate.c | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b37a963bc5..fd6dbf7702 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -744,9 +744,11 @@ 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) { + uintptr_t ra = GETPC(); uint8_t end = env->regs[0] & 0xff; uint64_t l = len; uint64_t i; + uint32_t cc = 0; if (!(env->psw.mask & PSW_MASK_64)) { array &= 0x7fffffff; @@ -757,25 +759,24 @@ uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, 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; + cc = 3; } for (i = 0; i < l; i++) { uint8_t byte, new_byte; - byte = cpu_ldub_data(env, array + i); + byte = cpu_ldub_data_ra(env, array + i, ra); if (byte == end) { - env->cc_op = 1; + cc = 1; break; } - new_byte = cpu_ldub_data(env, trans + byte); - cpu_stb_data(env, array + i, new_byte); + new_byte = cpu_ldub_data_ra(env, trans + byte, ra); + cpu_stb_data_ra(env, array + i, new_byte, ra); } + env->cc_op = cc; env->retxl = len - i; return array + i; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index e4da94d7c3..d42896f703 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4078,7 +4078,6 @@ static ExitStatus op_tr(DisasContext *s, DisasOps *o) 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); From 2c7e5f8c25fa176a9cabf2ff8d46ee4cdca0270d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 11:59:43 -0700 Subject: [PATCH 23/70] target/s390x: Use unwind data for helper_trt Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 28 ++++++++++++++++------------ target/s390x/translate.c | 1 - 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index fd6dbf7702..ff127776e2 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -781,25 +781,29 @@ uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, return array + i; } -uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array, - uint64_t trans) +static uint32_t do_helper_trt(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans, uintptr_t ra) { - uint32_t cc = 0; - int i; + uint32_t 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); + uint8_t byte = cpu_ldub_data_ra(env, array + i, ra); + uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra); if (sbyte != 0) { env->regs[1] = array + i; - env->regs[2] = (env->regs[2] & ~0xff) | sbyte; - cc = (i == len) ? 2 : 1; - break; + env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte); + return (i == len) ? 2 : 1; } } - return cc; + return 0; +} + +uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans) +{ + return do_helper_trt(env, len, array, trans, GETPC()); } void HELPER(cdsg)(CPUS390XState *env, uint64_t addr, @@ -1275,8 +1279,8 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, get_address(env, 0, b2, d2), 0); return cc; case 0xd00: - cc = helper_trt(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2)); + cc = do_helper_trt(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); break; default: goto abort; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index d42896f703..c95adcde0f 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4087,7 +4087,6 @@ static ExitStatus op_tre(DisasContext *s, DisasOps *o) 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); From 97ae2149aff5148d20a4bf91ba667b0084047376 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 12:14:58 -0700 Subject: [PATCH 24/70] target/s390x: Use unwind data for helper_lctlg Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 8 ++++---- target/s390x/translate.c | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index ff127776e2..68e3817039 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -848,20 +848,20 @@ void HELPER(cdsg)(CPUS390XState *env, uint64_t addr, #if !defined(CONFIG_USER_ONLY) void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { + uintptr_t ra = GETPC(); S390CPU *cpu = s390_env_get_cpu(env); bool PERchanged = false; - int i; uint64_t src = a2; - uint64_t val; + uint32_t i; for (i = r1;; i = (i + 1) % 16) { - val = cpu_ldq_data(env, src); + uint64_t val = cpu_ldq_data_ra(env, src, ra); if (env->cregs[i] != val && i >= 9 && i <= 11) { PERchanged = true; } env->cregs[i] = val; HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", - i, src, env->cregs[i]); + i, src, val); src += sizeof(uint64_t); if (i == r3) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index c95adcde0f..2386c418f8 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2557,7 +2557,6 @@ static ExitStatus op_lctlg(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); check_privileged(s); - potential_page_fault(s); gen_helper_lctlg(cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From 1b642a732cc777d2346e17c2957b13e787015d5f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 12:18:42 -0700 Subject: [PATCH 25/70] target/s390x: Use unwind data for helper_lctl Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 9 +++++---- target/s390x/translate.c | 1 - 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 68e3817039..614cdb2643 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -878,18 +878,19 @@ void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { + uintptr_t ra = GETPC(); S390CPU *cpu = s390_env_get_cpu(env); bool PERchanged = false; - int i; uint64_t src = a2; - uint32_t val; + uint32_t i; for (i = r1;; i = (i + 1) % 16) { - val = cpu_ldl_data(env, src); + uint32_t val = cpu_ldl_data_ra(env, src, ra); if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) { PERchanged = true; } - env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | val; + env->cregs[i] = deposit64(env->cregs[i], 0, 32, val); + HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val); src += sizeof(uint32_t); if (i == r3) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 2386c418f8..3a98c5772d 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2545,7 +2545,6 @@ static ExitStatus op_lctl(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); check_privileged(s); - potential_page_fault(s); gen_helper_lctl(cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From 75d6240c593c28c1df0b57bdf99409669cd5d808 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 12:43:23 -0700 Subject: [PATCH 26/70] target/s390x: Use unwind data for helper_stctl Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 10 ++++++---- target/s390x/translate.c | 2 -- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 614cdb2643..b64c04ed53 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -907,11 +907,12 @@ void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { - int i; + uintptr_t ra = GETPC(); uint64_t dest = a2; + uint32_t i; for (i = r1;; i = (i + 1) % 16) { - cpu_stq_data(env, dest, env->cregs[i]); + cpu_stq_data_ra(env, dest, env->cregs[i], ra); dest += sizeof(uint64_t); if (i == r3) { @@ -922,11 +923,12 @@ void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { - int i; + uintptr_t ra = GETPC(); uint64_t dest = a2; + uint32_t i; for (i = r1;; i = (i + 1) % 16) { - cpu_stl_data(env, dest, env->cregs[i]); + cpu_stl_data_ra(env, dest, env->cregs[i], ra); dest += sizeof(uint32_t); if (i == r3) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 3a98c5772d..2f15329a5e 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3617,7 +3617,6 @@ static ExitStatus op_stctg(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); check_privileged(s); - potential_page_fault(s); gen_helper_stctg(cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); @@ -3629,7 +3628,6 @@ static ExitStatus op_stctl(DisasContext *s, DisasOps *o) TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); check_privileged(s); - potential_page_fault(s); gen_helper_stctl(cpu_env, r1, o->in2, r3); tcg_temp_free_i32(r1); tcg_temp_free_i32(r3); From aef2b01a5011fffbcccb9d41b7ec01e9b4f05612 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 12:53:32 -0700 Subject: [PATCH 27/70] target/s390x: Use unwind data for helper_testblock Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 3 +++ target/s390x/translate.c | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b64c04ed53..7df2e5382b 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -939,6 +939,7 @@ void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) { + uintptr_t ra = GETPC(); CPUState *cs = CPU(s390_env_get_cpu(env)); uint64_t abs_addr; int i; @@ -947,12 +948,14 @@ uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK; if (!address_space_access_valid(&address_space_memory, abs_addr, TARGET_PAGE_SIZE, true)) { + cpu_restore_state(cs, ra); program_interrupt(env, PGM_ADDRESSING, 4); return 1; } /* Check low-address protection */ if ((env->cregs[0] & CR0_LOWPROT) && real_addr < 0x2000) { + cpu_restore_state(cs, ra); program_interrupt(env, PGM_PROTECTION, 4); return 1; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 2f15329a5e..16e39d34ed 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4047,7 +4047,6 @@ static ExitStatus op_tcxb(DisasContext *s, DisasOps *o) static ExitStatus op_testblock(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_testblock(cc_op, cpu_env, o->in2); set_cc_static(s); return NO_EXIT; From 1f3ca416656bf1ed0c33b35f2dbbdd50f9b0e17e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 12:54:35 -0700 Subject: [PATCH 28/70] target/s390x: Use unwind data for helper_tprot Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 1 - target/s390x/translate.c | 1 - 2 files changed, 2 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 7df2e5382b..a8c85c926c 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -970,7 +970,6 @@ uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) { /* XXX implement */ - return 0; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 16e39d34ed..cafcecba45 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4054,7 +4054,6 @@ static ExitStatus op_testblock(DisasContext *s, DisasOps *o) static ExitStatus op_tprot(DisasContext *s, DisasOps *o) { - potential_page_fault(s); gen_helper_tprot(cc_op, o->addr1, o->in2); set_cc_static(s); return NO_EXIT; From b157fbe6a95384e910caccc63a79c3f73c64d8ac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 13:59:02 -0700 Subject: [PATCH 29/70] target/s390x: Use unwind data for helper_lra Fix saving exception_index around mmu_translate; eliminate a dead store. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 6 +++--- target/s390x/translate.c | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index a8c85c926c..17d8257f71 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1208,17 +1208,17 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) { CPUState *cs = CPU(s390_env_get_cpu(env)); uint32_t cc = 0; - int old_exc = cs->exception_index; uint64_t asc = env->psw.mask & PSW_MASK_ASC; uint64_t ret; - int flags; + int old_exc, flags; /* XXX incomplete - has more corner cases */ if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { + cpu_restore_state(cs, GETPC()); program_interrupt(env, PGM_SPECIAL_OP, 2); } - cs->exception_index = old_exc; + old_exc = cs->exception_index; if (mmu_translate(env, addr, 0, asc, &ret, &flags, true)) { cc = 3; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index cafcecba45..80b08b9ebd 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2565,7 +2565,6 @@ static ExitStatus op_lctlg(DisasContext *s, DisasOps *o) static ExitStatus op_lra(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_lra(o->out, cpu_env, o->in2); set_cc_static(s); return NO_EXIT; From b90fb26bded72c28865e4fb257b5d3975f93b88b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 19:45:43 -0700 Subject: [PATCH 30/70] target/s390x: Use unwind data for helper_mvcs/mvcp Reviewed-by: Thomas Huth Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 8 ++++++-- target/s390x/translate.c | 2 -- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 17d8257f71..a73d486165 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1082,6 +1082,7 @@ uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2) uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { + uintptr_t ra = GETPC(); int cc = 0, i; HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", @@ -1095,7 +1096,8 @@ uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) /* XXX replace w/ memcpy */ for (i = 0; i < l; i++) { - cpu_stb_secondary(env, a1 + i, cpu_ldub_primary(env, a2 + i)); + uint8_t x = cpu_ldub_primary_ra(env, a2 + i, ra); + cpu_stb_secondary_ra(env, a1 + i, x, ra); } return cc; @@ -1103,6 +1105,7 @@ uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { + uintptr_t ra = GETPC(); int cc = 0, i; HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", @@ -1116,7 +1119,8 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) /* XXX replace w/ memcpy */ for (i = 0; i < l; i++) { - cpu_stb_primary(env, a1 + i, cpu_ldub_secondary(env, a2 + i)); + uint8_t x = cpu_ldub_secondary_ra(env, a2 + i, ra); + cpu_stb_primary_ra(env, a1 + i, x, ra); } return cc; diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 80b08b9ebd..e99fbd9f4c 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2894,7 +2894,6 @@ static ExitStatus op_mvcp(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, l1); check_privileged(s); - potential_page_fault(s); gen_helper_mvcp(cc_op, cpu_env, regs[r1], o->addr1, o->in2); set_cc_static(s); return NO_EXIT; @@ -2904,7 +2903,6 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, l1); check_privileged(s); - potential_page_fault(s); gen_helper_mvcs(cc_op, cpu_env, regs[r1], o->addr1, o->in2); set_cc_static(s); return NO_EXIT; From 8350079329562e93d109607d03393153de582d4a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 24 May 2017 11:49:53 -0700 Subject: [PATCH 31/70] target/s390x: Fix some helper_ex problems (1) The OR of the low bits or R1 into INSN were not being done consistently; it was forgotten along all but the SVC path. (2) The setting of ILEN was wrong on SVC path for EXRL. (3) The data load for ICM read too much. Fix these by consolidating data load at the beginning, using get_ilen to control the number of bytes loaded, and ORing in the byte from R1. Use extract64 from the full aligned insn to extract arguments. Pass in ILEN rather than RET as the more natural way to give the required data along the SVC path. Modify ENV->CC_OP directly rather than include it in the functional interface. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/mem_helper.c | 129 +++++++++++++++++++++----------------- target/s390x/translate.c | 8 +-- 3 files changed, 75 insertions(+), 64 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index ea35834fc6..38194095c0 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -14,7 +14,7 @@ DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) DEF_HELPER_FLAGS_4(mvpg, TCG_CALL_NO_WG, i32, 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_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) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index a73d486165..fa03129e70 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1245,76 +1245,87 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) in other words: tricky... currently implemented by interpreting the cases it is most commonly used. */ -uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, - uint64_t addr, uint64_t ret) +void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) { S390CPU *cpu = s390_env_get_cpu(env); - uint16_t insn = cpu_lduw_code(env, addr); + uint64_t insn = cpu_lduw_code(env, addr); + uint8_t opc = insn >> 8; - HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, - insn); - if ((insn & 0xf0ff) == 0xd000) { - uint32_t l, insn2, b1, b2, d1, d2; + /* Or in the contents of R1[56:63]. */ + insn |= r1 & 0xff; - l = v1 & 0xff; - insn2 = cpu_ldl_code(env, addr + 2); - b1 = (insn2 >> 28) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d1 = (insn2 >> 16) & 0xfff; - d2 = insn2 & 0xfff; - switch (insn & 0xf00) { - case 0x200: + /* Load the rest of the instruction. */ + insn <<= 48; + switch (get_ilen(opc)) { + case 2: + break; + case 4: + insn |= (uint64_t)cpu_lduw_code(env, addr + 2) << 32; + break; + case 6: + insn |= (uint64_t)(uint32_t)cpu_ldl_code(env, addr + 2) << 16; + break; + default: + g_assert_not_reached(); + } + + HELPER_LOG("%s: addr 0x%lx insn 0x%" PRIx64 "\n", __func__, addr, insn); + + if ((opc & 0xf0) == 0xd0) { + uint32_t l, b1, b2, d1, d2; + + l = extract64(insn, 48, 8); + b1 = extract64(insn, 44, 4); + b2 = extract64(insn, 28, 4); + d1 = extract64(insn, 32, 12); + d2 = extract64(insn, 16, 12); + switch (opc & 0xf) { + case 0x2: do_helper_mvc(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2), 0); - break; - case 0x400: - cc = do_helper_nc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x500: - cc = do_helper_clc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x600: - cc = do_helper_oc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x700: - cc = do_helper_xc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0xc00: + return; + case 0x4: + env->cc_op = do_helper_nc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + return; + case 0x5: + env->cc_op = do_helper_clc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + return; + case 0x6: + env->cc_op = do_helper_oc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + return; + case 0x7: + env->cc_op = do_helper_xc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + return; + case 0xc: do_helper_tr(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2), 0); - return cc; - case 0xd00: - cc = do_helper_trt(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - default: - goto abort; + return; + case 0xd: + env->cc_op = do_helper_trt(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + return; } - } else if ((insn & 0xff00) == 0x0a00) { + } else if (opc == 0x0a) { /* supervisor call */ - HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); - env->psw.addr = ret - 4; - env->int_svc_code = (insn | v1) & 0xff; - env->int_svc_ilen = 4; + env->int_svc_code = extract64(insn, 48, 8); + env->int_svc_ilen = ilen; helper_exception(env, EXCP_SVC); - } else if ((insn & 0xff00) == 0xbf00) { - uint32_t insn2, r1, r3, b2, d2; + return; + } else if (opc == 0xbf) { + uint32_t r1, r3, b2, d2; - insn2 = cpu_ldl_code(env, addr + 2); - r1 = (insn2 >> 20) & 0xf; - r3 = (insn2 >> 16) & 0xf; - b2 = (insn2 >> 12) & 0xf; - d2 = insn2 & 0xfff; - cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); - } else { - abort: - cpu_abort(CPU(cpu), - "EXECUTE on instruction prefix 0x%x not implemented\n", - insn); + r1 = extract64(insn, 52, 4); + r3 = extract64(insn, 48, 4); + b2 = extract64(insn, 44, 4); + d2 = extract64(insn, 32, 12); + env->cc_op = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); + return; } - return cc; + + cpu_abort(CPU(cpu), "EXECUTE on instruction prefix 0x%x not implemented\n", + opc); } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index e99fbd9f4c..c1162a134d 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2164,14 +2164,14 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) MVC inside of memcpy, which needs a helper call anyway. So perhaps this doesn't bear thinking about any further. */ - TCGv_i64 tmp; + TCGv_i32 ilen; update_psw_addr(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); + ilen = tcg_const_i32(s->next_pc - s->pc); + gen_helper_ex(cpu_env, ilen, o->in1, o->in2); + tcg_temp_free_i32(ilen); return NO_EXIT; } From a72da8b7f555d640d79e41b131c1cd3169811861 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 24 May 2017 11:56:15 -0700 Subject: [PATCH 32/70] target/s390x: Fix EXECUTE with R1==0 The PoO specifies that when R1==0, no ORing into the insn loaded from storage takes place. Load a zero for this case. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/insn-data.def | 4 ++-- target/s390x/translate.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index cac0f51ac6..3c3541cfbf 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -327,9 +327,9 @@ C(0xeb57, XIY, SIY, LD, m1_8u, i2_8u, new, m1_8, xor, nz64) /* EXECUTE */ - C(0x4400, EX, RX_a, Z, r1_o, a2, 0, 0, ex, 0) + C(0x4400, EX, RX_a, Z, 0, a2, 0, 0, ex, 0) /* EXECUTE RELATIVE LONG */ - C(0xc600, EXRL, RIL_b, EE, r1_o, ri2, 0, 0, ex, 0) + C(0xc600, EXRL, RIL_b, EE, 0, ri2, 0, 0, ex, 0) /* EXTRACT ACCESS */ C(0xb24f, EAR, RRE, Z, 0, 0, new, r1_32, ear, 0) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index c1162a134d..78c14ef6ce 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2164,15 +2164,27 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) MVC inside of memcpy, which needs a helper call anyway. So perhaps this doesn't bear thinking about any further. */ + int r1 = get_field(s->fields, r1); TCGv_i32 ilen; + TCGv_i64 v1; update_psw_addr(s); gen_op_calc_cc(s); + if (r1 == 0) { + v1 = tcg_const_i64(0); + } else { + v1 = regs[r1]; + } + ilen = tcg_const_i32(s->next_pc - s->pc); - gen_helper_ex(cpu_env, ilen, o->in1, o->in2); + gen_helper_ex(cpu_env, ilen, v1, o->in2); tcg_temp_free_i32(ilen); + if (r1 == 0) { + tcg_temp_free_i64(v1); + } + return NO_EXIT; } From 31a18b4575c1b882f2cd2fa2ef5dba7a5c12a497 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 18:34:42 -0700 Subject: [PATCH 33/70] target/s390x: Use atomic operations for COMPARE SWAP PURGE Also provide the cross-cpu tlb flushing required by the PoO. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/insn-data.def | 2 +- target/s390x/mem_helper.c | 32 ++++++++--------------------- target/s390x/translate.c | 42 ++++++++++++++++++++++++++++++++++---- 4 files changed, 48 insertions(+), 30 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 38194095c0..cc451c70a6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -107,13 +107,13 @@ DEF_HELPER_FLAGS_2(tprot, TCG_CALL_NO_RWG, i32, i64, i64) DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) -DEF_HELPER_3(csp, i32, env, i32, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) DEF_HELPER_FLAGS_2(lura, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(lurag, TCG_CALL_NO_WG, i64, env, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 3c3541cfbf..4c91f30fe0 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -837,7 +837,7 @@ #ifndef CONFIG_USER_ONLY /* COMPARE AND SWAP AND PURGE */ - C(0xb250, CSP, RRE, Z, 0, ra2, 0, 0, csp, 0) + D(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL) /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0) /* INSERT STORAGE KEY EXTENDED */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index fa03129e70..4b96c279e3 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1056,30 +1056,6 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) return re >> 1; } -/* compare and swap and purge */ -uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2) -{ - S390CPU *cpu = s390_env_get_cpu(env); - uint32_t cc; - uint32_t o1 = env->regs[r1]; - uint64_t a2 = r2 & ~3ULL; - uint32_t o2 = cpu_ldl_data(env, a2); - - if (o1 == o2) { - cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); - if (r2 & 0x3) { - /* flush TLB / ALB */ - tlb_flush(CPU(cpu)); - } - cc = 0; - } else { - env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; - cc = 1; - } - - return cc; -} - uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) { uintptr_t ra = GETPC(); @@ -1161,6 +1137,14 @@ void HELPER(ptlb)(CPUS390XState *env) tlb_flush(CPU(cpu)); } +/* flush global tlb */ +void HELPER(purge)(CPUS390XState *env) +{ + S390CPU *cpu = s390_env_get_cpu(env); + + tlb_flush_all_cpus_synced(CPU(cpu)); +} + /* load using real address */ uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 78c14ef6ce..711b9c947e 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2006,11 +2006,45 @@ static ExitStatus op_cdsg(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static ExitStatus op_csp(DisasContext *s, DisasOps *o) { - TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGMemOp mop = s->insn->data; + TCGv_i64 addr, old, cc; + TCGLabel *lab = gen_new_label(); + + /* Note that in1 = R1 (zero-extended expected value), + out = R1 (original reg), out2 = R1+1 (new value). */ + check_privileged(s); - gen_helper_csp(cc_op, cpu_env, r1, o->in2); - tcg_temp_free_i32(r1); - set_cc_static(s); + addr = tcg_temp_new_i64(); + old = tcg_temp_new_i64(); + tcg_gen_andi_i64(addr, o->in2, -1ULL << (mop & MO_SIZE)); + tcg_gen_atomic_cmpxchg_i64(old, addr, o->in1, o->out2, + get_mem_index(s), mop | MO_ALIGN); + tcg_temp_free_i64(addr); + + /* Are the memory and expected values (un)equal? */ + cc = tcg_temp_new_i64(); + tcg_gen_setcond_i64(TCG_COND_NE, cc, o->in1, old); + tcg_gen_extrl_i64_i32(cc_op, cc); + + /* Write back the output now, so that it happens before the + following branch, so that we don't need local temps. */ + if ((mop & MO_SIZE) == MO_32) { + tcg_gen_deposit_i64(o->out, o->out, old, 0, 32); + } else { + tcg_gen_mov_i64(o->out, old); + } + tcg_temp_free_i64(old); + + /* If the comparison was equal, and the LSB of R2 was set, + then we need to flush the TLB (for all cpus). */ + tcg_gen_xori_i64(cc, cc, 1); + tcg_gen_and_i64(cc, cc, o->in2); + tcg_gen_brcondi_i64(TCG_COND_EQ, cc, 0, lab); + tcg_temp_free_i64(cc); + + gen_helper_purge(cpu_env); + gen_set_label(lab); + return NO_EXIT; } #endif From b26de9518d332e8a72ba634bdf348b69bbf4173e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 22 May 2017 18:58:42 -0700 Subject: [PATCH 34/70] target/s390x: Implement CSPG Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/insn-data.def | 1 + target/s390x/translate.c | 1 + 2 files changed, 2 insertions(+) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 4c91f30fe0..f818437069 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -838,6 +838,7 @@ #ifndef CONFIG_USER_ONLY /* COMPARE AND SWAP AND PURGE */ D(0xb250, CSP, RRE, Z, r1_32u, ra2, r1_P, 0, csp, 0, MO_TEUL) + D(0xb98a, CSPG, RRE, DAT_ENH, r1_o, ra2, r1_P, 0, csp, 0, MO_TEQ) /* DIAGNOSE (KVM hypercall) */ C(0x8300, DIAG, RSI, Z, 0, 0, 0, 0, diag, 0) /* INSERT STORAGE KEY EXTENDED */ diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 711b9c947e..737b577ce4 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1200,6 +1200,7 @@ typedef enum DisasFacility { FAC_SFLE, /* store facility list extended */ FAC_ILA, /* interlocked access facility 1 */ FAC_LPP, /* load-program-parameter */ + FAC_DAT_ENH, /* DAT-enhancement */ } DisasFacility; struct DisasInsn { From 99e57856f6c6da8031dcbca5f1aa6735da04bb6f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 24 May 2017 12:27:36 -0700 Subject: [PATCH 35/70] target/s390x: Save current ilen during translation Use this saved value instead of recomputing from next_pc difference. Reviewed-by: David Hildenbrand Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/translate.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 737b577ce4..5c7e5c1c27 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -58,6 +58,7 @@ struct DisasContext { const DisasInsn *insn; DisasFields *fields; uint64_t pc, next_pc; + uint32_t ilen; enum cc_op cc_op; bool singlestep_enabled; }; @@ -349,7 +350,7 @@ static void gen_program_exception(DisasContext *s, int code) tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_code)); tcg_temp_free_i32(tmp); - tmp = tcg_const_i32(s->next_pc - s->pc); + tmp = tcg_const_i32(s->ilen); tcg_gen_st_i32(tmp, cpu_env, offsetof(CPUS390XState, int_pgm_ilen)); tcg_temp_free_i32(tmp); @@ -2212,7 +2213,7 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) v1 = regs[r1]; } - ilen = tcg_const_i32(s->next_pc - s->pc); + ilen = tcg_const_i32(s->ilen); gen_helper_ex(cpu_env, ilen, v1, o->in2); tcg_temp_free_i32(ilen); @@ -4057,7 +4058,7 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_code)); tcg_temp_free_i32(t); - t = tcg_const_i32(s->next_pc - s->pc); + t = tcg_const_i32(s->ilen); tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, int_svc_ilen)); tcg_temp_free_i32(t); @@ -5196,6 +5197,7 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, op = (insn >> 8) & 0xff; ilen = get_ilen(op); s->next_pc = s->pc + ilen; + s->ilen = ilen; switch (ilen) { case 2: From 06fc03486cf9b825f8afd9defe80a255364ed02c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 24 May 2017 13:00:16 -0700 Subject: [PATCH 36/70] target/s390x: End the TB after EXECUTE This split will be required for implementing EXECUTE properly. Do this now as a separate step to aid comparison of before and after TB listings. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 54 +++++++++++++++++++++++---------------- target/s390x/translate.c | 6 ++++- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 4b96c279e3..d57d5b1702 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1234,6 +1234,7 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) S390CPU *cpu = s390_env_get_cpu(env); uint64_t insn = cpu_lduw_code(env, addr); uint8_t opc = insn >> 8; + uint32_t cc; /* Or in the contents of R1[56:63]. */ insn |= r1 & 0xff; @@ -1263,42 +1264,46 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) b2 = extract64(insn, 28, 4); d1 = extract64(insn, 32, 12); d2 = extract64(insn, 16, 12); + + cc = env->cc_op; switch (opc & 0xf) { case 0x2: do_helper_mvc(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2), 0); - return; + break; case 0x4: - env->cc_op = do_helper_nc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - return; + cc = do_helper_nc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + break; case 0x5: - env->cc_op = do_helper_clc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - return; + cc = do_helper_clc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + break; case 0x6: - env->cc_op = do_helper_oc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - return; + cc = do_helper_oc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + break; case 0x7: - env->cc_op = do_helper_xc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - return; + cc = do_helper_xc(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + break; case 0xc: do_helper_tr(env, l, get_address(env, 0, b1, d1), get_address(env, 0, b2, d2), 0); - return; + break; case 0xd: - env->cc_op = do_helper_trt(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - return; + cc = do_helper_trt(env, l, get_address(env, 0, b1, d1), + get_address(env, 0, b2, d2), 0); + break; + default: + goto abort; } } else if (opc == 0x0a) { /* supervisor call */ env->int_svc_code = extract64(insn, 48, 8); env->int_svc_ilen = ilen; helper_exception(env, EXCP_SVC); - return; + g_assert_not_reached(); } else if (opc == 0xbf) { uint32_t r1, r3, b2, d2; @@ -1306,10 +1311,15 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) r3 = extract64(insn, 48, 4); b2 = extract64(insn, 44, 4); d2 = extract64(insn, 32, 12); - env->cc_op = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); - return; + cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); + } else { + abort: + cpu_abort(CPU(cpu), + "EXECUTE on instruction prefix 0x%x not implemented\n", + opc); + g_assert_not_reached(); } - cpu_abort(CPU(cpu), "EXECUTE on instruction prefix 0x%x not implemented\n", - opc); + env->cc_op = cc; + env->psw.addr += ilen; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 5c7e5c1c27..b6b9d755f9 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1168,6 +1168,8 @@ typedef enum { the PC (for whatever reason), so there's no need to do it again on exiting the TB. */ EXIT_PC_UPDATED, + /* We have updated the PC and CC values. */ + EXIT_PC_CC_UPDATED, /* We are exiting the TB, but have neither emitted a goto_tb, nor updated the PC for the next instruction to be executed. */ EXIT_PC_STALE, @@ -2221,7 +2223,7 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) tcg_temp_free_i64(v1); } - return NO_EXIT; + return EXIT_PC_CC_UPDATED; } static ExitStatus op_fieb(DisasContext *s, DisasOps *o) @@ -5494,6 +5496,8 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb) /* Next TB starts off with CC_OP_DYNAMIC, so make sure the cc op type is in env */ update_cc_op(&dc); + /* FALLTHRU */ + case EXIT_PC_CC_UPDATED: /* Exit the TB, either by raising a debug exception or by return. */ if (do_debug) { gen_exception(EXCP_DEBUG); From 303c681a8f50eb88fbafc2bf6a7e4c5813ac2be0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 21 May 2017 09:50:00 -0700 Subject: [PATCH 37/70] target/s390x: Implement EXECUTE via new TranslationBlock Previously, helper_ex would construct the insn and then implement the insn via direct calls other helpers. This was sufficient to boot Linux but that is all. It is easy enough to go the whole nine yards by stashing state for EXECUTE within the cpu, and then rely on a new TB to be created that properly and completely interprets the insn. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/cpu.h | 4 +- target/s390x/helper.c | 5 ++ target/s390x/machine.c | 19 ++++++ target/s390x/mem_helper.c | 118 ++++---------------------------------- target/s390x/translate.c | 80 +++++++++++++++----------- 5 files changed, 85 insertions(+), 141 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index f463113116..fdb2f50383 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -107,6 +107,8 @@ typedef struct CPUS390XState { uint64_t cc_dst; uint64_t cc_vr; + uint64_t ex_value; + uint64_t __excp_addr; uint64_t psa; @@ -393,7 +395,7 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { *pc = env->psw.addr; - *cs_base = 0; + *cs_base = env->ex_value; *flags = ((env->psw.mask >> 32) & ~FLAG_MASK_CC) | ((env->psw.mask & PSW_MASK_32) ? FLAG_MASK_32 : 0); } diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 4f8aadf305..291db720fb 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -642,6 +642,11 @@ bool s390_cpu_exec_interrupt(CPUState *cs, int interrupt_request) S390CPU *cpu = S390_CPU(cs); CPUS390XState *env = &cpu->env; + if (env->ex_value) { + /* Execution of the target insn is indivisible from + the parent EXECUTE insn. */ + return false; + } if (env->psw.mask & PSW_MASK_EXT) { s390_cpu_do_interrupt(cs); return true; diff --git a/target/s390x/machine.c b/target/s390x/machine.c index 8503fa1c8d..8f908bbe82 100644 --- a/target/s390x/machine.c +++ b/target/s390x/machine.c @@ -34,6 +34,7 @@ static int cpu_post_load(void *opaque, int version_id) return 0; } + static void cpu_pre_save(void *opaque) { S390CPU *cpu = opaque; @@ -156,6 +157,23 @@ const VMStateDescription vmstate_riccb = { } }; +static bool exval_needed(void *opaque) +{ + S390CPU *cpu = opaque; + return cpu->env.ex_value != 0; +} + +const VMStateDescription vmstate_exval = { + .name = "cpu/exval", + .version_id = 1, + .minimum_version_id = 1, + .needed = exval_needed, + .fields = (VMStateField[]) { + VMSTATE_UINT64(env.ex_value, S390CPU), + VMSTATE_END_OF_LIST() + } +}; + const VMStateDescription vmstate_s390_cpu = { .name = "cpu", .post_load = cpu_post_load, @@ -188,6 +206,7 @@ const VMStateDescription vmstate_s390_cpu = { &vmstate_fpu, &vmstate_vregs, &vmstate_riccb, + &vmstate_exval, NULL }, }; diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index d57d5b1702..3a77edc9fe 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -435,37 +435,6 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) return d + len; } -static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, - uint32_t mask) -{ - int pos = 24; /* top of the lower half of r1 */ - uint64_t rmask = 0xff000000ULL; - uint8_t val = 0; - int ccd = 0; - uint32_t cc = 0; - - while (mask) { - if (mask & 8) { - env->regs[r1] &= ~rmask; - val = cpu_ldub_data(env, address); - if ((val & 0x80) && !ccd) { - cc = 1; - } - ccd = 1; - if (val && cc == 0) { - cc = 2; - } - env->regs[r1] |= (uint64_t)val << pos; - address++; - } - mask = (mask << 1) & 0xf; - pos -= 8; - rmask >>= 8; - } - - return cc; -} - /* load access registers r1 to r3 from memory at a2 */ void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { @@ -1222,19 +1191,17 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) } #endif -/* execute instruction - this instruction executes an insn modified with the contents of r1 - it does not change the executed instruction in memory - it does not change the program counter - in other words: tricky... - currently implemented by interpreting the cases it is most commonly used. +/* Execute instruction. This instruction executes an insn modified with + the contents of r1. It does not change the executed instruction in memory; + it does not change the program counter. + + Perform this by recording the modified instruction in env->ex_value. + This will be noticed by cpu_get_tb_cpu_state and thus tb translation. */ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) { - S390CPU *cpu = s390_env_get_cpu(env); uint64_t insn = cpu_lduw_code(env, addr); uint8_t opc = insn >> 8; - uint32_t cc; /* Or in the contents of R1[56:63]. */ insn |= r1 & 0xff; @@ -1254,72 +1221,9 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) g_assert_not_reached(); } - HELPER_LOG("%s: addr 0x%lx insn 0x%" PRIx64 "\n", __func__, addr, insn); - - if ((opc & 0xf0) == 0xd0) { - uint32_t l, b1, b2, d1, d2; - - l = extract64(insn, 48, 8); - b1 = extract64(insn, 44, 4); - b2 = extract64(insn, 28, 4); - d1 = extract64(insn, 32, 12); - d2 = extract64(insn, 16, 12); - - cc = env->cc_op; - switch (opc & 0xf) { - case 0x2: - do_helper_mvc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x4: - cc = do_helper_nc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x5: - cc = do_helper_clc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x6: - cc = do_helper_oc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0x7: - cc = do_helper_xc(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0xc: - do_helper_tr(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - case 0xd: - cc = do_helper_trt(env, l, get_address(env, 0, b1, d1), - get_address(env, 0, b2, d2), 0); - break; - default: - goto abort; - } - } else if (opc == 0x0a) { - /* supervisor call */ - env->int_svc_code = extract64(insn, 48, 8); - env->int_svc_ilen = ilen; - helper_exception(env, EXCP_SVC); - g_assert_not_reached(); - } else if (opc == 0xbf) { - uint32_t r1, r3, b2, d2; - - r1 = extract64(insn, 52, 4); - r3 = extract64(insn, 48, 4); - b2 = extract64(insn, 44, 4); - d2 = extract64(insn, 32, 12); - cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); - } else { - abort: - cpu_abort(CPU(cpu), - "EXECUTE on instruction prefix 0x%x not implemented\n", - opc); - g_assert_not_reached(); - } - - env->cc_op = cc; - env->psw.addr += ilen; + /* Record the insn we want to execute as well as the ilen to use + during the execution of the target insn. This will also ensure + that ex_value is non-zero, which flags that we are in a state + that requires such execution. */ + env->ex_value = insn | ilen; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index b6b9d755f9..0406f22be0 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -57,6 +57,7 @@ struct DisasContext { struct TranslationBlock *tb; const DisasInsn *insn; DisasFields *fields; + uint64_t ex_value; uint64_t pc, next_pc; uint32_t ilen; enum cc_op cc_op; @@ -2191,23 +2192,18 @@ static ExitStatus op_epsw(DisasContext *s, DisasOps *o) static ExitStatus op_ex(DisasContext *s, DisasOps *o) { - /* ??? Perhaps a better way to implement EXECUTE is to set a bit in - tb->flags, (ab)use the tb->cs_base field as the address of - the template in memory, and grab 8 bits of tb->flags/cflags for - the contents of the register. We would then recognize all this - in gen_intermediate_code_internal, generating code for exactly - one instruction. This new TB then gets executed normally. - - On the other hand, this seems to be mostly used for modifying - MVC inside of memcpy, which needs a helper call anyway. So - perhaps this doesn't bear thinking about any further. */ - int r1 = get_field(s->fields, r1); TCGv_i32 ilen; TCGv_i64 v1; + /* Nested EXECUTE is not allowed. */ + if (unlikely(s->ex_value)) { + gen_program_exception(s, PGM_EXECUTE); + return EXIT_NORETURN; + } + update_psw_addr(s); - gen_op_calc_cc(s); + update_cc_op(s); if (r1 == 0) { v1 = tcg_const_i64(0); @@ -5195,26 +5191,37 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, int op, op2, ilen; const DisasInsn *info; - insn = ld_code2(env, pc); - op = (insn >> 8) & 0xff; - ilen = get_ilen(op); + if (unlikely(s->ex_value)) { + /* Drop the EX data now, so that it's clear on exception paths. */ + TCGv_i64 zero = tcg_const_i64(0); + tcg_gen_st_i64(zero, cpu_env, offsetof(CPUS390XState, ex_value)); + tcg_temp_free_i64(zero); + + /* Extract the values saved by EXECUTE. */ + insn = s->ex_value & 0xffffffffffff0000ull; + ilen = s->ex_value & 0xf; + op = insn >> 56; + } else { + insn = ld_code2(env, pc); + op = (insn >> 8) & 0xff; + ilen = get_ilen(op); + switch (ilen) { + case 2: + insn = insn << 48; + break; + case 4: + insn = ld_code4(env, pc) << 32; + break; + case 6: + insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); + break; + default: + g_assert_not_reached(); + } + } s->next_pc = s->pc + ilen; s->ilen = ilen; - switch (ilen) { - case 2: - insn = insn << 48; - break; - case 4: - insn = ld_code4(env, pc) << 32; - break; - case 6: - insn = (insn << 48) | (ld_code4(env, pc + 2) << 16); - break; - default: - abort(); - } - /* We can't actually determine the insn format until we've looked up the full insn opcode. Which we can't do without locating the secondary opcode. Assume by default that OP2 is at bit 40; for @@ -5430,6 +5437,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb) dc.tb = tb; dc.pc = pc_start; dc.cc_op = CC_OP_DYNAMIC; + dc.ex_value = tb->cs_base; do_debug = dc.singlestep_enabled = cs->singlestep_enabled; next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; @@ -5476,7 +5484,8 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb) || tcg_op_buf_full() || num_insns >= max_insns || singlestep - || cs->singlestep_enabled)) { + || cs->singlestep_enabled + || dc.ex_value)) { status = EXIT_PC_STALE; } } while (status == NO_EXIT); @@ -5520,9 +5529,14 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb) if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM) && qemu_log_in_addr_range(pc_start)) { qemu_log_lock(); - qemu_log("IN: %s\n", lookup_symbol(pc_start)); - log_target_disas(cs, pc_start, dc.pc - pc_start, 1); - qemu_log("\n"); + if (unlikely(dc.ex_value)) { + /* ??? Unfortunately log_target_disas can't use host memory. */ + qemu_log("IN: EXECUTE %016" PRIx64 "\n", dc.ex_value); + } else { + qemu_log("IN: %s\n", lookup_symbol(pc_start)); + log_target_disas(cs, pc_start, dc.pc - pc_start, 1); + qemu_log("\n"); + } qemu_log_unlock(); } #endif From d376f123c7de4cb82c743cb42421653aa305150e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 24 May 2017 14:34:10 -0700 Subject: [PATCH 38/70] target/s390x: Re-implement a few EXECUTE target insns directly While the previous patch is required for proper conformance, the vast majority of target insns are MVC and XC for implementing memmove and memset respectively. The next most common are CLC, TR, and SVC. Implementing these (and a few others for which we already have an implementation) directly is faster than going through full translation to a TB. Reviewed-by: Aurelien Jarno Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 66 ++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 3a77edc9fe..e35571e342 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -200,31 +200,30 @@ uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, } /* memmove */ -static void do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest, - uint64_t src, uintptr_t ra) +static uint32_t do_helper_mvc(CPUS390XState *env, uint32_t l, uint64_t dest, + uint64_t src, uintptr_t ra) { uint32_t i; HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", __func__, l, dest, src); + /* mvc and memmove do not behave the same when areas overlap! */ /* mvc with source pointing to the byte after the destination is the same as memset with the first source byte */ if (dest == src + 1) { fast_memset(env, dest, cpu_ldub_data_ra(env, src, ra), l + 1, ra); - return; - } - - /* mvc and memmove do not behave the same when areas overlap! */ - if (dest < src || src + l < dest) { + } else if (dest < src || src + l < dest) { fast_memmove(env, dest, src, l + 1, ra); - return; + } else { + /* slow version with byte accesses which always work */ + for (i = 0; i <= l; i++) { + uint8_t x = cpu_ldub_data_ra(env, src + i, ra); + cpu_stb_data_ra(env, dest + i, x, ra); + } } - /* slow version with byte accesses which always work */ - for (i = 0; i <= l; i++) { - cpu_stb_data_ra(env, dest + i, cpu_ldub_data_ra(env, src + i, ra), ra); - } + return env->cc_op; } void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) @@ -692,8 +691,8 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, } } -static void do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, - uint64_t trans, uintptr_t ra) +static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, + uint64_t trans, uintptr_t ra) { uint32_t i; @@ -702,12 +701,14 @@ static void do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, uint8_t new_byte = cpu_ldub_data_ra(env, trans + byte, ra); cpu_stb_data_ra(env, array + i, new_byte, ra); } + + return env->cc_op; } void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, uint64_t trans) { - return do_helper_tr(env, len, array, trans, GETPC()); + do_helper_tr(env, len, array, trans, GETPC()); } uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array, @@ -1221,6 +1222,41 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) g_assert_not_reached(); } + /* The very most common cases can be sped up by avoiding a new TB. */ + if ((opc & 0xf0) == 0xd0) { + typedef uint32_t (*dx_helper)(CPUS390XState *, uint32_t, uint64_t, + uint64_t, uintptr_t); + static const dx_helper dx[16] = { + [0x2] = do_helper_mvc, + [0x4] = do_helper_nc, + [0x5] = do_helper_clc, + [0x6] = do_helper_oc, + [0x7] = do_helper_xc, + [0xc] = do_helper_tr, + [0xd] = do_helper_trt, + }; + dx_helper helper = dx[opc & 0xf]; + + if (helper) { + uint32_t l = extract64(insn, 48, 8); + uint32_t b1 = extract64(insn, 44, 4); + uint32_t d1 = extract64(insn, 32, 12); + uint32_t b2 = extract64(insn, 28, 4); + uint32_t d2 = extract64(insn, 16, 12); + uint64_t a1 = get_address(env, 0, b1, d1); + uint64_t a2 = get_address(env, 0, b2, d2); + + env->cc_op = helper(env, l, a1, a2, 0); + env->psw.addr += ilen; + return; + } + } else if (opc == 0x0a) { + env->int_svc_code = extract64(insn, 48, 8); + env->int_svc_ilen = ilen; + helper_exception(env, EXCP_SVC); + g_assert_not_reached(); + } + /* Record the insn we want to execute as well as the ilen to use during the execution of the target insn. This will also ensure that ex_value is non-zero, which flags that we are in a state From fc7fbcbc4829563469fa33b68e6b771d455229ac Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 25 May 2017 11:22:12 +0200 Subject: [PATCH 39/70] target/s390x/cpu_models: Allow some additional feature bits for the "qemu" CPU Currently we only present the plain z900 feature bits to the guest, but QEMU already emulates some additional features (but not all of the next CPU generation, so we can not use the next CPU level as default yet). Since newer Linux kernels are checking the feature bits and refuse to work if a required feature is missing, it would be nice to have a way to present more of the supported features when we are running with the "qemu" CPU. This patch now adds the supported features to the "full_feat" bitmap, so that additional features can be enabled on the command line now, for example with: qemu-system-s390x -cpu qemu,stfle=true,ldisp=true,eimm=true,stckf=true Acked-by: David Hildenbrand Reviewed-by: Aurelien Jarno Signed-off-by: Thomas Huth Message-Id: <1495704132-5675-1-git-send-email-thuth@redhat.com> Signed-off-by: Richard Henderson --- target/s390x/cpu_models.c | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 8d27363b07..e5e005a430 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -658,6 +658,30 @@ static void check_compatibility(const S390CPUModel *max_model, "available in the configuration: "); } +/** + * The base TCG CPU model "qemu" is based on the z900. However, we already + * can also emulate some additional features of later CPU generations, so + * we add these additional feature bits here. + */ +static void add_qemu_cpu_model_features(S390FeatBitmap fbm) +{ + static const int feats[] = { + S390_FEAT_STFLE, + S390_FEAT_EXTENDED_IMMEDIATE, + S390_FEAT_LONG_DISPLACEMENT, + S390_FEAT_LONG_DISPLACEMENT_FAST, + S390_FEAT_STORE_CLOCK_FAST, + S390_FEAT_GENERAL_INSTRUCTIONS_EXT, + S390_FEAT_EXECUTE_EXT, + S390_FEAT_STFLE_45, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(feats); i++) { + set_bit(feats[i], fbm); + } +} + static S390CPUModel *get_max_cpu_model(Error **errp) { static S390CPUModel max_model; @@ -670,10 +694,11 @@ static S390CPUModel *get_max_cpu_model(Error **errp) if (kvm_enabled()) { kvm_s390_get_host_cpu_model(&max_model, errp); } else { - /* TCG emulates a z900 */ + /* TCG emulates a z900 (with some optional additional features) */ max_model.def = &s390_cpu_defs[0]; bitmap_copy(max_model.features, max_model.def->default_feat, S390_FEAT_MAX); + add_qemu_cpu_model_features(max_model.features); } if (!*errp) { cached = true; @@ -925,11 +950,14 @@ static void s390_host_cpu_model_initfn(Object *obj) static void s390_qemu_cpu_model_initfn(Object *obj) { + static S390CPUDef s390_qemu_cpu_defs; S390CPU *cpu = S390_CPU(obj); cpu->model = g_malloc0(sizeof(*cpu->model)); - /* TCG emulates a z900 */ - cpu->model->def = &s390_cpu_defs[0]; + /* TCG emulates a z900 (with some optional additional features) */ + memcpy(&s390_qemu_cpu_defs, &s390_cpu_defs[0], sizeof(s390_qemu_cpu_defs)); + add_qemu_cpu_model_features(s390_qemu_cpu_defs.full_feat); + cpu->model->def = &s390_qemu_cpu_defs; bitmap_copy(cpu->model->features, cpu->model->def->default_feat, S390_FEAT_MAX); } From 51a718bf3dc7a4d8ae70219ffe4fef7a8dfadb24 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:00 +0200 Subject: [PATCH 40/70] target/s390x: remove dead code in translate.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-2-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/translate.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 0406f22be0..67ddf1b809 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -5472,10 +5472,7 @@ void gen_intermediate_code(CPUS390XState *env, struct TranslationBlock *tb) gen_io_start(); } - status = NO_EXIT; - if (status == NO_EXIT) { - status = translate_one(env, &dc); - } + status = translate_one(env, &dc); /* If we reach a page boundary, are single stepping, or exhaust instruction count, stop generation. */ From 8a4719f527484a7b9940e1c93690b01dc5ca5144 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:01 +0200 Subject: [PATCH 41/70] target/s390x: remove some Linux assumptions from IPTE Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-3-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/cpu.h | 2 ++ target/s390x/mem_helper.c | 17 ++++++++++------- target/s390x/mmu_helper.c | 2 -- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index fdb2f50383..a4d31df2b5 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -1035,6 +1035,8 @@ struct sysib_322 { #define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */ #define _SEGMENT_ENTRY_INV 0x20 /* invalid segment table entry */ +#define VADDR_PX 0xff000 /* page index bits */ + #define _PAGE_RO 0x200 /* HW read-only bit */ #define _PAGE_INVALID 0x400 /* HW invalid bit */ #define _PAGE_RES0 0x800 /* bit must be zero */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index e35571e342..0ebd65d9ab 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1073,19 +1073,22 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) } /* invalidate pte */ -void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr) +void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr) { CPUState *cs = CPU(s390_env_get_cpu(env)); uint64_t page = vaddr & TARGET_PAGE_MASK; - uint64_t pte = 0; + uint64_t pte_addr, pte; /* XXX broadcast to other CPUs */ - /* XXX Linux is nice enough to give us the exact pte address. - According to spec we'd have to find it out ourselves */ - /* XXX Linux is fine with overwriting the pte, the spec requires - us to only set the invalid bit */ - stq_phys(cs->as, pte_addr, pte | _PAGE_INVALID); + /* Compute the page table entry address */ + pte_addr = (pto & _SEGMENT_ENTRY_ORIGIN); + pte_addr += (vaddr & _VADDR_PX) >> 9; + + /* Mark the page table entry as invalid */ + pte = ldq_phys(cs->as, pte_addr); + pte |= _PAGE_INVALID; + stq_phys(cs->as, pte_addr, pte); /* XXX we exploit the fact that Linux passes the exact virtual address here - it's not obliged to! */ diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 31eb9efa9b..501e39010d 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -143,8 +143,6 @@ static int mmu_translate_pte(CPUS390XState *env, target_ulong vaddr, return 0; } -#define VADDR_PX 0xff000 /* Page index bits */ - /* Decode segment table entry */ static int mmu_translate_segment(CPUS390XState *env, target_ulong vaddr, uint64_t asc, uint64_t st_entry, From 1f58720c5fd033e4e2de1d047020b43a3cb3aa1b Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:02 +0200 Subject: [PATCH 42/70] target/s390x: implement local-TLB-clearing in IPTE And at the same time make IPTE SMP aware. Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-4-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 2 +- target/s390x/mem_helper.c | 21 +++++++++++++-------- target/s390x/translate.c | 6 +++++- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index cc451c70a6..3f5a05d43b 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -111,7 +111,7 @@ DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i64) DEF_HELPER_FLAGS_2(sacf, TCG_CALL_NO_WG, void, env, i64) -DEF_HELPER_FLAGS_3(ipte, TCG_CALL_NO_RWG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(ipte, TCG_CALL_NO_RWG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_1(purge, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(lra, i64, env, i64) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 0ebd65d9ab..ddbebcd7ae 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1073,17 +1073,16 @@ uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) } /* invalidate pte */ -void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr) +void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr, + uint32_t m4) { CPUState *cs = CPU(s390_env_get_cpu(env)); uint64_t page = vaddr & TARGET_PAGE_MASK; uint64_t pte_addr, pte; - /* XXX broadcast to other CPUs */ - /* Compute the page table entry address */ pte_addr = (pto & _SEGMENT_ENTRY_ORIGIN); - pte_addr += (vaddr & _VADDR_PX) >> 9; + pte_addr += (vaddr & VADDR_PX) >> 9; /* Mark the page table entry as invalid */ pte = ldq_phys(cs->as, pte_addr); @@ -1092,13 +1091,19 @@ void HELPER(ipte)(CPUS390XState *env, uint64_t pto, uint64_t vaddr) /* XXX we exploit the fact that Linux passes the exact virtual address here - it's not obliged to! */ - tlb_flush_page(cs, page); + /* XXX: the LC bit should be considered as 0 if the local-TLB-clearing + facility is not installed. */ + if (m4 & 1) { + tlb_flush_page(cs, page); + } else { + tlb_flush_page_all_cpus_synced(cs, page); + } /* XXX 31-bit hack */ - if (page & 0x80000000) { - tlb_flush_page(cs, page & ~0x80000000); + if (m4 & 1) { + tlb_flush_page(cs, page ^ 0x80000000); } else { - tlb_flush_page(cs, page | 0x80000000); + tlb_flush_page_all_cpus_synced(cs, page ^ 0x80000000); } } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 67ddf1b809..0a1b3b3d07 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2357,8 +2357,12 @@ static ExitStatus op_ipm(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static ExitStatus op_ipte(DisasContext *s, DisasOps *o) { + TCGv_i32 m4; + check_privileged(s); - gen_helper_ipte(cpu_env, o->in1, o->in2); + m4 = tcg_const_i32(get_field(s->fields, m4)); + gen_helper_ipte(cpu_env, o->in1, o->in2, m4); + tcg_temp_free_i32(m4); return NO_EXIT; } From 6699adfc1824d420e14aacbb86712264cfcaa1ce Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:03 +0200 Subject: [PATCH 43/70] target/s390x: implement TEST AND SET Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-5-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/insn-data.def | 3 +++ target/s390x/translate.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index f818437069..0f70acea5c 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -810,6 +810,9 @@ /* SUPERVISOR CALL */ C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) +/* TEST AND SET */ + C(0x9300, TS, S, Z, 0, a2, 0, 0, ts, 0) + /* TEST DATA CLASS */ C(0xed10, TCEB, RXE, Z, e1, a2, 0, 0, tceb, 0) C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 0a1b3b3d07..2d45132745 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4134,6 +4134,16 @@ static ExitStatus op_trt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ts(DisasContext *s, DisasOps *o) +{ + TCGv_i32 t1 = tcg_const_i32(0xff); + tcg_gen_atomic_xchg_i32(t1, o->in2, t1, get_mem_index(s), MO_UB); + tcg_gen_extract_i32(cc_op, t1, 7, 1); + tcg_temp_free_i32(t1); + 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 0c0974d785047ecd6226a4796374886d2c84b0ee Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:04 +0200 Subject: [PATCH 44/70] target/s390x: implement TEST ADDRESSING MODE Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-6-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/insn-data.def | 3 +++ target/s390x/translate.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 0f70acea5c..170b50ef2e 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -810,6 +810,9 @@ /* SUPERVISOR CALL */ C(0x0a00, SVC, I, Z, 0, 0, 0, 0, svc, 0) +/* TEST ADDRESSING MODE */ + C(0x010b, TAM, E, Z, 0, 0, 0, 0, tam, 0) + /* TEST AND SET */ C(0x9300, TS, S, Z, 0, a2, 0, 0, ts, 0) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 2d45132745..854a66ad79 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4068,6 +4068,16 @@ static ExitStatus op_svc(DisasContext *s, DisasOps *o) return EXIT_NORETURN; } +static ExitStatus op_tam(DisasContext *s, DisasOps *o) +{ + int cc = 0; + + cc |= (s->tb->flags & FLAG_MASK_64) ? 2 : 0; + cc |= (s->tb->flags & FLAG_MASK_32) ? 1 : 0; + gen_op_movi_cc(s, cc); + return NO_EXIT; +} + static ExitStatus op_tceb(DisasContext *s, DisasOps *o) { gen_helper_tceb(cc_op, cpu_env, o->in1, o->in2); From 76c574906ee33139db9b826ac2e2e96fb067c23f Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:05 +0200 Subject: [PATCH 45/70] target/s390x: implement PACK Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-7-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 5 +++++ target/s390x/mem_helper.c | 37 +++++++++++++++++++++++++++++++++++++ target/s390x/translate.c | 8 ++++++++ 4 files changed, 51 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 3f5a05d43b..c6fbc3b949 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -75,6 +75,7 @@ DEF_HELPER_FLAGS_2(sqeb, TCG_CALL_NO_WG, i64, env, i64) DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) 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(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64) 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 170b50ef2e..f92bfde4f8 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -639,6 +639,11 @@ C(0x9600, OI, SI, Z, m1_8u, i2_8u, new, m1_8, or, nz64) C(0xeb56, OIY, SIY, LD, m1_8u, i2_8u, new, m1_8, or, nz64) +/* PACK */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf200, PACK, SS_a, Z, la1, a2, 0, 0, pack, 0) + /* PREFETCH */ /* Implemented as nops of course. */ C(0xe336, PFD, RXY_b, GIE, 0, 0, 0, 0, 0, 0) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index ddbebcd7ae..850472e9ff 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -644,6 +644,43 @@ uint64_t HELPER(cksm)(CPUS390XState *env, uint64_t r1, return len; } +void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) +{ + uintptr_t ra = GETPC(); + int len_dest = len >> 4; + int len_src = len & 0xf; + uint8_t b; + + dest += len_dest; + src += len_src; + + /* last byte is special, it only flips the nibbles */ + b = cpu_ldub_data_ra(env, src, ra); + cpu_stb_data_ra(env, dest, (b << 4) | (b >> 4), ra); + src--; + len_src--; + + /* now pack every value */ + while (len_dest >= 0) { + b = 0; + + if (len_src > 0) { + b = cpu_ldub_data_ra(env, src, ra) & 0x0f; + src--; + len_src--; + } + if (len_src > 0) { + b |= cpu_ldub_data_ra(env, src, ra) << 4; + src--; + len_src--; + } + + len_dest--; + dest--; + cpu_stb_data_ra(env, dest, b, ra); + } +} + void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 854a66ad79..b3cc349150 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3144,6 +3144,14 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_pack(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + gen_helper_pack(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) { gen_helper_popcnt(o->out, o->in2); From 9c8be598364d9cfb618e44ee08a30071d9242aca Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:08 +0200 Subject: [PATCH 46/70] target/s390x: implement COMPARE AND SIGNAL These functions differ from COMPARE by generating an exception for a QNaN input. Use the non quiet version of floatXX_compare. Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-10-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/fpu_helper.c | 27 +++++++++++++++++++++++++++ target/s390x/helper.h | 3 +++ target/s390x/insn-data.def | 6 ++++++ target/s390x/translate.c | 21 +++++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c index e604e9f7be..26f124fe96 100644 --- a/target/s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c @@ -585,6 +585,33 @@ uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3) return RET128(ret); } +/* 32-bit FP compare and signal */ +uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) +{ + int cmp = float32_compare(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); +} + +/* 64-bit FP compare and signal */ +uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) +{ + int cmp = float64_compare(f1, f2, &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); +} + +/* 128-bit FP compare and signal */ +uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al, + uint64_t bh, uint64_t bl) +{ + int cmp = float128_compare(make_float128(ah, al), + make_float128(bh, bl), + &env->fpu_status); + handle_exceptions(env, GETPC()); + return float_comp_to_cc(env, cmp); +} + /* 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 c6fbc3b949..86e2bc185e 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -49,6 +49,9 @@ DEF_HELPER_FLAGS_3(lexb, TCG_CALL_NO_WG, i64, env, i64, i64) DEF_HELPER_FLAGS_3(ceb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_3(cdb, TCG_CALL_NO_WG_SE, i32, env, i64, i64) DEF_HELPER_FLAGS_5(cxb, TCG_CALL_NO_WG_SE, i32, env, i64, i64, i64, i64) +DEF_HELPER_FLAGS_3(keb, TCG_CALL_NO_WG, i32, env, i64, i64) +DEF_HELPER_FLAGS_3(kdb, TCG_CALL_NO_WG, i32, env, i64, i64) +DEF_HELPER_FLAGS_5(kxb, TCG_CALL_NO_WG, i32, env, i64, i64, i64, i64) DEF_HELPER_FLAGS_3(cgeb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(cgdb, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_4(cgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index f92bfde4f8..39fcce5891 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -154,6 +154,12 @@ C(0xb349, CXBR, RRE, Z, x1_o, x2_o, 0, 0, cxb, 0) C(0xed09, CEB, RXE, Z, e1, m2_32u, 0, 0, ceb, 0) C(0xed19, CDB, RXE, Z, f1_o, m2_64, 0, 0, cdb, 0) +/* COMPARE AND SIGNAL */ + C(0xb308, KEBR, RRE, Z, e1, e2, 0, 0, keb, 0) + C(0xb318, KDBR, RRE, Z, f1_o, f2_o, 0, 0, kdb, 0) + C(0xb348, KXBR, RRE, Z, x1_o, x2_o, 0, 0, kxb, 0) + C(0xed08, KEB, RXE, Z, e1, m2_32u, 0, 0, keb, 0) + C(0xed18, KDB, RXE, Z, f1_o, m2_64, 0, 0, kdb, 0) /* COMPARE IMMEDIATE */ C(0xc20d, CFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps32) C(0xc20c, CGFI, RIL_a, EI, r1, i2, 0, 0, 0, cmps64) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index b3cc349150..0a35eed6cf 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2374,6 +2374,27 @@ static ExitStatus op_iske(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_keb(DisasContext *s, DisasOps *o) +{ + gen_helper_keb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_kdb(DisasContext *s, DisasOps *o) +{ + gen_helper_kdb(cc_op, cpu_env, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_kxb(DisasContext *s, DisasOps *o) +{ + gen_helper_kxb(cc_op, cpu_env, o->out, o->out2, o->in1, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_laa(DisasContext *s, DisasOps *o) { /* The real output is indeed the original value in memory; From 6c9deca8a1f7008b551dedcc9bde599c428dfd07 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:09 +0200 Subject: [PATCH 47/70] target/s390x: implement MOVE INVERSE Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-11-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 12 ++++++++++++ target/s390x/translate.c | 8 ++++++++ 4 files changed, 23 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 86e2bc185e..4b6c75661f 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -3,6 +3,7 @@ DEF_HELPER_FLAGS_4(nc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(oc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(xc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(mvcin, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 39fcce5891..c1303d695d 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -570,6 +570,8 @@ C(0xe548, MVGHI, SIL, GIE, la1, i2, 0, m1_64, mov2, 0) C(0x9200, MVI, SI, Z, la1, i2, 0, m1_8, mov2, 0) C(0xeb52, MVIY, SIY, LD, la1, i2, 0, m1_8, mov2, 0) +/* MOVE INVERSE */ + C(0xe800, MVCIN, SS_a, Z, la1, a2, 0, 0, mvcin, 0) /* MOVE LONG */ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) /* MOVE LONG EXTENDED */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 850472e9ff..6faaaddfcc 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -231,6 +231,18 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) do_helper_mvc(env, l, dest, src, GETPC()); } +/* move inverse */ +void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +{ + uintptr_t ra = GETPC(); + int i; + + for (i = 0; i <= l; i++) { + uint8_t v = cpu_ldub_data_ra(env, src - i, ra); + cpu_stb_data_ra(env, dest + i, v, ra); + } +} + /* compare unsigned byte arrays */ static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2, uintptr_t ra) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 0a35eed6cf..a9b96e7e99 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2938,6 +2938,14 @@ static ExitStatus op_mvc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvcin(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + gen_helper_mvcin(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); From 256dab6fe8872a041823a18e78d7d7a86d0e9618 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:10 +0200 Subject: [PATCH 48/70] target/s390x: implement MOVE NUMERICS Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-12-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 13 +++++++++++++ target/s390x/translate.c | 8 ++++++++ 4 files changed, 24 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 4b6c75661f..5780bb5090 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -13,6 +13,7 @@ DEF_HELPER_FLAGS_3(divs64, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) +DEF_HELPER_FLAGS_4(mvn, 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_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_4(ex, void, env, i32, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index c1303d695d..cbb91bbe71 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -576,6 +576,8 @@ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) /* MOVE LONG EXTENDED */ C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) +/* MOVE NUMERICS */ + C(0xd100, MVN, SS_a, Z, la1, a2, 0, 0, mvn, 0) /* MOVE PAGE */ C(0xb254, MVPG, RRE, Z, r1_o, r2_o, 0, 0, mvpg, 0) /* MOVE STRING */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 6faaaddfcc..f80b7a5f06 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -243,6 +243,19 @@ void HELPER(mvcin)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) } } +/* move numerics */ +void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +{ + uintptr_t ra = GETPC(); + int i; + + for (i = 0; i <= l; i++) { + uint8_t v = cpu_ldub_data_ra(env, dest + i, ra) & 0xf0; + v |= cpu_ldub_data_ra(env, src + i, ra) & 0x0f; + cpu_stb_data_ra(env, dest + i, v, ra); + } +} + /* compare unsigned byte arrays */ static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2, uintptr_t ra) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index a9b96e7e99..7b42c0267d 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2988,6 +2988,14 @@ static ExitStatus op_mvcs(DisasContext *s, DisasOps *o) } #endif +static ExitStatus op_mvn(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + gen_helper_mvn(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) { gen_helper_mvpg(cc_op, cpu_env, regs[0], o->in1, o->in2); From fdc0a7474aa271bdcf88dd63008fb10d8a4b4824 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:11 +0200 Subject: [PATCH 49/70] target/s390x: implement MOVE WITH OFFSET Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-13-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 4 ++++ target/s390x/mem_helper.c | 31 +++++++++++++++++++++++++++++++ target/s390x/translate.c | 8 ++++++++ 4 files changed, 44 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 5780bb5090..385ce9af71 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -14,6 +14,7 @@ DEF_HELPER_FLAGS_4(divu64, TCG_CALL_NO_WG, i64, env, i64, i64, i64) DEF_HELPER_4(srst, i64, env, i64, i64, i64) DEF_HELPER_4(clst, i64, env, i64, i64, i64) 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_4(mvst, i64, env, i64, i64, i64) DEF_HELPER_4(ex, void, env, i32, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index cbb91bbe71..45aaf11e61 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -582,6 +582,10 @@ 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) +/* MOVE WITH OFFSET */ + /* Really format SS_b, but we pack both lengths into one argument + for the helper call, so we might as well leave one 8-bit field. */ + C(0xf100, MVO, SS_a, Z, la1, a2, 0, 0, mvo, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index f80b7a5f06..facac4b6d7 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -256,6 +256,37 @@ void HELPER(mvn)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) } } +/* move with offset */ +void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +{ + uintptr_t ra = GETPC(); + int len_dest = l >> 4; + int len_src = l & 0xf; + uint8_t byte_dest, byte_src; + int i; + + src += len_src; + dest += len_dest; + + /* Handle rightmost byte */ + byte_src = cpu_ldub_data_ra(env, src, ra); + byte_dest = cpu_ldub_data_ra(env, dest, ra); + byte_dest = (byte_dest & 0x0f) | (byte_src << 4); + cpu_stb_data_ra(env, dest, byte_dest, ra); + + /* Process remaining bytes from right to left */ + for (i = 1; i <= len_dest; i++) { + byte_dest = byte_src >> 4; + if (len_src - i >= 0) { + byte_src = cpu_ldub_data_ra(env, src - i, ra); + } else { + byte_src = 0; + } + byte_dest |= byte_src << 4; + cpu_stb_data_ra(env, dest - i, byte_dest, ra); + } +} + /* compare unsigned byte arrays */ static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2, uintptr_t ra) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 7b42c0267d..7be1c70837 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2996,6 +2996,14 @@ static ExitStatus op_mvn(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvo(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + gen_helper_mvo(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_mvpg(DisasContext *s, DisasOps *o) { gen_helper_mvpg(cc_op, cpu_env, regs[0], o->in1, o->in2); From 01f8db88579bef0b6de9f48d0ad2617c5ca2696f Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:12 +0200 Subject: [PATCH 50/70] target/s390x: implement MOVE ZONES Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-14-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 13 +++++++++++++ target/s390x/translate.c | 8 ++++++++ 4 files changed, 24 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 385ce9af71..a537e514f2 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -16,6 +16,7 @@ DEF_HELPER_4(clst, i64, env, i64, i64, i64) 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_4(ex, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 45aaf11e61..7fb2e257b3 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -586,6 +586,8 @@ /* Really format SS_b, but we pack both lengths into one argument for the helper call, so we might as well leave one 8-bit field. */ C(0xf100, MVO, SS_a, Z, la1, a2, 0, 0, mvo, 0) +/* MOVE ZONES */ + C(0xd300, MVZ, SS_a, Z, la1, a2, 0, 0, mvz, 0) /* MULTIPLY */ C(0x1c00, MR, RR_a, Z, r1p1_32s, r2_32s, new, r1_D32, mul, 0) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index facac4b6d7..10754dd52d 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -287,6 +287,19 @@ void HELPER(mvo)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) } } +/* move zones */ +void HELPER(mvz)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) +{ + uintptr_t ra = GETPC(); + int i; + + for (i = 0; i <= l; i++) { + uint8_t b = cpu_ldub_data_ra(env, dest + i, ra) & 0x0f; + b |= cpu_ldub_data_ra(env, src + i, ra) & 0xf0; + cpu_stb_data_ra(env, dest + i, b, ra); + } +} + /* compare unsigned byte arrays */ static uint32_t do_helper_clc(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2, uintptr_t ra) diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 7be1c70837..a21de0967a 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3019,6 +3019,14 @@ static ExitStatus op_mvst(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvz(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + gen_helper_mvz(cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_mul(DisasContext *s, DisasOps *o) { tcg_gen_mul_i64(o->out, o->in1, o->in2); From a5c3cedd739b7cf0aea051f9f70adf2bcf813e1a Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:13 +0200 Subject: [PATCH 51/70] target/s390x: improve 24-bit and 31-bit addresses read Improve fix_address to also handle the 24-bit mode. Rename fix_address to wrap_address to better explain what is changed. Replace the calls to get_address with x2 = 0 and b2 = 0 by call to wrap_address, leading to the removal of this function. Rename get_address_31fix into get_address. Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-15-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 71 +++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 10754dd52d..aba26beb8c 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -365,30 +365,23 @@ uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, return cc; } -static inline uint64_t fix_address(CPUS390XState *env, uint64_t a) +static inline uint64_t wrap_address(CPUS390XState *env, uint64_t a) { - /* 31-Bit mode */ if (!(env->psw.mask & PSW_MASK_64)) { - a &= 0x7fffffff; + if (!(env->psw.mask & PSW_MASK_32)) { + /* 24-Bit mode */ + a &= 0x00ffffff; + } else { + /* 31-Bit mode */ + a &= 0x7fffffff; + } } return a; } -static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) +static inline uint64_t get_address(CPUS390XState *env, int reg) { - uint64_t r = d2; - if (x2) { - r += env->regs[x2]; - } - if (b2) { - r += env->regs[b2]; - } - return fix_address(env, r); -} - -static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) -{ - return fix_address(env, env->regs[reg]); + return wrap_address(env, env->regs[reg]); } /* search string (c is byte to search, r2 is string, r1 end of string) */ @@ -399,8 +392,8 @@ uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, uint32_t len; uint8_t v, c = r0; - str = fix_address(env, str); - end = fix_address(env, end); + str = wrap_address(env, str); + end = wrap_address(env, end); /* Assume for now that R2 is unmodified. */ env->retxl = str; @@ -434,8 +427,8 @@ uint64_t HELPER(clst)(CPUS390XState *env, uint64_t c, uint64_t s1, uint64_t s2) uint32_t len; c = c & 0xff; - s1 = fix_address(env, s1); - s2 = fix_address(env, s2); + s1 = wrap_address(env, s1); + s2 = wrap_address(env, s2); /* 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. */ @@ -481,8 +474,8 @@ uint64_t HELPER(mvst)(CPUS390XState *env, uint64_t c, uint64_t d, uint64_t s) uint32_t len; c = c & 0xff; - d = fix_address(env, d); - s = fix_address(env, s); + 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. */ @@ -540,9 +533,9 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) { uintptr_t ra = GETPC(); uint64_t destlen = env->regs[r1 + 1] & 0xffffff; - uint64_t dest = get_address_31fix(env, r1); + uint64_t dest = get_address(env, r1); uint64_t srclen = env->regs[r2 + 1] & 0xffffff; - uint64_t src = get_address_31fix(env, r2); + uint64_t src = get_address(env, r2); uint8_t pad = env->regs[r2 + 1] >> 24; uint8_t v; uint32_t cc; @@ -583,9 +576,9 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, { uintptr_t ra = GETPC(); uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = env->regs[r1]; + uint64_t dest = get_address(env, r1); uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = env->regs[r3]; + uint64_t src = get_address(env, r3); uint8_t pad = a2 & 0xff; uint8_t v; uint32_t cc; @@ -593,8 +586,6 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, if (!(env->psw.mask & PSW_MASK_64)) { destlen = (uint32_t)destlen; srclen = (uint32_t)srclen; - dest &= 0x7fffffff; - src &= 0x7fffffff; } if (destlen == srclen) { @@ -634,9 +625,9 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, { uintptr_t ra = GETPC(); uint64_t destlen = env->regs[r1 + 1]; - uint64_t dest = get_address_31fix(env, r1); + uint64_t dest = get_address(env, r1); uint64_t srclen = env->regs[r3 + 1]; - uint64_t src = get_address_31fix(env, r3); + uint64_t src = get_address(env, r3); uint8_t pad = a2 & 0xff; uint32_t cc = 0; @@ -1020,7 +1011,7 @@ uint32_t HELPER(testblock)(CPUS390XState *env, uint64_t real_addr) uint64_t abs_addr; int i; - real_addr = fix_address(env, real_addr); + real_addr = wrap_address(env, real_addr); abs_addr = mmu_real2abs(env, real_addr) & TARGET_PAGE_MASK; if (!address_space_access_valid(&address_space_memory, abs_addr, TARGET_PAGE_SIZE, true)) { @@ -1054,7 +1045,7 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) { static S390SKeysState *ss; static S390SKeysClass *skeyclass; - uint64_t addr = get_address(env, 0, 0, r2); + uint64_t addr = wrap_address(env, r2); uint8_t key; if (addr > ram_size) { @@ -1077,7 +1068,7 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) { static S390SKeysState *ss; static S390SKeysClass *skeyclass; - uint64_t addr = get_address(env, 0, 0, r2); + uint64_t addr = wrap_address(env, r2); uint8_t key; if (addr > ram_size) { @@ -1234,14 +1225,14 @@ uint64_t HELPER(lura)(CPUS390XState *env, uint64_t addr) { CPUState *cs = CPU(s390_env_get_cpu(env)); - return (uint32_t)ldl_phys(cs->as, get_address(env, 0, 0, addr)); + return (uint32_t)ldl_phys(cs->as, wrap_address(env, addr)); } uint64_t HELPER(lurag)(CPUS390XState *env, uint64_t addr) { CPUState *cs = CPU(s390_env_get_cpu(env)); - return ldq_phys(cs->as, get_address(env, 0, 0, addr)); + return ldq_phys(cs->as, wrap_address(env, addr)); } /* store using real address */ @@ -1249,7 +1240,7 @@ void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint64_t v1) { CPUState *cs = CPU(s390_env_get_cpu(env)); - stl_phys(cs->as, get_address(env, 0, 0, addr), (uint32_t)v1); + stl_phys(cs->as, wrap_address(env, addr), (uint32_t)v1); if ((env->psw.mask & PSW_MASK_PER) && (env->cregs[9] & PER_CR9_EVENT_STORE) && @@ -1264,7 +1255,7 @@ void HELPER(sturg)(CPUS390XState *env, uint64_t addr, uint64_t v1) { CPUState *cs = CPU(s390_env_get_cpu(env)); - stq_phys(cs->as, get_address(env, 0, 0, addr), v1); + stq_phys(cs->as, wrap_address(env, addr), v1); if ((env->psw.mask & PSW_MASK_PER) && (env->cregs[9] & PER_CR9_EVENT_STORE) && @@ -1357,8 +1348,8 @@ void HELPER(ex)(CPUS390XState *env, uint32_t ilen, uint64_t r1, uint64_t addr) uint32_t d1 = extract64(insn, 32, 12); uint32_t b2 = extract64(insn, 28, 4); uint32_t d2 = extract64(insn, 16, 12); - uint64_t a1 = get_address(env, 0, b1, d1); - uint64_t a2 = get_address(env, 0, b2, d2); + uint64_t a1 = wrap_address(env, env->regs[b1] + d1); + uint64_t a2 = wrap_address(env, env->regs[b2] + d2); env->cc_op = helper(env, l, a1, a2, 0); env->psw.addr += ilen; From a65047afe5ef685f4ab310562f20950ce2dfb417 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:14 +0200 Subject: [PATCH 52/70] target/s390x: improve 24-bit and 31-bit addresses write Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-16-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index aba26beb8c..5f11e1e33e 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -384,6 +384,29 @@ static inline uint64_t get_address(CPUS390XState *env, int reg) return wrap_address(env, env->regs[reg]); } +static inline void set_address(CPUS390XState *env, int reg, uint64_t address) +{ + if (env->psw.mask & PSW_MASK_64) { + /* 64-Bit mode */ + env->regs[reg] = address; + } else { + if (!(env->psw.mask & PSW_MASK_32)) { + /* 24-Bit mode. According to the PoO it is implementation + dependent if bits 32-39 remain unchanged or are set to + zeros. Choose the former so that the function can also be + used for TRT. */ + env->regs[reg] = deposit64(env->regs[reg], 0, 24, address); + } else { + /* 31-Bit mode. According to the PoO it is implementation + dependent if bit 32 remains unchanged or is set to zero. + Choose the latter so that the function can also be used for + TRT. */ + address &= 0x7fffffff; + env->regs[reg] = deposit64(env->regs[reg], 0, 32, address); + } + } +} + /* search string (c is byte to search, r2 is string, r1 end of string) */ uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, uint64_t str) @@ -564,8 +587,8 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) env->regs[r1 + 1] = destlen; /* can't use srclen here, we trunc'ed it */ env->regs[r2 + 1] -= src - env->regs[r2]; - env->regs[r1] = dest; - env->regs[r2] = src; + set_address(env, r1, dest); + set_address(env, r2, src); return cc; } @@ -613,8 +636,8 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, /* can't use srclen here, we trunc'ed it */ /* FIXME: 31-bit mode! */ env->regs[r3 + 1] -= src - env->regs[r3]; - env->regs[r1] = dest; - env->regs[r3] = src; + set_address(env, r1, dest); + set_address(env, r3, src); return cc; } @@ -651,8 +674,8 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, env->regs[r1 + 1] = destlen; /* can't use srclen here, we trunc'ed it */ env->regs[r3 + 1] -= src - env->regs[r3]; - env->regs[r1] = dest; - env->regs[r3] = src; + set_address(env, r1, dest); + set_address(env, r3, src); return cc; } @@ -858,7 +881,7 @@ static uint32_t do_helper_trt(CPUS390XState *env, uint32_t len, uint64_t array, uint8_t sbyte = cpu_ldub_data_ra(env, trans + byte, ra); if (sbyte != 0) { - env->regs[1] = array + i; + set_address(env, 1, array + i); env->regs[2] = deposit64(env->regs[2], 0, 8, sbyte); return (i == len) ? 2 : 1; } From 29a58fd85f315b722c69f489aefd3f2913d3e42d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:15 +0200 Subject: [PATCH 53/70] target/s390x: improve 24-bit and 31-bit lengths read/write Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-17-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 47 +++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 5f11e1e33e..83c32c4dac 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -407,6 +407,31 @@ static inline void set_address(CPUS390XState *env, int reg, uint64_t address) } } +static inline uint64_t wrap_length(CPUS390XState *env, uint64_t length) +{ + if (!(env->psw.mask & PSW_MASK_64)) { + /* 24-Bit and 31-Bit mode */ + length &= 0x7fffffff; + } + return length; +} + +static inline uint64_t get_length(CPUS390XState *env, int reg) +{ + return wrap_length(env, env->regs[reg]); +} + +static inline void set_length(CPUS390XState *env, int reg, uint64_t length) +{ + if (env->psw.mask & PSW_MASK_64) { + /* 64-Bit mode */ + env->regs[reg] = length; + } else { + /* 24-Bit and 31-Bit mode */ + env->regs[reg] = deposit64(env->regs[reg], 0, 32, length); + } +} + /* search string (c is byte to search, r2 is string, r1 end of string) */ uint64_t HELPER(srst)(CPUS390XState *env, uint64_t r0, uint64_t end, uint64_t str) @@ -598,19 +623,14 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { uintptr_t ra = GETPC(); - uint64_t destlen = env->regs[r1 + 1]; + uint64_t destlen = get_length(env, r1 + 1); uint64_t dest = get_address(env, r1); - uint64_t srclen = env->regs[r3 + 1]; + uint64_t srclen = get_length(env, r3 + 1); uint64_t src = get_address(env, r3); uint8_t pad = a2 & 0xff; uint8_t v; uint32_t cc; - if (!(env->psw.mask & PSW_MASK_64)) { - destlen = (uint32_t)destlen; - srclen = (uint32_t)srclen; - } - if (destlen == srclen) { cc = 0; } else if (destlen < srclen) { @@ -632,10 +652,9 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, cpu_stb_data_ra(env, dest, pad, ra); } - env->regs[r1 + 1] = destlen; + set_length(env, r1 + 1 , destlen); /* can't use srclen here, we trunc'ed it */ - /* FIXME: 31-bit mode! */ - env->regs[r3 + 1] -= src - env->regs[r3]; + set_length(env, r3 + 1, env->regs[r3 + 1] - src - env->regs[r3]); set_address(env, r1, dest); set_address(env, r3, src); @@ -647,9 +666,9 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { uintptr_t ra = GETPC(); - uint64_t destlen = env->regs[r1 + 1]; + uint64_t destlen = get_length(env, r1 + 1); uint64_t dest = get_address(env, r1); - uint64_t srclen = env->regs[r3 + 1]; + uint64_t srclen = get_length(env, r3 + 1); uint64_t src = get_address(env, r3); uint8_t pad = a2 & 0xff; uint32_t cc = 0; @@ -671,9 +690,9 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, } } - env->regs[r1 + 1] = destlen; + set_length(env, r1 + 1, destlen); /* can't use srclen here, we trunc'ed it */ - env->regs[r3 + 1] -= src - env->regs[r3]; + set_length(env, r3 + 1, env->regs[r3 + 1] - src - env->regs[r3]); set_address(env, r1, dest); set_address(env, r3, src); From 84aa07f109f0afaeeec63c159f3a578b955c3de9 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:16 +0200 Subject: [PATCH 54/70] target/s390x: fix COMPARE LOGICAL LONG EXTENDED There are multiple issues with the COMPARE LOGICAL LONG EXTENDED instruction: - The test between the two operands is inverted, leading to an inversion of the cc values 1 and 2. - The address and length of an operand continue to be decreased after reaching the end of this operand. These values are then wrong write back to the registers. - We should limit the amount of bytes to process, so that interrupts can be served correctly. At the same time rename dest into src1 and src into src3 to match the operand names and make the code less confusing. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-18-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 54 +++++++++++++++++++++++++++------------ target/s390x/translate.c | 20 +++++++++++---- 2 files changed, 52 insertions(+), 22 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 83c32c4dac..e30020c8e9 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -666,35 +666,55 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { uintptr_t ra = GETPC(); - uint64_t destlen = get_length(env, r1 + 1); - uint64_t dest = get_address(env, r1); - uint64_t srclen = get_length(env, r3 + 1); - uint64_t src = get_address(env, r3); + uint64_t src1len = get_length(env, r1 + 1); + uint64_t src1 = get_address(env, r1); + uint64_t src3len = get_length(env, r3 + 1); + uint64_t src3 = get_address(env, r3); uint8_t pad = a2 & 0xff; + uint64_t len = MAX(src1len, src3len); uint32_t cc = 0; - if (!(destlen || srclen)) { + if (!len) { return cc; } - if (srclen > destlen) { - srclen = destlen; + /* 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 (len > 0x2000) { + len = 0x2000; + cc = 3; } - for (; destlen || srclen; src++, dest++, destlen--, srclen--) { - uint8_t v1 = srclen ? cpu_ldub_data_ra(env, src, ra) : pad; - uint8_t v2 = destlen ? cpu_ldub_data_ra(env, dest, ra) : pad; - if (v1 != v2) { - cc = (v1 < v2) ? 1 : 2; + for (; len; len--) { + uint8_t v1 = pad; + uint8_t v3 = pad; + + if (src1len) { + v1 = cpu_ldub_data_ra(env, src1, ra); + } + if (src3len) { + v3 = cpu_ldub_data_ra(env, src3, ra); + } + + if (v1 != v3) { + cc = (v1 < v3) ? 1 : 2; break; } + + if (src1len) { + src1++; + src1len--; + } + if (src3len) { + src3++; + src3len--; + } } - set_length(env, r1 + 1, destlen); - /* can't use srclen here, we trunc'ed it */ - set_length(env, r3 + 1, env->regs[r3 + 1] - src - env->regs[r3]); - set_address(env, r1, dest); - set_address(env, r3, src); + set_length(env, r1 + 1, src1len); + set_length(env, r3 + 1, src3len); + set_address(env, r1, src1); + set_address(env, r3, src3); return cc; } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index a21de0967a..ecd0a91c04 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1922,11 +1922,21 @@ static ExitStatus op_clc(DisasContext *s, DisasOps *o) static ExitStatus op_clcle(DisasContext *s, DisasOps *o) { - TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); - TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - gen_helper_clcle(cc_op, cpu_env, r1, o->in2, r3); - tcg_temp_free_i32(r1); - tcg_temp_free_i32(r3); + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i32 t1, t3; + + /* r1 and r3 must be even. */ + if (r1 & 1 || r3 & 1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + + t1 = tcg_const_i32(r1); + t3 = tcg_const_i32(r3); + gen_helper_clcle(cc_op, cpu_env, t1, o->in2, t3); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t3); set_cc_static(s); return NO_EXIT; } From 5c2b48a8f0d02acfcb577abdbd5f3040d61455d9 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:17 +0200 Subject: [PATCH 55/70] target/s390x: implement COMPARE LOGICAL LONG As CLCL and CLCLE mostly differ by their operands, use a common do_clcl helper. Another difference is that CLCL is not interruptible. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-19-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 + target/s390x/mem_helper.c | 114 ++++++++++++++++++++++++------------- target/s390x/translate.c | 21 +++++++ 4 files changed, 99 insertions(+), 39 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index a537e514f2..a06e276870 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -6,6 +6,7 @@ DEF_HELPER_FLAGS_4(mvc, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(mvcin, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(clc, TCG_CALL_NO_WG, i32, env, i32, i64, i64) DEF_HELPER_3(mvcl, i32, env, i32, i32) +DEF_HELPER_3(clcl, i32, env, i32, i32) DEF_HELPER_FLAGS_4(clm, TCG_CALL_NO_WG, i32, env, i32, i32, i64) DEF_HELPER_FLAGS_3(divs32, TCG_CALL_NO_WG, s64, env, s64, s64) DEF_HELPER_FLAGS_3(divu32, TCG_CALL_NO_WG, i64, env, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 7fb2e257b3..e30b1b9753 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -216,6 +216,8 @@ C(0xc60e, CLGFRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu64) C(0xc607, CLHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu32) C(0xc606, CLGHRL, RIL_b, GIE, r1_o, mri2_16u, 0, 0, 0, cmpu64) +/* COMPARE LOGICAL LONG */ + C(0x0f00, CLCL, RR_a, Z, 0, 0, 0, 0, clcl, 0) /* COMPARE LOGICAL LONG EXTENDED */ C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) /* COMPARE LOGICAL CHARACTERS UNDER MASK */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index e30020c8e9..4ed0b65751 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -661,6 +661,78 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, return cc; } +/* compare logical long helper */ +static inline uint32_t do_clcl(CPUS390XState *env, + uint64_t *src1, uint64_t *src1len, + uint64_t *src3, uint64_t *src3len, + uint8_t pad, uint64_t limit, + uintptr_t ra) +{ + uint64_t len = MAX(*src1len, *src3len); + uint32_t cc = 0; + + if (!len) { + return cc; + } + + /* Lest we fail to service interrupts in a timely manner, limit the + amount of work we're willing to do. */ + if (len > limit) { + len = limit; + cc = 3; + } + + for (; len; len--) { + uint8_t v1 = pad; + uint8_t v3 = pad; + + if (*src1len) { + v1 = cpu_ldub_data_ra(env, *src1, ra); + } + if (*src3len) { + v3 = cpu_ldub_data_ra(env, *src3, ra); + } + + if (v1 != v3) { + cc = (v1 < v3) ? 1 : 2; + break; + } + + if (*src1len) { + *src1 += 1; + *src1len -= 1; + } + if (*src3len) { + *src3 += 1; + *src3len -= 1; + } + } + + return cc; +} + + +/* compare logical long */ +uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) +{ + uintptr_t ra = GETPC(); + uint64_t src1len = extract64(env->regs[r1 + 1], 0, 24); + uint64_t src1 = get_address(env, r1); + uint64_t src3len = extract64(env->regs[r2 + 1], 0, 24); + uint64_t src3 = get_address(env, r2); + uint8_t pad = env->regs[r2 + 1] >> 24; + uint32_t cc; + + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, ra); + + env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len); + env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len); + set_address(env, r1, src1); + set_address(env, r2, src3); + + return cc; +} + /* compare logical long extended memcompare insn with padding */ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) @@ -670,46 +742,10 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint64_t src1 = get_address(env, r1); uint64_t src3len = get_length(env, r3 + 1); uint64_t src3 = get_address(env, r3); - uint8_t pad = a2 & 0xff; - uint64_t len = MAX(src1len, src3len); - uint32_t cc = 0; + uint8_t pad = a2; + uint32_t cc; - if (!len) { - return cc; - } - - /* 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 (len > 0x2000) { - len = 0x2000; - cc = 3; - } - - for (; len; len--) { - uint8_t v1 = pad; - uint8_t v3 = pad; - - if (src1len) { - v1 = cpu_ldub_data_ra(env, src1, ra); - } - if (src3len) { - v3 = cpu_ldub_data_ra(env, src3, ra); - } - - if (v1 != v3) { - cc = (v1 < v3) ? 1 : 2; - break; - } - - if (src1len) { - src1++; - src1len--; - } - if (src3len) { - src3++; - src3len--; - } - } + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, ra); set_length(env, r1 + 1, src1len); set_length(env, r3 + 1, src3len); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index ecd0a91c04..2d47f1d2b4 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1920,6 +1920,27 @@ static ExitStatus op_clc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clcl(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r2 = get_field(s->fields, r2); + TCGv_i32 t1, t2; + + /* r1 and r2 must be even. */ + if (r1 & 1 || r2 & 1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + + t1 = tcg_const_i32(r1); + t2 = tcg_const_i32(r2); + gen_helper_clcl(cc_op, cpu_env, t1, t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_clcle(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); From 22f04c31980c63c6f842135679b104f0d87d4613 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:18 +0200 Subject: [PATCH 56/70] target/s390x: fix adj_len_to_page adj_len_to_page doesn't return the correct result when the address is already page aligned and the length is bigger than a page. Fix that. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-20-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 4ed0b65751..2326f0bdb9 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -61,7 +61,7 @@ static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr) { #ifndef CONFIG_USER_ONLY if ((addr & ~TARGET_PAGE_MASK) + len - 1 >= TARGET_PAGE_SIZE) { - return -addr & ~TARGET_PAGE_MASK; + return -(addr | TARGET_PAGE_MASK); } #endif return len; From d33271213437ed1834b0a50540d79e877e1cd894 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:19 +0200 Subject: [PATCH 57/70] target/s390x: improve MOVE LONG and MOVE LONG EXTENDED As MVCL and MVCLE only differ by their operands, use a common do_mvcl helper. Optimize it calling fast_memmove and fast_memset. Correctly write back addresses. Check that r1 and r2/r3 registers are even. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-21-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 90 +++++++++++++++++---------------------- target/s390x/translate.c | 40 ++++++++++++----- 2 files changed, 70 insertions(+), 60 deletions(-) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 2326f0bdb9..3b2ff09fec 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -576,6 +576,38 @@ void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) } } +/* move long helper */ +static inline uint32_t do_mvcl(CPUS390XState *env, + uint64_t *dest, uint64_t *destlen, + uint64_t *src, uint64_t *srclen, + uint8_t pad, uintptr_t ra) +{ + uint64_t len = MIN(*srclen, *destlen); + uint32_t cc; + + if (*destlen == *srclen) { + cc = 0; + } else if (*destlen < *srclen) { + cc = 1; + } else { + cc = 2; + } + + /* Copy the src array */ + fast_memmove(env, *dest, *src, len, ra); + *src += len; + *srclen -= len; + *dest += len; + *destlen -= len; + + /* Pad the remaining area */ + fast_memset(env, *dest, pad, *destlen, ra); + *dest += *destlen; + *destlen = 0; + + return cc; +} + /* move long */ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) { @@ -585,40 +617,19 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) uint64_t srclen = env->regs[r2 + 1] & 0xffffff; uint64_t src = get_address(env, r2); uint8_t pad = env->regs[r2 + 1] >> 24; - uint8_t v; uint32_t cc; - if (destlen == srclen) { - cc = 0; - } else if (destlen < srclen) { - cc = 1; - } else { - cc = 2; - } + cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, ra); - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = cpu_ldub_data_ra(env, src, ra); - cpu_stb_data_ra(env, dest, v, ra); - } - - for (; destlen; dest++, destlen--) { - cpu_stb_data_ra(env, dest, pad, ra); - } - - env->regs[r1 + 1] = destlen; - /* can't use srclen here, we trunc'ed it */ - env->regs[r2 + 1] -= src - env->regs[r2]; + env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen); + env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen); set_address(env, r1, dest); set_address(env, r2, src); return cc; } -/* move long extended another memcopy insn with more bells and whistles */ +/* move long extended */ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) { @@ -627,34 +638,13 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint64_t dest = get_address(env, r1); uint64_t srclen = get_length(env, r3 + 1); uint64_t src = get_address(env, r3); - uint8_t pad = a2 & 0xff; - uint8_t v; + uint8_t pad = a2; uint32_t cc; - if (destlen == srclen) { - cc = 0; - } else if (destlen < srclen) { - cc = 1; - } else { - cc = 2; - } + cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, ra); - if (srclen > destlen) { - srclen = destlen; - } - - for (; destlen && srclen; src++, dest++, destlen--, srclen--) { - v = cpu_ldub_data_ra(env, src, ra); - cpu_stb_data_ra(env, dest, v, ra); - } - - for (; destlen; dest++, destlen--) { - cpu_stb_data_ra(env, dest, pad, ra); - } - - set_length(env, r1 + 1 , destlen); - /* can't use srclen here, we trunc'ed it */ - set_length(env, r3 + 1, env->regs[r3 + 1] - src - env->regs[r3]); + set_length(env, r1 + 1, destlen); + set_length(env, r3 + 1, srclen); set_address(env, r1, dest); set_address(env, r3, src); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 2d47f1d2b4..c131f67a60 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2979,22 +2979,42 @@ static ExitStatus op_mvcin(DisasContext *s, DisasOps *o) static ExitStatus op_mvcl(DisasContext *s, DisasOps *o) { - TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); - TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); - gen_helper_mvcl(cc_op, cpu_env, r1, r2); - tcg_temp_free_i32(r1); - tcg_temp_free_i32(r2); + int r1 = get_field(s->fields, r1); + int r2 = get_field(s->fields, r2); + TCGv_i32 t1, t2; + + /* r1 and r2 must be even. */ + if (r1 & 1 || r2 & 1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + + t1 = tcg_const_i32(r1); + t2 = tcg_const_i32(r2); + gen_helper_mvcl(cc_op, cpu_env, t1, t2); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t2); set_cc_static(s); return NO_EXIT; } static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) { - TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); - TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); - gen_helper_mvcle(cc_op, cpu_env, r1, o->in2, r3); - tcg_temp_free_i32(r1); - tcg_temp_free_i32(r3); + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i32 t1, t3; + + /* r1 and r3 must be even. */ + if (r1 & 1 || r3 & 1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + + t1 = tcg_const_i32(r1); + t3 = tcg_const_i32(r3); + gen_helper_mvcle(cc_op, cpu_env, t1, o->in2, t3); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t3); set_cc_static(s); return NO_EXIT; } From 31006af3bb6615a0a9ae3f0b476e4ebc9fa0045a Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:20 +0200 Subject: [PATCH 58/70] target/s390x: implement COMPARE LOGICAL LONG UNICODE For that we need to make program_interrupt available to qemu-user. Fortunately there is almost nothing to change as both kvm_enabled and CONFIG_KVM evaluate to false in that case. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-22-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 + target/s390x/mem_helper.c | 76 +++++++++++++++++++++++++++++++------- target/s390x/misc_helper.c | 4 +- target/s390x/translate.c | 22 +++++++++++ 5 files changed, 90 insertions(+), 15 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index a06e276870..b672c3b269 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -24,6 +24,7 @@ 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) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) +DEF_HELPER_4(clclu, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) DEF_HELPER_3(cdgb, i64, env, s64, i32) DEF_HELPER_3(cxgb, i64, env, s64, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index e30b1b9753..a6aaf50ab3 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -220,6 +220,8 @@ C(0x0f00, CLCL, RR_a, Z, 0, 0, 0, 0, clcl, 0) /* COMPARE LOGICAL LONG EXTENDED */ C(0xa900, CLCLE, RS_a, Z, 0, a2, 0, 0, clcle, 0) +/* COMPARE LOGICAL LONG UNICODE */ + C(0xeb8f, CLCLU, RSY_a, E2, 0, a2, 0, 0, clclu, 0) /* COMPARE LOGICAL CHARACTERS UNDER MASK */ C(0xbd00, CLM, RS_b, Z, r1_o, a2, 0, 0, clm, 0) C(0xeb21, CLMY, RSY_b, LD, r1_o, a2, 0, 0, clm, 0) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 3b2ff09fec..4a7c66cd2c 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -67,6 +67,32 @@ static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr) return len; } +/* Trigger a SPECIFICATION exception if an address or a length is not + naturally aligned. */ +static inline void check_alignment(CPUS390XState *env, uint64_t v, + int wordsize, uintptr_t ra) +{ + if (v % wordsize) { + CPUState *cs = CPU(s390_env_get_cpu(env)); + cpu_restore_state(cs, ra); + program_interrupt(env, PGM_SPECIFICATION, 6); + } +} + +/* Load a value from memory according to its size. */ +static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr, + int wordsize, uintptr_t ra) +{ + switch (wordsize) { + case 1: + return cpu_ldub_data_ra(env, addr, ra); + case 2: + return cpu_lduw_data_ra(env, addr, ra); + default: + abort(); + } +} + static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, uint32_t l, uintptr_t ra) { @@ -655,12 +681,14 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, static inline uint32_t do_clcl(CPUS390XState *env, uint64_t *src1, uint64_t *src1len, uint64_t *src3, uint64_t *src3len, - uint8_t pad, uint64_t limit, - uintptr_t ra) + uint16_t pad, uint64_t limit, + int wordsize, uintptr_t ra) { uint64_t len = MAX(*src1len, *src3len); uint32_t cc = 0; + check_alignment(env, *src1len | *src3len, wordsize, ra); + if (!len) { return cc; } @@ -672,15 +700,15 @@ static inline uint32_t do_clcl(CPUS390XState *env, cc = 3; } - for (; len; len--) { - uint8_t v1 = pad; - uint8_t v3 = pad; + for (; len; len -= wordsize) { + uint16_t v1 = pad; + uint16_t v3 = pad; if (*src1len) { - v1 = cpu_ldub_data_ra(env, *src1, ra); + v1 = cpu_ldusize_data_ra(env, *src1, wordsize, ra); } if (*src3len) { - v3 = cpu_ldub_data_ra(env, *src3, ra); + v3 = cpu_ldusize_data_ra(env, *src3, wordsize, ra); } if (v1 != v3) { @@ -689,12 +717,12 @@ static inline uint32_t do_clcl(CPUS390XState *env, } if (*src1len) { - *src1 += 1; - *src1len -= 1; + *src1 += wordsize; + *src1len -= wordsize; } if (*src3len) { - *src3 += 1; - *src3len -= 1; + *src3 += wordsize; + *src3len -= wordsize; } } @@ -713,7 +741,7 @@ uint32_t HELPER(clcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) uint8_t pad = env->regs[r2 + 1] >> 24; uint32_t cc; - cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, ra); + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, -1, 1, ra); env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, src1len); env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, src3len); @@ -735,7 +763,29 @@ uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint8_t pad = a2; uint32_t cc; - cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, ra); + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x2000, 1, ra); + + set_length(env, r1 + 1, src1len); + set_length(env, r3 + 1, src3len); + set_address(env, r1, src1); + set_address(env, r3, src3); + + return cc; +} + +/* compare logical long unicode memcompare insn with padding */ +uint32_t HELPER(clclu)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) +{ + uintptr_t ra = GETPC(); + uint64_t src1len = get_length(env, r1 + 1); + uint64_t src1 = get_address(env, r1); + uint64_t src3len = get_length(env, r3 + 1); + uint64_t src3 = get_address(env, r3); + uint16_t pad = a2; + uint32_t cc = 0; + + cc = do_clcl(env, &src1, &src1len, &src3, &src3len, pad, 0x1000, 2, ra); set_length(env, r1 + 1, src1len); set_length(env, r3 + 1, src3len); diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 1b9f448875..edcdf17db6 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -80,8 +80,6 @@ void HELPER(exception)(CPUS390XState *env, uint32_t excp) cpu_loop_exit(cs); } -#ifndef CONFIG_USER_ONLY - void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) { S390CPU *cpu = s390_env_get_cpu(env); @@ -108,6 +106,8 @@ void program_interrupt(CPUS390XState *env, uint32_t code, int ilen) } } +#ifndef CONFIG_USER_ONLY + /* SCLP service call */ uint32_t HELPER(servc)(CPUS390XState *env, uint64_t r1, uint64_t r2) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index c131f67a60..d371d45f8f 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -1205,6 +1205,7 @@ typedef enum DisasFacility { FAC_ILA, /* interlocked access facility 1 */ FAC_LPP, /* load-program-parameter */ FAC_DAT_ENH, /* DAT-enhancement */ + FAC_E2, /* extended-translation facility 2 */ } DisasFacility; struct DisasInsn { @@ -1962,6 +1963,27 @@ static ExitStatus op_clcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_clclu(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i32 t1, t3; + + /* r1 and r3 must be even. */ + if (r1 & 1 || r3 & 1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + + t1 = tcg_const_i32(r1); + t3 = tcg_const_i32(r3); + gen_helper_clclu(cc_op, cpu_env, t1, o->in2, t3); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t3); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_clm(DisasContext *s, DisasOps *o) { TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); From 16f2e4b841799c6a25631753a495ea2c82510651 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:21 +0200 Subject: [PATCH 59/70] target/s390x: implement MOVE LONG UNICODE Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-23-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 47 +++++++++++++++++++++++++++++++++----- target/s390x/translate.c | 21 +++++++++++++++++ 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index b672c3b269..8ce5e3f802 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -23,6 +23,7 @@ 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) DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) +DEF_HELPER_4(mvclu, i32, env, i32, i64, i32) DEF_HELPER_4(clcle, i32, env, i32, i64, i32) DEF_HELPER_4(clclu, i32, env, i32, i64, i32) DEF_HELPER_3(cegb, i64, env, s64, i32) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index a6aaf50ab3..d16857a6a1 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -580,6 +580,8 @@ C(0x0e00, MVCL, RR_a, Z, 0, 0, 0, 0, mvcl, 0) /* MOVE LONG EXTENDED */ C(0xa800, MVCLE, RS_a, Z, 0, a2, 0, 0, mvcle, 0) +/* MOVE LONG UNICODE */ + C(0xeb8e, MVCLU, RSY_a, E2, 0, a2, 0, 0, mvclu, 0) /* MOVE NUMERICS */ C(0xd100, MVN, SS_a, Z, la1, a2, 0, 0, mvn, 0) /* MOVE PAGE */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 4a7c66cd2c..581f10760b 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -606,7 +606,7 @@ void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) static inline uint32_t do_mvcl(CPUS390XState *env, uint64_t *dest, uint64_t *destlen, uint64_t *src, uint64_t *srclen, - uint8_t pad, uintptr_t ra) + uint16_t pad, int wordsize, uintptr_t ra) { uint64_t len = MIN(*srclen, *destlen); uint32_t cc; @@ -627,9 +627,22 @@ static inline uint32_t do_mvcl(CPUS390XState *env, *destlen -= len; /* Pad the remaining area */ - fast_memset(env, *dest, pad, *destlen, ra); - *dest += *destlen; - *destlen = 0; + if (wordsize == 1) { + fast_memset(env, *dest, pad, *destlen, ra); + *dest += *destlen; + *destlen = 0; + } else { + /* If remaining length is odd, pad with odd byte first. */ + if (*destlen & 1) { + cpu_stb_data_ra(env, *dest, pad & 0xff, ra); + *dest += 1; + *destlen -= 1; + } + /* The remaining length is even, pad using words. */ + for (; *destlen; *dest += 2, *destlen -= 2) { + cpu_stw_data_ra(env, *dest, pad, ra); + } + } return cc; } @@ -645,7 +658,7 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) uint8_t pad = env->regs[r2 + 1] >> 24; uint32_t cc; - cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, ra); + cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra); env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen); env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen); @@ -667,7 +680,29 @@ uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint8_t pad = a2; uint32_t cc; - cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, ra); + cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra); + + set_length(env, r1 + 1, destlen); + set_length(env, r3 + 1, srclen); + set_address(env, r1, dest); + set_address(env, r3, src); + + return cc; +} + +/* move long unicode */ +uint32_t HELPER(mvclu)(CPUS390XState *env, uint32_t r1, uint64_t a2, + uint32_t r3) +{ + uintptr_t ra = GETPC(); + uint64_t destlen = get_length(env, r1 + 1); + uint64_t dest = get_address(env, r1); + uint64_t srclen = get_length(env, r3 + 1); + uint64_t src = get_address(env, r3); + uint16_t pad = a2; + uint32_t cc; + + cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 2, ra); set_length(env, r1 + 1, destlen); set_length(env, r3 + 1, srclen); diff --git a/target/s390x/translate.c b/target/s390x/translate.c index d371d45f8f..4f1a50e4fe 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3041,6 +3041,27 @@ static ExitStatus op_mvcle(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mvclu(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int r3 = get_field(s->fields, r3); + TCGv_i32 t1, t3; + + /* r1 and r3 must be even. */ + if (r1 & 1 || r3 & 1) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + + t1 = tcg_const_i32(r1); + t3 = tcg_const_i32(r3); + gen_helper_mvclu(cc_op, cpu_env, t1, o->in2, t3); + tcg_temp_free_i32(t1); + tcg_temp_free_i32(t3); + set_cc_static(s); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_mvcp(DisasContext *s, DisasOps *o) { From 3bd3d6d302bd5a86a103a228b6d708025db4dcc2 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:22 +0200 Subject: [PATCH 60/70] target/s390x: implement PACK ASCII Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-24-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 35 +++++++++++++++++++++++++++++++++++ target/s390x/translate.c | 16 ++++++++++++++++ 4 files changed, 54 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 8ce5e3f802..61f3ead1bc 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -86,6 +86,7 @@ DEF_HELPER_FLAGS_2(sqdb, TCG_CALL_NO_WG, i64, env, i64) 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(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32) 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index d16857a6a1..a5063a4cfb 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -665,6 +665,8 @@ /* Really format SS_b, but we pack both lengths into one argument for the helper call, so we might as well leave one 8-bit field. */ C(0xf200, PACK, SS_a, Z, la1, a2, 0, 0, pack, 0) +/* PACK ASCII */ + C(0xe900, PKA, SS_f, E2, la1, a2, 0, 0, pka, 0) /* PREFETCH */ /* Implemented as nops of course. */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 581f10760b..4cf96c8485 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -914,6 +914,41 @@ void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) } } +void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src, + uint32_t srclen) +{ + uintptr_t ra = GETPC(); + int i; + /* The destination operand is always 16 bytes long. */ + const int destlen = 16; + + /* The operands are processed from right to left. */ + src += srclen - 1; + dest += destlen - 1; + + for (i = 0; i < destlen; i++) { + uint8_t b = 0; + + /* Start with a positive sign */ + if (i == 0) { + b = 0xc; + } else if (srclen > 1) { + b = cpu_ldub_data_ra(env, src, ra) & 0x0f; + src--; + srclen--; + } + + if (srclen > 1) { + b |= cpu_ldub_data_ra(env, src, ra) << 4; + src--; + srclen--; + } + + cpu_stb_data_ra(env, dest, b, ra); + dest--; + } +} + void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 4f1a50e4fe..493931147d 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3299,6 +3299,22 @@ static ExitStatus op_pack(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_pka(DisasContext *s, DisasOps *o) +{ + int l2 = get_field(s->fields, l2) + 1; + TCGv_i32 l; + + /* The length must not exceed 32 bytes. */ + if (l2 > 32) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + l = tcg_const_i32(l2); + gen_helper_pka(cpu_env, o->addr1, o->in2, l); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) { gen_helper_popcnt(o->out, o->in2); From 4e256bef6552ee0b4c0c844077b44e4c7fcc05fc Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:23 +0200 Subject: [PATCH 61/70] target/s390x: implement PACK UNICODE Use a common helper with PACK ASCII as the differences are limited to the stride of the source operand. Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-25-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 30 +++++++++++++++++++++--------- target/s390x/translate.c | 16 ++++++++++++++++ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 61f3ead1bc..cda7f7f08e 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -87,6 +87,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(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(pku, TCG_CALL_NO_WG, void, env, i64, i64, i32) 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index a5063a4cfb..1b487c30ef 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -667,6 +667,8 @@ C(0xf200, PACK, SS_a, Z, la1, a2, 0, 0, pack, 0) /* PACK ASCII */ C(0xe900, PKA, SS_f, E2, la1, a2, 0, 0, pka, 0) +/* PACK UNICODE */ + C(0xe100, PKU, SS_f, E2, la1, a2, 0, 0, pku, 0) /* PREFETCH */ /* Implemented as nops of course. */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 4cf96c8485..218f1ab1fd 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -914,10 +914,9 @@ void HELPER(pack)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) } } -void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src, - uint32_t srclen) +static inline void do_pkau(CPUS390XState *env, uint64_t dest, uint64_t src, + uint32_t srclen, int ssize, uintptr_t ra) { - uintptr_t ra = GETPC(); int i; /* The destination operand is always 16 bytes long. */ const int destlen = 16; @@ -932,16 +931,16 @@ void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src, /* Start with a positive sign */ if (i == 0) { b = 0xc; - } else if (srclen > 1) { + } else if (srclen > ssize) { b = cpu_ldub_data_ra(env, src, ra) & 0x0f; - src--; - srclen--; + src -= ssize; + srclen -= ssize; } - if (srclen > 1) { + if (srclen > ssize) { b |= cpu_ldub_data_ra(env, src, ra) << 4; - src--; - srclen--; + src -= ssize; + srclen -= ssize; } cpu_stb_data_ra(env, dest, b, ra); @@ -949,6 +948,19 @@ void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src, } } + +void HELPER(pka)(CPUS390XState *env, uint64_t dest, uint64_t src, + uint32_t srclen) +{ + do_pkau(env, dest, src, srclen, 1, GETPC()); +} + +void HELPER(pku)(CPUS390XState *env, uint64_t dest, uint64_t src, + uint32_t srclen) +{ + do_pkau(env, dest, src, srclen, 2, GETPC()); +} + void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, uint64_t src) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 493931147d..7e01c40394 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3315,6 +3315,22 @@ static ExitStatus op_pka(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_pku(DisasContext *s, DisasOps *o) +{ + int l2 = get_field(s->fields, l2) + 1; + TCGv_i32 l; + + /* The length must be even and should not exceed 64 bytes. */ + if ((l2 & 1) || (l2 > 64)) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + l = tcg_const_i32(l2); + gen_helper_pku(cpu_env, o->addr1, o->in2, l); + tcg_temp_free_i32(l); + return NO_EXIT; +} + static ExitStatus op_popcnt(DisasContext *s, DisasOps *o) { gen_helper_popcnt(o->out, o->in2); From 1a35f08a222f33e1ef5890c8acf0a862df5a56aa Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:24 +0200 Subject: [PATCH 62/70] target/s390x: implement UNPACK ASCII Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-26-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 51 ++++++++++++++++++++++++++++++++++++++ target/s390x/translate.c | 17 +++++++++++++ 4 files changed, 71 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index cda7f7f08e..c21be5094b 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -89,6 +89,7 @@ DEF_HELPER_FLAGS_4(pack, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(pku, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) +DEF_HELPER_FLAGS_4(unpka, TCG_CALL_NO_WG, i32, env, i64, i32, 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 1b487c30ef..1782e2f3ac 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -871,6 +871,8 @@ /* Really format SS_b, but we pack both lengths into one argument for the helper call, so we might as well leave one 8-bit field. */ C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) +/* UNPACK ASCII */ + C(0xea00, UNPKA, SS_a, E2, la1, a2, 0, 0, unpka, 0) #ifndef CONFIG_USER_ONLY /* COMPARE AND SWAP AND PURGE */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 218f1ab1fd..b87e41764f 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1008,6 +1008,57 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, } } +uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen, + uint64_t src) +{ + uintptr_t ra = GETPC(); + int i; + uint32_t cc; + uint8_t b; + /* The source operand is always 16 bytes long. */ + const int srclen = 16; + + /* The operands are processed from right to left. */ + src += srclen - 1; + dest += destlen - 1; + + /* Check for the sign. */ + b = cpu_ldub_data_ra(env, src, ra); + src--; + switch (b & 0xf) { + case 0xa: + case 0xc: + case 0xe ... 0xf: + cc = 0; /* plus */ + break; + case 0xb: + case 0xd: + cc = 1; /* minus */ + break; + default: + case 0x0 ... 0x9: + cc = 3; /* invalid */ + break; + } + + /* Now pad every nibble with 0x30, advancing one nibble at a time. */ + for (i = 0; i < destlen; i++) { + if (i == 31) { + /* If length is 32 bytes, the leftmost byte is 0. */ + b = 0; + } else if (i % 2) { + b = cpu_ldub_data_ra(env, src, ra); + src--; + } else { + b >>= 4; + } + cpu_stb_data_ra(env, dest, 0x30 + (b & 0xf), ra); + dest--; + } + + return cc; +} + static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, uint64_t trans, uintptr_t ra) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 7e01c40394..cd5cbd18c8 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4349,6 +4349,23 @@ static ExitStatus op_unpk(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_unpka(DisasContext *s, DisasOps *o) +{ + int l1 = get_field(s->fields, l1) + 1; + TCGv_i32 l; + + /* The length must not exceed 32 bytes. */ + if (l1 > 32) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + l = tcg_const_i32(l1); + gen_helper_unpka(cc_op, cpu_env, o->addr1, l, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_xc(DisasContext *s, DisasOps *o) { int d1 = get_field(s->fields, d1); From 15417787212f321efa0592d64b89d6b189c58b41 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:25 +0200 Subject: [PATCH 63/70] target/s390x: implement UNPACK UNICODE Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-27-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 49 ++++++++++++++++++++++++++++++-------- target/s390x/translate.c | 18 ++++++++++++++ 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index c21be5094b..9d4bf6426b 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -90,6 +90,7 @@ DEF_HELPER_FLAGS_4(pka, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(pku, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(unpka, TCG_CALL_NO_WG, i32, env, i64, i32, i64) +DEF_HELPER_FLAGS_4(unpku, TCG_CALL_NO_WG, i32, env, i64, i32, 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 1782e2f3ac..6aa02213ea 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -873,6 +873,8 @@ C(0xf300, UNPK, SS_a, Z, la1, a2, 0, 0, unpk, 0) /* UNPACK ASCII */ C(0xea00, UNPKA, SS_a, E2, la1, a2, 0, 0, unpka, 0) +/* UNPACK UNICODE */ + C(0xe200, UNPKU, SS_a, E2, la1, a2, 0, 0, unpku, 0) #ifndef CONFIG_USER_ONLY /* COMPARE AND SWAP AND PURGE */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b87e41764f..402147e708 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -93,6 +93,23 @@ static inline uint64_t cpu_ldusize_data_ra(CPUS390XState *env, uint64_t addr, } } +/* Store a to memory according to its size. */ +static inline void cpu_stsize_data_ra(CPUS390XState *env, uint64_t addr, + uint64_t value, int wordsize, + uintptr_t ra) +{ + switch (wordsize) { + case 1: + cpu_stb_data_ra(env, addr, value, ra); + break; + case 2: + cpu_stw_data_ra(env, addr, value, ra); + break; + default: + abort(); + } +} + static void fast_memset(CPUS390XState *env, uint64_t dest, uint8_t byte, uint32_t l, uintptr_t ra) { @@ -1008,10 +1025,10 @@ void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, } } -uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen, - uint64_t src) +static inline uint32_t do_unpkau(CPUS390XState *env, uint64_t dest, + uint32_t destlen, int dsize, uint64_t src, + uintptr_t ra) { - uintptr_t ra = GETPC(); int i; uint32_t cc; uint8_t b; @@ -1020,7 +1037,7 @@ uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen, /* The operands are processed from right to left. */ src += srclen - 1; - dest += destlen - 1; + dest += destlen - dsize; /* Check for the sign. */ b = cpu_ldub_data_ra(env, src, ra); @@ -1042,23 +1059,35 @@ uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen, } /* Now pad every nibble with 0x30, advancing one nibble at a time. */ - for (i = 0; i < destlen; i++) { - if (i == 31) { - /* If length is 32 bytes, the leftmost byte is 0. */ + for (i = 0; i < destlen; i += dsize) { + if (i == (31 * dsize)) { + /* If length is 32/64 bytes, the leftmost byte is 0. */ b = 0; - } else if (i % 2) { + } else if (i % (2 * dsize)) { b = cpu_ldub_data_ra(env, src, ra); src--; } else { b >>= 4; } - cpu_stb_data_ra(env, dest, 0x30 + (b & 0xf), ra); - dest--; + cpu_stsize_data_ra(env, dest, 0x30 + (b & 0xf), dsize, ra); + dest -= dsize; } return cc; } +uint32_t HELPER(unpka)(CPUS390XState *env, uint64_t dest, uint32_t destlen, + uint64_t src) +{ + return do_unpkau(env, dest, destlen, 1, src, GETPC()); +} + +uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen, + uint64_t src) +{ + return do_unpkau(env, dest, destlen, 2, src, GETPC()); +} + static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, uint64_t trans, uintptr_t ra) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index cd5cbd18c8..bba9ce87e0 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4366,6 +4366,24 @@ static ExitStatus op_unpka(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_unpku(DisasContext *s, DisasOps *o) +{ + int l1 = get_field(s->fields, l1) + 1; + TCGv_i32 l; + + /* The length must be even and should not exceed 64 bytes. */ + if ((l1 & 1) || (l1 > 64)) { + gen_program_exception(s, PGM_SPECIFICATION); + return EXIT_NORETURN; + } + l = tcg_const_i32(l1); + gen_helper_unpku(cc_op, cpu_env, o->addr1, l, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + + static ExitStatus op_xc(DisasContext *s, DisasOps *o) { int d1 = get_field(s->fields, d1); From 5d4a655a4187a0fe245b8bbaa1cf4ce9de5b4aea Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:26 +0200 Subject: [PATCH 64/70] target/s390x: implement TEST DECIMAL Reviewed-by: Richard Henderson Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-28-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 3 +++ target/s390x/mem_helper.c | 23 +++++++++++++++++++++++ target/s390x/translate.c | 9 +++++++++ 4 files changed, 36 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 9d4bf6426b..587156890d 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -91,6 +91,7 @@ DEF_HELPER_FLAGS_4(pku, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64) DEF_HELPER_FLAGS_4(unpka, TCG_CALL_NO_WG, i32, env, i64, i32, i64) DEF_HELPER_FLAGS_4(unpku, TCG_CALL_NO_WG, i32, env, i64, i32, i64) +DEF_HELPER_FLAGS_3(tp, TCG_CALL_NO_WG, i32, env, i64, i32) 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) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 6aa02213ea..7db5133722 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -852,6 +852,9 @@ C(0xed11, TCDB, RXE, Z, f1_o, a2, 0, 0, tcdb, 0) C(0xed12, TCXB, RXE, Z, x1_o, a2, 0, 0, tcxb, 0) +/* TEST DECIMAL */ + C(0xebc0, TP, RSL, E2, la1, 0, 0, 0, tp, 0) + /* TEST UNDER MASK */ C(0x9100, TM, SI, Z, m1_8u, i2_8u, 0, 0, 0, tm32) C(0xeb51, TMY, SIY, LD, m1_8u, i2_8u, 0, 0, 0, tm32) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index 402147e708..fa2bfbbf2f 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1088,6 +1088,29 @@ uint32_t HELPER(unpku)(CPUS390XState *env, uint64_t dest, uint32_t destlen, return do_unpkau(env, dest, destlen, 2, src, GETPC()); } +uint32_t HELPER(tp)(CPUS390XState *env, uint64_t dest, uint32_t destlen) +{ + uintptr_t ra = GETPC(); + uint32_t cc = 0; + int i; + + for (i = 0; i < destlen; i++) { + uint8_t b = cpu_ldub_data_ra(env, dest + i, ra); + /* digit */ + cc |= (b & 0xf0) > 0x90 ? 2 : 0; + + if (i == (destlen - 1)) { + /* sign */ + cc |= (b & 0xf) < 0xa ? 1 : 0; + } else { + /* digit */ + cc |= (b & 0xf) > 0x9 ? 2 : 0; + } + } + + return cc; +} + static uint32_t do_helper_tr(CPUS390XState *env, uint32_t len, uint64_t array, uint64_t trans, uintptr_t ra) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index bba9ce87e0..2253ce68e3 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4305,6 +4305,15 @@ static ExitStatus op_tprot(DisasContext *s, DisasOps *o) #endif +static ExitStatus op_tp(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l1 = tcg_const_i32(get_field(s->fields, l1) + 1); + gen_helper_tp(cc_op, cpu_env, o->addr1, l1); + tcg_temp_free_i32(l1); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_tr(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); From 4065ae7634601dfd8be8138fdad5562f798c4f5c Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:27 +0200 Subject: [PATCH 65/70] target/s390x: implement TRANSLATE ONE/TWO TO ONE/TWO Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-29-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 9 ++++++++ target/s390x/mem_helper.c | 45 ++++++++++++++++++++++++++++++++++++++ target/s390x/translate.c | 30 +++++++++++++++++++++++++ 4 files changed, 85 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 587156890d..11a545edb6 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -95,6 +95,7 @@ DEF_HELPER_FLAGS_3(tp, TCG_CALL_NO_WG, i32, env, i64, i32) 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_5(trXX, i32, env, i32, i32, i32, i32) 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 7db5133722..9976d290c4 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -870,6 +870,15 @@ /* TRANSLATE EXTENDED */ C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0) +/* TRANSLATE ONE TO ONE */ + C(0xb993, TROO, RRF_c, E2, 0, 0, 0, 0, trXX, 0) +/* TRANSLATE ONE TO TWO */ + C(0xb992, TROT, RRF_c, E2, 0, 0, 0, 0, trXX, 0) +/* TRANSLATE TWO TO ONE */ + C(0xb991, TRTO, RRF_c, E2, 0, 0, 0, 0, trXX, 0) +/* TRANSLATE TWO TO TWO */ + C(0xb990, TRTT, RRF_c, E2, 0, 0, 0, 0, trXX, 0) + /* UNPACK */ /* Really format SS_b, but we pack both lengths into one argument for the helper call, so we might as well leave one 8-bit field. */ diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index fa2bfbbf2f..be89cc4fb4 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1196,6 +1196,51 @@ uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array, return do_helper_trt(env, len, array, trans, GETPC()); } +/* Translate one/two to one/two */ +uint32_t HELPER(trXX)(CPUS390XState *env, uint32_t r1, uint32_t r2, + uint32_t tst, uint32_t sizes) +{ + uintptr_t ra = GETPC(); + int dsize = (sizes & 1) ? 1 : 2; + int ssize = (sizes & 2) ? 1 : 2; + uint64_t tbl = get_address(env, 1) & ~7; + uint64_t dst = get_address(env, r1); + uint64_t len = get_length(env, r1 + 1); + uint64_t src = get_address(env, r2); + uint32_t cc = 3; + int i; + + check_alignment(env, len, ssize, ra); + + /* Lest we fail to service interrupts in a timely manner, */ + /* limit the amount of work we're willing to do. */ + for (i = 0; i < 0x2000; i++) { + uint16_t sval = cpu_ldusize_data_ra(env, src, ssize, ra); + uint64_t tble = tbl + (sval * dsize); + uint16_t dval = cpu_ldusize_data_ra(env, tble, dsize, ra); + if (dval == tst) { + cc = 1; + break; + } + cpu_stsize_data_ra(env, dst, dval, dsize, ra); + + len -= ssize; + src += ssize; + dst += dsize; + + if (len == 0) { + cc = 0; + break; + } + } + + set_address(env, r1, dst); + set_length(env, r1 + 1, len); + set_address(env, r2, src); + + return cc; +} + void HELPER(cdsg)(CPUS390XState *env, uint64_t addr, uint32_t r1, uint32_t r3) { diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 2253ce68e3..9f3443ed6f 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4340,6 +4340,36 @@ static ExitStatus op_trt(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_trXX(DisasContext *s, DisasOps *o) +{ + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r2 = tcg_const_i32(get_field(s->fields, r2)); + TCGv_i32 sizes = tcg_const_i32(s->insn->opc & 3); + TCGv_i32 tst = tcg_temp_new_i32(); + int m3 = get_field(s->fields, m3); + + /* XXX: the C bit in M3 should be considered as 0 when the + ETF2-enhancement facility is not installed. */ + if (m3 & 1) { + tcg_gen_movi_i32(tst, -1); + } else { + tcg_gen_extrl_i64_i32(tst, regs[0]); + if (s->insn->opc & 3) { + tcg_gen_ext8u_i32(tst, tst); + } else { + tcg_gen_ext16u_i32(tst, tst); + } + } + gen_helper_trXX(cc_op, cpu_env, r1, r2, tst, sizes); + + tcg_temp_free_i32(r1); + tcg_temp_free_i32(r2); + tcg_temp_free_i32(sizes); + tcg_temp_free_i32(tst); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_ts(DisasContext *s, DisasOps *o) { TCGv_i32 t1 = tcg_const_i32(0xff); From e22dfdb28dbba83d97ea6b40652ccccd7c60365d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 4 Jun 2017 22:20:32 +0200 Subject: [PATCH 66/70] target/s390x: implement LOAD PAIR FROM QUADWORD Signed-off-by: Aurelien Jarno Message-Id: <20170604202034.16615-2-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 27 +++++++++++++++++++++++++++ target/s390x/translate.c | 7 +++++++ 4 files changed, 37 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 11a545edb6..054ccd686d 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -103,6 +103,7 @@ DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(stfle, i32, env, i64) +DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 9976d290c4..32dee40269 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -517,6 +517,8 @@ /* LOAD PAIR DISJOINT */ D(0xc804, LPD, SSF, ILA, 0, 0, new_P, r3_P32, lpd, 0, MO_TEUL) D(0xc805, LPDG, SSF, ILA, 0, 0, new_P, r3_P64, lpd, 0, MO_TEQ) +/* LOAD PAIR FROM QUADWORD */ + C(0xe38f, LPQ, RXY_a, Z, 0, a2, r1_P, 0, lpq, 0) /* LOAD POSITIVE */ C(0x1000, LPR, RR_a, Z, 0, r2_32s, new, r1_32, abs, abs32) C(0xb900, LPGR, RRE, Z, 0, r2, r1, 0, abs, abs64) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index be89cc4fb4..f48908cecb 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1665,6 +1665,33 @@ uint64_t HELPER(lra)(CPUS390XState *env, uint64_t addr) } #endif +/* load pair from quadword */ +uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr) +{ + uintptr_t ra = GETPC(); + uint64_t hi, lo; + + if (parallel_cpus) { +#ifndef CONFIG_ATOMIC128 + cpu_loop_exit_atomic(ENV_GET_CPU(env), ra); +#else + int mem_idx = cpu_mmu_index(env, false); + TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); + Int128 v = helper_atomic_ldo_be_mmu(env, addr, oi, ra); + hi = int128_gethi(v); + lo = int128_getlo(v); +#endif + } else { + check_alignment(env, addr, 16, ra); + + hi = cpu_ldq_data_ra(env, addr + 0, ra); + lo = cpu_ldq_data_ra(env, addr + 8, ra); + } + + env->retxl = lo; + return hi; +} + /* Execute instruction. This instruction executes an insn modified with the contents of r1. It does not change the executed instruction in memory; it does not change the program counter. diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 9f3443ed6f..10019edd53 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -2909,6 +2909,13 @@ static ExitStatus op_lpd(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_lpq(DisasContext *s, DisasOps *o) +{ + gen_helper_lpq(o->out, cpu_env, o->in2); + return_low128(o->out2); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_lura(DisasContext *s, DisasOps *o) { From c21b610f58f0334aa7f3ddca86efb488d4a92085 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 4 Jun 2017 22:20:33 +0200 Subject: [PATCH 67/70] target/s390x: implement STORE PAIR TO QUADWORD Signed-off-by: Aurelien Jarno Message-Id: <20170604202034.16615-3-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/helper.h | 1 + target/s390x/insn-data.def | 2 ++ target/s390x/mem_helper.c | 24 ++++++++++++++++++++++++ target/s390x/translate.c | 6 ++++++ 4 files changed, 33 insertions(+) diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 054ccd686d..69249a5249 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -104,6 +104,7 @@ DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_1(stfl, TCG_CALL_NO_RWG, void, env) DEF_HELPER_2(stfle, i32, env, i64) DEF_HELPER_FLAGS_2(lpq, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_4(stpq, TCG_CALL_NO_WG, void, env, i64, i64, i64) #ifndef CONFIG_USER_ONLY DEF_HELPER_3(servc, i32, env, i64, i64) diff --git a/target/s390x/insn-data.def b/target/s390x/insn-data.def index 32dee40269..73dd05daf0 100644 --- a/target/s390x/insn-data.def +++ b/target/s390x/insn-data.def @@ -796,6 +796,8 @@ /* STORE ACCESS MULTIPLE */ C(0x9b00, STAM, RS_a, Z, 0, a2, 0, 0, stam, 0) C(0xeb9b, STAMY, RSY_a, LD, 0, a2, 0, 0, stam, 0) +/* STORE PAIR TO QUADWORD */ + C(0xe38e, STPQ, RXY_a, Z, 0, a2, r1_P, 0, stpq, 0) /* SUBTRACT */ C(0x1b00, SR, RR_a, Z, r1, r2, new, r1_32, sub, subs32) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index f48908cecb..a8988e0293 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1692,6 +1692,30 @@ uint64_t HELPER(lpq)(CPUS390XState *env, uint64_t addr) return hi; } +/* store pair to quadword */ +void HELPER(stpq)(CPUS390XState *env, uint64_t addr, + uint64_t low, uint64_t high) +{ + uintptr_t ra = GETPC(); + + if (parallel_cpus) { +#ifndef CONFIG_ATOMIC128 + cpu_loop_exit_atomic(ENV_GET_CPU(env), ra); +#else + int mem_idx = cpu_mmu_index(env, false); + TCGMemOpIdx oi = make_memop_idx(MO_TEQ | MO_ALIGN_16, mem_idx); + + Int128 v = int128_make128(low, high); + helper_atomic_sto_be_mmu(env, addr, v, oi, ra); +#endif + } else { + check_alignment(env, addr, 16, ra); + + cpu_stq_data_ra(env, addr + 0, high, ra); + cpu_stq_data_ra(env, addr + 8, low, ra); + } +} + /* Execute instruction. This instruction executes an insn modified with the contents of r1. It does not change the executed instruction in memory; it does not change the program counter. diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 10019edd53..95f91d4f08 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -4203,6 +4203,12 @@ static ExitStatus op_stmh(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_stpq(DisasContext *s, DisasOps *o) +{ + gen_helper_stpq(cpu_env, o->in2, o->out2, o->out); + return NO_EXIT; +} + static ExitStatus op_srst(DisasContext *s, DisasOps *o) { gen_helper_srst(o->in1, cpu_env, regs[0], o->in1, o->in2); From c0080f1bdbb409b12aa07c2a18caf3ff6a7c1f65 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 4 Jun 2017 22:20:34 +0200 Subject: [PATCH 68/70] target/s390x: check alignment in CDSG in the !CONFIG_ATOMIC128 case The CDSG instruction requires a 16-byte alignement, as expressed in the MO_ALIGN_16 passed to helper_atomic_cmpxchgo_be_mmu. In the non parallel case, use check_alignment to enforce this. Signed-off-by: Aurelien Jarno Message-Id: <20170604202034.16615-4-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/mem_helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index a8988e0293..80caab9c9d 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -1262,6 +1262,8 @@ void HELPER(cdsg)(CPUS390XState *env, uint64_t addr, } else { uint64_t oldh, oldl; + check_alignment(env, addr, 16, ra); + oldh = cpu_ldq_data_ra(env, addr + 0, ra); oldl = cpu_ldq_data_ra(env, addr + 8, ra); From 3190dfc5e1cf8d9114c77dd3c0cbfc7ef226b6db Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Thu, 1 Jun 2017 00:01:28 +0200 Subject: [PATCH 69/70] target/s390x: mark ETF2 and ETF2-ENH facilities as available Signed-off-by: Aurelien Jarno Message-Id: <20170531220129.27724-30-aurelien@aurel32.net> Signed-off-by: Richard Henderson --- target/s390x/cpu_models.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index e5e005a430..fc3cb25cc3 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -668,8 +668,10 @@ static void add_qemu_cpu_model_features(S390FeatBitmap fbm) static const int feats[] = { S390_FEAT_STFLE, S390_FEAT_EXTENDED_IMMEDIATE, + S390_FEAT_EXTENDED_TRANSLATION_2, S390_FEAT_LONG_DISPLACEMENT, S390_FEAT_LONG_DISPLACEMENT_FAST, + S390_FEAT_ETF2_ENH, S390_FEAT_STORE_CLOCK_FAST, S390_FEAT_GENERAL_INSTRUCTIONS_EXT, S390_FEAT_EXECUTE_EXT, From 49921d6886c54ec8727f2253b7698f173166bbd3 Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Mon, 29 May 2017 14:12:28 +0200 Subject: [PATCH 70/70] target/s390x: addressing exceptions are suppressing We have to make the address in the old PSW point at the next instruction, as addressing exceptions are suppressing and not nullifying. I assume that there are a lot of other broken cases (as most instructions we care about are suppressing) - all trigger_pgm_exception() specifying and explicit number or ILEN_LATER look suspicious, however this is another story that might require bigger changes (and I have to understand when the address might already have been incremented first). This is needed to make an upcoming kvm-unit-test work. Reviewed-by: Thomas Huth Signed-off-by: David Hildenbrand Message-Id: <20170529121228.2789-1-david@redhat.com> Signed-off-by: Richard Henderson --- 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 291db720fb..a8d20c51fa 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -204,7 +204,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, if (raddr > ram_size) { DPRINTF("%s: raddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, (uint64_t)raddr, (uint64_t)ram_size); - trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER); + trigger_pgm_exception(env, PGM_ADDRESSING, ILEN_LATER_INC); return 1; }