diff options
Diffstat (limited to 'target-s390x/translate.c')
-rw-r--r-- | target-s390x/translate.c | 556 |
1 files changed, 503 insertions, 53 deletions
diff --git a/target-s390x/translate.c b/target-s390x/translate.c index fbffd3066d..42f52c70c6 100644 --- a/target-s390x/translate.c +++ b/target-s390x/translate.c @@ -150,6 +150,7 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, static TCGv_i64 psw_addr; static TCGv_i64 psw_mask; +static TCGv_i64 gbea; static TCGv_i32 cc_op; static TCGv_i64 cc_src; @@ -173,6 +174,9 @@ void s390x_translate_init(void) psw_mask = tcg_global_mem_new_i64(TCG_AREG0, offsetof(CPUS390XState, psw.mask), "psw_mask"); + gbea = tcg_global_mem_new_i64(TCG_AREG0, + offsetof(CPUS390XState, gbea), + "gbea"); cc_op = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUS390XState, cc_op), "cc_op"); @@ -249,6 +253,46 @@ static void update_psw_addr(DisasContext *s) tcg_gen_movi_i64(psw_addr, s->pc); } +static void per_branch(DisasContext *s, bool to_next) +{ +#ifndef CONFIG_USER_ONLY + tcg_gen_movi_i64(gbea, s->pc); + + if (s->tb->flags & FLAG_MASK_PER) { + TCGv_i64 next_pc = to_next ? tcg_const_i64(s->next_pc) : psw_addr; + gen_helper_per_branch(cpu_env, gbea, next_pc); + if (to_next) { + tcg_temp_free_i64(next_pc); + } + } +#endif +} + +static void per_branch_cond(DisasContext *s, TCGCond cond, + TCGv_i64 arg1, TCGv_i64 arg2) +{ +#ifndef CONFIG_USER_ONLY + if (s->tb->flags & FLAG_MASK_PER) { + TCGLabel *lab = gen_new_label(); + tcg_gen_brcond_i64(tcg_invert_cond(cond), arg1, arg2, lab); + + tcg_gen_movi_i64(gbea, s->pc); + gen_helper_per_branch(cpu_env, gbea, psw_addr); + + gen_set_label(lab); + } else { + TCGv_i64 pc = tcg_const_i64(s->pc); + tcg_gen_movcond_i64(cond, gbea, arg1, arg2, gbea, pc); + tcg_temp_free_i64(pc); + } +#endif +} + +static void per_breaking_event(DisasContext *s) +{ + tcg_gen_movi_i64(gbea, s->pc); +} + static void update_cc_op(DisasContext *s) { if (s->cc_op != CC_OP_DYNAMIC && s->cc_op != CC_OP_STATIC) { @@ -320,7 +364,21 @@ static void gen_program_exception(DisasContext *s, int code) static inline void gen_illegal_opcode(DisasContext *s) { - gen_program_exception(s, PGM_SPECIFICATION); + gen_program_exception(s, PGM_OPERATION); +} + +static inline void gen_trap(DisasContext *s) +{ + TCGv_i32 t; + + /* Set DXC to 0xff. */ + t = tcg_temp_new_i32(); + tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_gen_ori_i32(t, t, 0xff00); + tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); + tcg_temp_free_i32(t); + + gen_program_exception(s, PGM_DATA); } #ifndef CONFIG_USER_ONLY @@ -554,7 +612,8 @@ static int use_goto_tb(DisasContext *s, uint64_t dest) return (((dest & TARGET_PAGE_MASK) == (s->tb->pc & TARGET_PAGE_MASK) || (dest & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) && !s->singlestep_enabled - && !(s->tb->cflags & CF_LAST_IO)); + && !(s->tb->cflags & CF_LAST_IO) + && !(s->tb->flags & FLAG_MASK_PER)); } static void account_noninline_branch(DisasContext *s, int cc_op) @@ -987,6 +1046,7 @@ enum DisasFieldIndexC { }; struct DisasFields { + uint64_t raw_insn; unsigned op:8; unsigned op2:8; unsigned presentC:16; @@ -1119,6 +1179,8 @@ typedef enum DisasFacility { FAC_HFP_MA, /* HFP multiply-and-add/subtract */ FAC_HW, /* high-word */ FAC_IEEEE_SIM, /* IEEE exception sumilation */ + FAC_MIE, /* miscellaneous-instruction-extensions */ + FAC_LAT, /* load-and-trap */ FAC_LOC, /* load/store on condition */ FAC_LD, /* long displacement */ FAC_PC, /* population count */ @@ -1165,16 +1227,19 @@ static void help_l2_shift(DisasContext *s, DisasFields *f, static ExitStatus help_goto_direct(DisasContext *s, uint64_t dest) { if (dest == s->next_pc) { + per_branch(s, true); return NO_EXIT; } if (use_goto_tb(s, dest)) { update_cc_op(s); + per_breaking_event(s); tcg_gen_goto_tb(0); tcg_gen_movi_i64(psw_addr, dest); tcg_gen_exit_tb((uintptr_t)s->tb); return EXIT_GOTO_TB; } else { tcg_gen_movi_i64(psw_addr, dest); + per_branch(s, false); return EXIT_PC_UPDATED; } } @@ -1194,6 +1259,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, if (is_imm) { if (dest == s->next_pc) { /* Branch to next. */ + per_branch(s, true); ret = NO_EXIT; goto egress; } @@ -1209,6 +1275,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, } if (c->cond == TCG_COND_ALWAYS) { tcg_gen_mov_i64(psw_addr, cdest); + per_branch(s, false); ret = EXIT_PC_UPDATED; goto egress; } @@ -1233,6 +1300,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, /* Branch taken. */ gen_set_label(lab); + per_breaking_event(s); tcg_gen_goto_tb(1); tcg_gen_movi_i64(psw_addr, dest); tcg_gen_exit_tb((uintptr_t)s->tb + 1); @@ -1264,6 +1332,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, if (is_imm) { tcg_gen_movi_i64(psw_addr, dest); } + per_breaking_event(s); ret = EXIT_PC_UPDATED; } } else { @@ -1279,6 +1348,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, if (c->is_64) { tcg_gen_movcond_i64(c->cond, psw_addr, c->u.s64.a, c->u.s64.b, cdest, next); + per_branch_cond(s, c->cond, c->u.s64.a, c->u.s64.b); } else { TCGv_i32 t0 = tcg_temp_new_i32(); TCGv_i64 t1 = tcg_temp_new_i64(); @@ -1287,6 +1357,7 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, tcg_gen_extu_i32_i64(t1, t0); tcg_temp_free_i32(t0); tcg_gen_movcond_i64(TCG_COND_NE, psw_addr, t1, z, cdest, next); + per_branch_cond(s, TCG_COND_NE, t1, z); tcg_temp_free_i64(t1); tcg_temp_free_i64(z); } @@ -1310,7 +1381,13 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c, static ExitStatus op_abs(DisasContext *s, DisasOps *o) { - gen_helper_abs_i64(o->out, o->in2); + TCGv_i64 z, n; + z = tcg_const_i64(0); + n = tcg_temp_new_i64(); + tcg_gen_neg_i64(n, o->in2); + tcg_gen_movcond_i64(TCG_COND_LT, o->out, o->in2, z, n, o->in2); + tcg_temp_free_i64(n); + tcg_temp_free_i64(z); return NO_EXIT; } @@ -1413,6 +1490,7 @@ 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)) { tcg_gen_mov_i64(psw_addr, o->in2); + per_branch(s, false); return EXIT_PC_UPDATED; } else { return NO_EXIT; @@ -1460,6 +1538,30 @@ static ExitStatus op_bct32(DisasContext *s, DisasOps *o) return help_branch(s, &c, is_imm, imm, o->in2); } +static ExitStatus op_bcth(DisasContext *s, DisasOps *o) +{ + int r1 = get_field(s->fields, r1); + int imm = get_field(s->fields, i2); + DisasCompare c; + TCGv_i64 t; + + c.cond = TCG_COND_NE; + c.is_64 = false; + c.g1 = false; + c.g2 = false; + + t = tcg_temp_new_i64(); + tcg_gen_shri_i64(t, regs[r1], 32); + tcg_gen_subi_i64(t, t, 1); + store_reg32h_i64(r1, t); + c.u.s32.a = tcg_temp_new_i32(); + c.u.s32.b = tcg_const_i32(0); + tcg_gen_trunc_i64_i32(c.u.s32.a, t); + tcg_temp_free_i64(t); + + return help_branch(s, &c, 1, imm, o->in2); +} + static ExitStatus op_bct64(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); @@ -1961,7 +2063,6 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) { int m3 = get_field(s->fields, m3); TCGLabel *lab = gen_new_label(); - TCGv_i32 t; TCGCond c; c = tcg_invert_cond(ltgt_cond[m3]); @@ -1970,15 +2071,8 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) } tcg_gen_brcond_i64(c, o->in1, o->in2, lab); - /* Set DXC to 0xff. */ - t = tcg_temp_new_i32(); - tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_gen_ori_i32(t, t, 0xff00); - tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc)); - tcg_temp_free_i32(t); - /* Trap. */ - gen_program_exception(s, PGM_DATA); + gen_trap(s); gen_set_label(lab); return NO_EXIT; @@ -1987,15 +2081,19 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o) #ifndef CONFIG_USER_ONLY static ExitStatus op_diag(DisasContext *s, DisasOps *o) { - TCGv_i32 tmp; + TCGv_i32 r1 = tcg_const_i32(get_field(s->fields, r1)); + TCGv_i32 r3 = tcg_const_i32(get_field(s->fields, r3)); + TCGv_i32 func_code = tcg_const_i32(get_field(s->fields, i2)); check_privileged(s); - potential_page_fault(s); + update_psw_addr(s); + gen_op_calc_cc(s); - /* We pretend the format is RX_a so that D2 is the field we want. */ - tmp = tcg_const_i32(get_field(s->fields, d2) & 0xfff); - gen_helper_diag(regs[2], cpu_env, tmp, regs[2], regs[1]); - tcg_temp_free_i32(tmp); + gen_helper_diag(cpu_env, r1, r3, func_code); + + tcg_temp_free_i32(func_code); + tcg_temp_free_i32(r3); + tcg_temp_free_i32(r1); return NO_EXIT; } #endif @@ -2101,13 +2199,37 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o) TCGv_i64 tmp; update_psw_addr(s); - update_cc_op(s); + gen_op_calc_cc(s); tmp = tcg_const_i64(s->next_pc); gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp); tcg_temp_free_i64(tmp); - set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_fieb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_fieb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_fidb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_fidb(o->out, cpu_env, o->in2, m3); + tcg_temp_free_i32(m3); + return NO_EXIT; +} + +static ExitStatus op_fixb(DisasContext *s, DisasOps *o) +{ + TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3)); + gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m3); + return_low128(o->out2); + tcg_temp_free_i32(m3); return NO_EXIT; } @@ -2320,6 +2442,61 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_lat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + store_reg32_i64(get_field(s->fields, r1), o->in2); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_lgat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s)); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_lfhat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + store_reg32h_i64(get_field(s->fields, r1), o->in2); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_llgfat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s)); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + +static ExitStatus op_llgtat(DisasContext *s, DisasOps *o) +{ + TCGLabel *lab = gen_new_label(); + tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff); + /* The value is stored even in case of trap. */ + tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab); + gen_trap(s); + gen_set_label(lab); + return NO_EXIT; +} + static ExitStatus op_loc(DisasContext *s, DisasOps *o) { DisasCompare c; @@ -2388,6 +2565,7 @@ static ExitStatus op_lpsw(DisasContext *s, DisasOps *o) TCGv_i64 t1, t2; check_privileged(s); + per_breaking_event(s); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); @@ -2407,6 +2585,7 @@ static ExitStatus op_lpswe(DisasContext *s, DisasOps *o) TCGv_i64 t1, t2; check_privileged(s); + per_breaking_event(s); t1 = tcg_temp_new_i64(); t2 = tcg_temp_new_i64(); @@ -2435,21 +2614,45 @@ static ExitStatus op_lm32(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - TCGv_i64 t = tcg_temp_new_i64(); - TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t1, t2; - while (1) { - tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); - store_reg32_i64(r1, t); - if (r1 == r3) { - break; - } - tcg_gen_add_i64(o->in2, o->in2, t4); + /* Only one register to read. */ + t1 = tcg_temp_new_i64(); + if (unlikely(r1 == r3)) { + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t1); + tcg_temp_free(t1); + return NO_EXIT; + } + + /* First load the values of the first and last registers to trigger + possible page faults. */ + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15)); + tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s)); + store_reg32_i64(r1, t1); + store_reg32_i64(r3, t2); + + /* Only two registers to read. */ + if (((r1 + 1) & 15) == r3) { + tcg_temp_free(t2); + tcg_temp_free(t1); + return NO_EXIT; + } + + /* Then load the remaining registers. Page fault can't occur. */ + r3 = (r3 - 1) & 15; + tcg_gen_movi_i64(t2, 4); + while (r1 != r3) { r1 = (r1 + 1) & 15; + tcg_gen_add_i64(o->in2, o->in2, t2); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32_i64(r1, t1); } + tcg_temp_free(t2); + tcg_temp_free(t1); - tcg_temp_free_i64(t); - tcg_temp_free_i64(t4); return NO_EXIT; } @@ -2457,21 +2660,45 @@ static ExitStatus op_lmh(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - TCGv_i64 t = tcg_temp_new_i64(); - TCGv_i64 t4 = tcg_const_i64(4); + TCGv_i64 t1, t2; - while (1) { - tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s)); - store_reg32h_i64(r1, t); - if (r1 == r3) { - break; - } - tcg_gen_add_i64(o->in2, o->in2, t4); + /* Only one register to read. */ + t1 = tcg_temp_new_i64(); + if (unlikely(r1 == r3)) { + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t1); + tcg_temp_free(t1); + return NO_EXIT; + } + + /* First load the values of the first and last registers to trigger + possible page faults. */ + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15)); + tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s)); + store_reg32h_i64(r1, t1); + store_reg32h_i64(r3, t2); + + /* Only two registers to read. */ + if (((r1 + 1) & 15) == r3) { + tcg_temp_free(t2); + tcg_temp_free(t1); + return NO_EXIT; + } + + /* Then load the remaining registers. Page fault can't occur. */ + r3 = (r3 - 1) & 15; + tcg_gen_movi_i64(t2, 4); + while (r1 != r3) { r1 = (r1 + 1) & 15; + tcg_gen_add_i64(o->in2, o->in2, t2); + tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s)); + store_reg32h_i64(r1, t1); } + tcg_temp_free(t2); + tcg_temp_free(t1); - tcg_temp_free_i64(t); - tcg_temp_free_i64(t4); return NO_EXIT; } @@ -2479,18 +2706,40 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o) { int r1 = get_field(s->fields, r1); int r3 = get_field(s->fields, r3); - TCGv_i64 t8 = tcg_const_i64(8); + TCGv_i64 t1, t2; - while (1) { + /* Only one register to read. */ + if (unlikely(r1 == r3)) { tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); - if (r1 == r3) { - break; - } - tcg_gen_add_i64(o->in2, o->in2, t8); + return NO_EXIT; + } + + /* First load the values of the first and last registers to trigger + possible page faults. */ + t1 = tcg_temp_new_i64(); + t2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s)); + tcg_gen_addi_i64(t2, o->in2, 8 * ((r3 - r1) & 15)); + tcg_gen_qemu_ld64(regs[r3], t2, get_mem_index(s)); + tcg_gen_mov_i64(regs[r1], t1); + tcg_temp_free(t2); + + /* Only two registers to read. */ + if (((r1 + 1) & 15) == r3) { + tcg_temp_free(t1); + return NO_EXIT; + } + + /* Then load the remaining registers. Page fault can't occur. */ + r3 = (r3 - 1) & 15; + tcg_gen_movi_i64(t1, 8); + while (r1 != r3) { r1 = (r1 + 1) & 15; + tcg_gen_add_i64(o->in2, o->in2, t1); + tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s)); } + tcg_temp_free(t1); - tcg_temp_free_i64(t8); return NO_EXIT; } @@ -2521,6 +2770,41 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_mov2e(DisasContext *s, DisasOps *o) +{ + int b2 = get_field(s->fields, b2); + TCGv ar1 = tcg_temp_new_i64(); + + o->out = o->in2; + o->g_out = o->g_in2; + TCGV_UNUSED_I64(o->in2); + o->g_in2 = false; + + switch (s->tb->flags & FLAG_MASK_ASC) { + case PSW_ASC_PRIMARY >> 32: + tcg_gen_movi_i64(ar1, 0); + break; + case PSW_ASC_ACCREG >> 32: + tcg_gen_movi_i64(ar1, 1); + break; + case PSW_ASC_SECONDARY >> 32: + if (b2) { + tcg_gen_ld32u_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[b2])); + } else { + tcg_gen_movi_i64(ar1, 0); + } + break; + case PSW_ASC_HOME >> 32: + tcg_gen_movi_i64(ar1, 2); + break; + } + + tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1])); + tcg_temp_free_i64(ar1); + + return NO_EXIT; +} + static ExitStatus op_movx(DisasContext *s, DisasOps *o) { o->out = o->in1; @@ -2681,7 +2965,13 @@ static ExitStatus op_msdb(DisasContext *s, DisasOps *o) static ExitStatus op_nabs(DisasContext *s, DisasOps *o) { - gen_helper_nabs_i64(o->out, o->in2); + TCGv_i64 z, n; + z = tcg_const_i64(0); + n = tcg_temp_new_i64(); + tcg_gen_neg_i64(n, o->in2); + tcg_gen_movcond_i64(TCG_COND_GE, o->out, o->in2, z, n, o->in2); + tcg_temp_free_i64(n); + tcg_temp_free_i64(z); return NO_EXIT; } @@ -3356,11 +3646,93 @@ static ExitStatus op_spx(DisasContext *s, DisasOps *o) return NO_EXIT; } -static ExitStatus op_subchannel(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; +} + +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; +} + +static ExitStatus op_hsch(DisasContext *s, DisasOps *o) { check_privileged(s); - /* Not operational. */ - gen_op_movi_cc(s, 3); + potential_page_fault(s); + gen_helper_hsch(cpu_env, regs[1]); + set_cc_static(s); + return NO_EXIT; +} + +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; +} + +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; +} + +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_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; +} + +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_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; +} + +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; } @@ -3646,6 +4018,25 @@ static ExitStatus op_tr(DisasContext *s, DisasOps *o) return NO_EXIT; } +static ExitStatus op_tre(DisasContext *s, DisasOps *o) +{ + potential_page_fault(s); + gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2); + return_low128(o->out2); + set_cc_static(s); + return NO_EXIT; +} + +static ExitStatus op_trt(DisasContext *s, DisasOps *o) +{ + TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); + potential_page_fault(s); + gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2); + tcg_temp_free_i32(l); + set_cc_static(s); + return NO_EXIT; +} + static ExitStatus op_unpk(DisasContext *s, DisasOps *o) { TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1)); @@ -3989,6 +4380,12 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_wout_r1_32 0 +static void wout_r1_32h(DisasContext *s, DisasFields *f, DisasOps *o) +{ + store_reg32h_i64(get_field(f, r1), o->out); +} +#define SPEC_wout_r1_32h 0 + static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o) { int r1 = get_field(f, r1); @@ -4159,6 +4556,13 @@ static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in1_r2 0 +static void in1_r2_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in1 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in1, regs[get_field(f, r2)], 32); +} +#define SPEC_in1_r2_sr32 0 + static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o) { o->in1 = load_reg(get_field(f, r3)); @@ -4372,6 +4776,13 @@ static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_r3 0 +static void in2_r3_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in2, regs[get_field(f, r3)], 32); +} +#define SPEC_in2_r3_sr32 0 + static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = tcg_temp_new_i64(); @@ -4386,6 +4797,13 @@ static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_r2_32u 0 +static void in2_r2_sr32(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_temp_new_i64(); + tcg_gen_shri_i64(o->in2, regs[get_field(f, r2)], 32); +} +#define SPEC_in2_r2_sr32 0 + static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o) { o->in2 = load_freg32_i64(get_field(f, r2)); @@ -4565,6 +4983,14 @@ static void in2_i2_32u_shl(DisasContext *s, DisasFields *f, DisasOps *o) } #define SPEC_in2_i2_32u_shl 0 +#ifndef CONFIG_USER_ONLY +static void in2_insn(DisasContext *s, DisasFields *f, DisasOps *o) +{ + o->in2 = tcg_const_i64(s->fields->raw_insn); +} +#define SPEC_in2_insn 0 +#endif + /* ====================================================================== */ /* Find opc within the table of insns. This is formulated as a switch @@ -4741,6 +5167,7 @@ static const DisasInsn *extract_insn(CPUS390XState *env, DisasContext *s, } memset(f, 0, sizeof(*f)); + f->raw_insn = insn; f->op = op; f->op2 = op2; @@ -4777,6 +5204,14 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) return EXIT_NORETURN; } +#ifndef CONFIG_USER_ONLY + if (s->tb->flags & FLAG_MASK_PER) { + TCGv_i64 addr = tcg_const_i64(s->pc); + gen_helper_per_ifetch(cpu_env, addr); + tcg_temp_free_i64(addr); + } +#endif + /* Check for insn specification exceptions. */ if (insn->spec) { int spec = insn->spec, excp = 0, r; @@ -4864,6 +5299,21 @@ static ExitStatus translate_one(CPUS390XState *env, DisasContext *s) tcg_temp_free_i64(o.addr1); } +#ifndef CONFIG_USER_ONLY + if (s->tb->flags & FLAG_MASK_PER) { + /* An exception might be triggered, save PSW if not already done. */ + if (ret == NO_EXIT || ret == EXIT_PC_STALE) { + 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); + } +#endif + /* Advance to the next instruction. */ s->pc = s->next_pc; return ret; |