aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2023-07-28 12:53:59 -0700
committerRichard Henderson <richard.henderson@linaro.org>2023-07-31 12:19:13 -0700
commit8b94ec53f367db7adcc9b59c483ce3e6c7bc3740 (patch)
tree5f9fa7340f118fde60eea07b302a4d088f417c78 /target
parent38dd78c41eaf08b490c9e7ec68fc508bbaa5cb1d (diff)
downloadqemu-8b94ec53f367db7adcc9b59c483ce3e6c7bc3740.zip
qemu-8b94ec53f367db7adcc9b59c483ce3e6c7bc3740.tar.gz
qemu-8b94ec53f367db7adcc9b59c483ce3e6c7bc3740.tar.bz2
target/s390x: Move trans_exc_code update to do_program_interrupt
This solves a problem in which the store to LowCore during tlb_fill triggers a clean-page TB invalidation for page0 during translation, which results in an assertion failure for locked pages. By delaying the store until after the exception has been raised, we will have unwound the pages locked for translation and the problem does not arise. There are plenty of other updates to LowCore while delivering an interrupt/exception; trans_exc_code does not need to be special. Reviewed-by: Ilya Leoshkevich <iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'target')
-rw-r--r--target/s390x/tcg/excp_helper.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c
index 3da337f..b7116d0 100644
--- a/target/s390x/tcg/excp_helper.c
+++ b/target/s390x/tcg/excp_helper.c
@@ -190,11 +190,6 @@ bool s390_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
return false;
}
- if (excp != PGM_ADDRESSING) {
- stq_phys(env_cpu(env)->as,
- env->psa + offsetof(LowCore, trans_exc_code), tec);
- }
-
/*
* For data accesses, ILEN will be filled in from the unwind info,
* within cpu_loop_exit_restore. For code accesses, retaddr == 0,
@@ -211,20 +206,33 @@ static void do_program_interrupt(CPUS390XState *env)
uint64_t mask, addr;
LowCore *lowcore;
int ilen = env->int_pgm_ilen;
+ bool set_trans_exc_code = false;
+ bool advance = false;
assert((env->int_pgm_code == PGM_SPECIFICATION && ilen == 0) ||
ilen == 2 || ilen == 4 || ilen == 6);
switch (env->int_pgm_code) {
case PGM_PER:
- if (env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION) {
- break;
- }
- /* FALL THROUGH */
+ advance = !(env->per_perc_atmid & PER_CODE_EVENT_NULLIFICATION);
+ break;
+ case PGM_ASCE_TYPE:
+ case PGM_REG_FIRST_TRANS:
+ case PGM_REG_SEC_TRANS:
+ case PGM_REG_THIRD_TRANS:
+ case PGM_SEGMENT_TRANS:
+ case PGM_PAGE_TRANS:
+ assert(env->int_pgm_code == env->tlb_fill_exc);
+ set_trans_exc_code = true;
+ break;
+ case PGM_PROTECTION:
+ assert(env->int_pgm_code == env->tlb_fill_exc);
+ set_trans_exc_code = true;
+ advance = true;
+ break;
case PGM_OPERATION:
case PGM_PRIVILEGED:
case PGM_EXECUTE:
- case PGM_PROTECTION:
case PGM_ADDRESSING:
case PGM_SPECIFICATION:
case PGM_DATA:
@@ -243,11 +251,15 @@ static void do_program_interrupt(CPUS390XState *env)
case PGM_PC_TRANS_SPEC:
case PGM_ALET_SPEC:
case PGM_MONITOR:
- /* advance the PSW if our exception is not nullifying */
- env->psw.addr += ilen;
+ advance = true;
break;
}
+ /* advance the PSW if our exception is not nullifying */
+ if (advance) {
+ env->psw.addr += ilen;
+ }
+
qemu_log_mask(CPU_LOG_INT,
"%s: code=0x%x ilen=%d psw: %" PRIx64 " %" PRIx64 "\n",
__func__, env->int_pgm_code, ilen, env->psw.mask,
@@ -263,6 +275,10 @@ static void do_program_interrupt(CPUS390XState *env)
env->per_perc_atmid = 0;
}
+ if (set_trans_exc_code) {
+ lowcore->trans_exc_code = cpu_to_be64(env->tlb_fill_tec);
+ }
+
lowcore->pgm_ilen = cpu_to_be16(ilen);
lowcore->pgm_code = cpu_to_be16(env->int_pgm_code);
lowcore->program_old_psw.mask = cpu_to_be64(s390_cpu_get_psw_mask(env));