diff options
Diffstat (limited to 'target')
-rw-r--r-- | target/s390x/helper.h | 2 | ||||
-rw-r--r-- | target/s390x/tcg/excp_helper.c | 2 | ||||
-rw-r--r-- | target/s390x/tcg/misc_helper.c | 23 | ||||
-rw-r--r-- | target/s390x/tcg/translate.c | 11 |
4 files changed, 28 insertions, 10 deletions
diff --git a/target/s390x/helper.h b/target/s390x/helper.h index cc1c20e..96ab71e 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -359,7 +359,7 @@ 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_3(lra, i64, env, i64, i64) -DEF_HELPER_1(per_check_exception, void, env) +DEF_HELPER_FLAGS_3(per_check_exception, TCG_CALL_NO_WG, void, env, i64, i32) DEF_HELPER_FLAGS_3(per_branch, TCG_CALL_NO_RWG, void, env, i64, i64) DEF_HELPER_FLAGS_2(per_ifetch, TCG_CALL_NO_RWG, void, env, i64) DEF_HELPER_FLAGS_1(per_store_real, TCG_CALL_NO_RWG, void, env) diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index f1c33f7..4c0b692 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -209,7 +209,7 @@ static void do_program_interrupt(CPUS390XState *env) switch (env->int_pgm_code) { case PGM_PER: - advance = !(env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION); + /* advance already handled */ break; case PGM_ASCE_TYPE: case PGM_REG_FIRST_TRANS: diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index 8764846..7c94468 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" +#include "qemu/log.h" #include "cpu.h" #include "s390x-internal.h" #include "qemu/host-utils.h" @@ -590,10 +591,26 @@ void HELPER(chsc)(CPUS390XState *env, uint64_t inst) #endif #ifndef CONFIG_USER_ONLY -void HELPER(per_check_exception)(CPUS390XState *env) +static G_NORETURN void per_raise_exception(CPUS390XState *env) { - if (env->per_perc_atmid) { - tcg_s390_program_interrupt(env, PGM_PER, GETPC()); + trigger_pgm_exception(env, PGM_PER); + cpu_loop_exit(env_cpu(env)); +} + +static G_NORETURN void per_raise_exception_log(CPUS390XState *env) +{ + qemu_log_mask(CPU_LOG_INT, "PER interrupt after 0x%" PRIx64 "\n", + env->per_address); + per_raise_exception(env); +} + +void HELPER(per_check_exception)(CPUS390XState *env, uint64_t next_pc, + uint32_t ilen) +{ + if (unlikely(env->per_perc_atmid)) { + env->psw.addr = next_pc; + env->int_pgm_ilen = ilen; + per_raise_exception_log(env); } } diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index ebd96ab..4c3ff19 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -6424,13 +6424,14 @@ static DisasJumpType translate_one(CPUS390XState *env, DisasContext *s) #ifndef CONFIG_USER_ONLY if (s->base.tb->flags & FLAG_MASK_PER) { - /* An exception might be triggered, save PSW if not already done. */ + TCGv_i64 next_pc = psw_addr; + if (ret == DISAS_NEXT || ret == DISAS_TOO_MANY) { - tcg_gen_movi_i64(psw_addr, s->pc_tmp); + next_pc = tcg_constant_i64(s->pc_tmp); } - - /* Call the helper to check for a possible PER exception. */ - gen_helper_per_check_exception(tcg_env); + update_cc_op(s); + gen_helper_per_check_exception(tcg_env, next_pc, + tcg_constant_i32(s->ilen)); } #endif |