diff options
Diffstat (limited to 'target/s390x/translate.c')
-rw-r--r-- | target/s390x/translate.c | 233 |
1 files changed, 186 insertions, 47 deletions
diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 85d0a6c3af..ac55886792 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -240,12 +240,6 @@ static void update_cc_op(DisasContext *s) } } -static void potential_page_fault(DisasContext *s) -{ - update_psw_addr(s); - update_cc_op(s); -} - static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) { return (uint64_t)cpu_lduw_code(env, pc); @@ -440,11 +434,9 @@ static void set_cc_static(DisasContext *s) /* calculates cc into cc_op */ static void gen_op_calc_cc(DisasContext *s) { - TCGv_i32 local_cc_op; - TCGv_i64 dummy; + TCGv_i32 local_cc_op = NULL; + TCGv_i64 dummy = NULL; - TCGV_UNUSED_I32(local_cc_op); - TCGV_UNUSED_I64(dummy); switch (s->cc_op) { default: dummy = tcg_const_i64(0); @@ -534,10 +526,10 @@ static void gen_op_calc_cc(DisasContext *s) tcg_abort(); } - if (!TCGV_IS_UNUSED_I32(local_cc_op)) { + if (local_cc_op) { tcg_temp_free_i32(local_cc_op); } - if (!TCGV_IS_UNUSED_I64(dummy)) { + if (dummy) { tcg_temp_free_i64(dummy); } @@ -1195,7 +1187,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, goto egress; } } else { - if (TCGV_IS_UNUSED_I64(cdest)) { + if (!cdest) { /* E.g. bcr %r0 -> no branch. */ ret = NO_EXIT; goto egress; @@ -1370,6 +1362,27 @@ static ExitStatus op_addc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_asi(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_STFLE_45)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic addition in memory. */ + tcg_gen_atomic_fetch_add_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_add_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_STFLE_45)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_aeb(DisasContext *s, DisasOps *o) { gen_helper_aeb(o->out, cpu_env, o->in1, o->in2); @@ -1412,10 +1425,31 @@ static ExitStatus op_andi(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ni(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic operation in memory. */ + tcg_gen_atomic_fetch_and_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_and_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_bas(DisasContext *s, DisasOps *o) { tcg_gen_movi_i64(o->out, pc_to_link_info(s, s->next_pc)); - if (!TCGV_IS_UNUSED_I64(o->in2)) { + if (o->in2) { tcg_gen_mov_i64(psw_addr, o->in2); per_branch(s, false); return EXIT_PC_UPDATED; @@ -2124,9 +2158,6 @@ static ExitStatus op_diag(DisasContext *s, DisasOps *o) TCGv_i32 func_code = tcg_const_i32(get_field(s->fields, i2)); check_privileged(s); - update_psw_addr(s); - gen_op_calc_cc(s); - gen_helper_diag(cpu_env, r1, r3, func_code); tcg_temp_free_i32(func_code); @@ -2942,7 +2973,8 @@ static ExitStatus op_lpd(DisasContext *s, DisasOps *o) /* In a parallel context, stop the world and single step. */ if (tb_cflags(s->tb) & CF_PARALLEL) { - potential_page_fault(s); + update_psw_addr(s); + update_cc_op(s); gen_exception(EXCP_ATOMIC); return EXIT_NORETURN; } @@ -2997,7 +3029,7 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) { o->out = o->in2; o->g_out = o->g_in2; - TCGV_UNUSED_I64(o->in2); + o->in2 = NULL; o->g_in2 = false; return NO_EXIT; } @@ -3009,7 +3041,7 @@ static ExitStatus op_mov2e(DisasContext *s, DisasOps *o) o->out = o->in2; o->g_out = o->g_in2; - TCGV_UNUSED_I64(o->in2); + o->in2 = NULL; o->g_in2 = false; switch (s->tb->flags & FLAG_MASK_ASC) { @@ -3043,8 +3075,8 @@ static ExitStatus op_movx(DisasContext *s, DisasOps *o) o->out2 = o->in2; o->g_out = o->g_in1; o->g_out2 = o->g_in2; - TCGV_UNUSED_I64(o->in1); - TCGV_UNUSED_I64(o->in2); + o->in1 = NULL; + o->in2 = NULL; o->g_in1 = o->g_in2 = false; return NO_EXIT; } @@ -3365,6 +3397,27 @@ static ExitStatus op_ori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_oi(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic operation in memory. */ + tcg_gen_atomic_fetch_or_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_or_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_pack(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); @@ -3704,7 +3757,6 @@ static ExitStatus op_sqxb(DisasContext *s, DisasOps *o) static ExitStatus op_servc(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_servc(cc_op, cpu_env, o->in2, o->in1); set_cc_static(s); return NO_EXIT; @@ -3863,6 +3915,36 @@ static ExitStatus op_spm(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_ectg(DisasContext *s, DisasOps *o) +{ + int b1 = get_field(s->fields, b1); + int d1 = get_field(s->fields, d1); + int b2 = get_field(s->fields, b2); + int d2 = get_field(s->fields, d2); + int r3 = get_field(s->fields, r3); + TCGv_i64 tmp = tcg_temp_new_i64(); + + /* fetch all operands first */ + o->in1 = tcg_temp_new_i64(); + tcg_gen_addi_i64(o->in1, regs[b1], d1); + o->in2 = tcg_temp_new_i64(); + tcg_gen_addi_i64(o->in2, regs[b2], d2); + o->addr1 = get_address(s, 0, r3, 0); + + /* load the third operand into r3 before modifying anything */ + tcg_gen_qemu_ld64(regs[r3], o->addr1, get_mem_index(s)); + + /* subtract CPU timer from first operand and store in GR0 */ + gen_helper_stpt(tmp, cpu_env); + tcg_gen_sub_i64(regs[0], o->in1, tmp); + + /* store second operand in GR1 */ + tcg_gen_mov_i64(regs[1], o->in2); + + tcg_temp_free_i64(tmp); + return NO_EXIT; +} + #ifndef CONFIG_USER_ONLY static ExitStatus op_spka(DisasContext *s, DisasOps *o) { @@ -3906,7 +3988,10 @@ static ExitStatus op_stcke(DisasContext *s, DisasOps *o) { TCGv_i64 c1 = tcg_temp_new_i64(); TCGv_i64 c2 = tcg_temp_new_i64(); + TCGv_i64 todpr = tcg_temp_new_i64(); gen_helper_stck(c1, cpu_env); + /* 16 bit value store in an uint32_t (only valid bits set) */ + tcg_gen_ld32u_i64(todpr, cpu_env, offsetof(CPUS390XState, todpr)); /* Shift the 64-bit value into its place as a zero-extended 104-bit value. Note that "bit positions 64-103 are always non-zero so that they compare differently to STCK"; we set @@ -3914,11 +3999,13 @@ static ExitStatus op_stcke(DisasContext *s, DisasOps *o) tcg_gen_shli_i64(c2, c1, 56); tcg_gen_shri_i64(c1, c1, 8); tcg_gen_ori_i64(c2, c2, 0x10000); + tcg_gen_or_i64(c2, c2, todpr); tcg_gen_qemu_st64(c1, o->in2, get_mem_index(s)); tcg_gen_addi_i64(o->in2, o->in2, 8); tcg_gen_qemu_st64(c2, o->in2, get_mem_index(s)); tcg_temp_free_i64(c1); tcg_temp_free_i64(c2); + tcg_temp_free_i64(todpr); /* ??? We don't implement clock states. */ gen_op_movi_cc(s, 0); return NO_EXIT; @@ -3931,6 +4018,13 @@ static ExitStatus op_sckc(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_sckpf(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sckpf(cpu_env, regs[0]); + return NO_EXIT; +} + static ExitStatus op_stckc(DisasContext *s, DisasOps *o) { check_privileged(s); @@ -3992,7 +4086,6 @@ static ExitStatus op_stpt(DisasContext *s, DisasOps *o) static ExitStatus op_stsi(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_stsi(cc_op, cpu_env, o->in2, regs[0], regs[1]); set_cc_static(s); return NO_EXIT; @@ -4008,7 +4101,6 @@ static ExitStatus op_spx(DisasContext *s, DisasOps *o) static ExitStatus op_xsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_xsch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4017,7 +4109,6 @@ static ExitStatus op_xsch(DisasContext *s, DisasOps *o) static ExitStatus op_csch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_csch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4026,7 +4117,6 @@ static ExitStatus op_csch(DisasContext *s, DisasOps *o) static ExitStatus op_hsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_hsch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4035,7 +4125,6 @@ static ExitStatus op_hsch(DisasContext *s, DisasOps *o) static ExitStatus op_msch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_msch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; @@ -4044,7 +4133,6 @@ static ExitStatus op_msch(DisasContext *s, DisasOps *o) static ExitStatus op_rchp(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_rchp(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; @@ -4053,16 +4141,43 @@ static ExitStatus op_rchp(DisasContext *s, DisasOps *o) static ExitStatus op_rsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_rsch(cpu_env, regs[1]); set_cc_static(s); return NO_EXIT; } +static ExitStatus op_sal(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_sal(cpu_env, regs[1]); + return NO_EXIT; +} + +static ExitStatus op_schm(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_schm(cpu_env, regs[1], regs[2], o->in2); + return NO_EXIT; +} + +static ExitStatus op_siga(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* From KVM code: Not provided, set CC = 3 for subchannel not operational */ + gen_op_movi_cc(s, 3); + return NO_EXIT; +} + +static ExitStatus op_stcps(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + /* The instruction is suppressed if not provided. */ + return NO_EXIT; +} + static ExitStatus op_ssch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_ssch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; @@ -4071,16 +4186,22 @@ static ExitStatus op_ssch(DisasContext *s, DisasOps *o) static ExitStatus op_stsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_stsch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; } +static ExitStatus op_stcrw(DisasContext *s, DisasOps *o) +{ + check_privileged(s); + gen_helper_stcrw(cpu_env, o->in2); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_tsch(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_tsch(cpu_env, regs[1], o->in2); set_cc_static(s); return NO_EXIT; @@ -4089,7 +4210,6 @@ static ExitStatus op_tsch(DisasContext *s, DisasOps *o) static ExitStatus op_chsc(DisasContext *s, DisasOps *o) { check_privileged(s); - potential_page_fault(s); gen_helper_chsc(cpu_env, o->in2); set_cc_static(s); return NO_EXIT; @@ -4622,6 +4742,27 @@ static ExitStatus op_xori(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_xi(DisasContext *s, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_ld_tl(o->in1, o->addr1, get_mem_index(s), s->insn->data); + } else { + /* Perform the atomic operation in memory. */ + tcg_gen_atomic_fetch_xor_i64(o->in1, o->addr1, o->in2, get_mem_index(s), + s->insn->data); + } + + /* Recompute also for atomic case: needed for setting CC. */ + tcg_gen_xor_i64(o->out, o->in1, o->in2); + + if (!s390_has_feat(S390_FEAT_INTERLOCKED_ACCESS_2)) { + tcg_gen_qemu_st_tl(o->out, o->addr1, get_mem_index(s), s->insn->data); + } + return NO_EXIT; +} + static ExitStatus op_zero(DisasContext *s, DisasOps *o) { o->out = tcg_const_i64(0); @@ -5566,6 +5707,7 @@ enum DisasInsnEnum { #define FAC_MSA3 S390_FEAT_MSA_EXT_3 /* msa-extension-3 facility */ #define FAC_MSA4 S390_FEAT_MSA_EXT_4 /* msa-extension-4 facility */ #define FAC_MSA5 S390_FEAT_MSA_EXT_5 /* msa-extension-5 facility */ +#define FAC_ECT S390_FEAT_EXTRACT_CPU_TIME static const DisasInsn insn_info[] = { #include "insn-data.def" @@ -5801,11 +5943,11 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) s->insn = insn; s->fields = &f; o.g_out = o.g_out2 = o.g_in1 = o.g_in2 = false; - TCGV_UNUSED_I64(o.out); - TCGV_UNUSED_I64(o.out2); - TCGV_UNUSED_I64(o.in1); - TCGV_UNUSED_I64(o.in2); - TCGV_UNUSED_I64(o.addr1); + o.out = NULL; + o.out2 = NULL; + o.in1 = NULL; + o.in2 = NULL; + o.addr1 = NULL; /* Implement the instruction. */ if (insn->help_in1) { @@ -5828,19 +5970,19 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) } /* Free any temporaries created by the helpers. */ - if (!TCGV_IS_UNUSED_I64(o.out) && !o.g_out) { + if (o.out && !o.g_out) { tcg_temp_free_i64(o.out); } - if (!TCGV_IS_UNUSED_I64(o.out2) && !o.g_out2) { + if (o.out2 && !o.g_out2) { tcg_temp_free_i64(o.out2); } - if (!TCGV_IS_UNUSED_I64(o.in1) && !o.g_in1) { + if (o.in1 && !o.g_in1) { tcg_temp_free_i64(o.in1); } - if (!TCGV_IS_UNUSED_I64(o.in2) && !o.g_in2) { + if (o.in2 && !o.g_in2) { tcg_temp_free_i64(o.in2); } - if (!TCGV_IS_UNUSED_I64(o.addr1)) { + if (o.addr1) { tcg_temp_free_i64(o.addr1); } @@ -5851,9 +5993,6 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) tcg_gen_movi_i64(psw_addr, s->next_pc); } - /* Save off cc. */ - update_cc_op(s); - /* Call the helper to check for a possible PER exception. */ gen_helper_per_check_exception(cpu_env); } |