diff options
author | Ilya Leoshkevich <iii@linux.ibm.com> | 2023-03-15 03:04:07 +0100 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2023-03-20 09:32:50 +0100 |
commit | 199c42a6a16ba32b5684e679df949cf29024b0cf (patch) | |
tree | d77d46b4911a089e4222a70b65690333b1dff61f /target/s390x/tcg/translate.c | |
parent | 377dc84e2d58a734f9b9d299f218c4111133addb (diff) |
target/s390x: Implement Early Exception Recognition
Generate a specification exception if a reserved bit is set in the PSW
mask or if the PSW address is out of bounds dictated by the addressing
mode.
Reported-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Message-Id: <20230315020408.384766-3-iii@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'target/s390x/tcg/translate.c')
-rw-r--r-- | target/s390x/tcg/translate.c | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 2e1e7e046a..7832cf02a6 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -4068,9 +4068,23 @@ static DisasJumpType op_sske(DisasContext *s, DisasOps *o) return DISAS_NEXT; } +static void gen_check_psw_mask(DisasContext *s) +{ + TCGv_i64 reserved = tcg_temp_new_i64(); + TCGLabel *ok = gen_new_label(); + + tcg_gen_andi_i64(reserved, psw_mask, PSW_MASK_RESERVED); + tcg_gen_brcondi_i64(TCG_COND_EQ, reserved, 0, ok); + gen_program_exception(s, PGM_SPECIFICATION); + gen_set_label(ok); +} + static DisasJumpType op_ssm(DisasContext *s, DisasOps *o) { tcg_gen_deposit_i64(psw_mask, psw_mask, o->in2, 56, 8); + + gen_check_psw_mask(s); + /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ s->exit_to_mainloop = true; return DISAS_TOO_MANY; @@ -4331,6 +4345,8 @@ static DisasJumpType op_stnosm(DisasContext *s, DisasOps *o) tcg_gen_ori_i64(psw_mask, psw_mask, i2 << 56); } + gen_check_psw_mask(s); + /* Exit to main loop to reevaluate s390_cpu_exec_interrupt. */ s->exit_to_mainloop = true; return DISAS_TOO_MANY; |