diff options
author | David Hildenbrand <david@redhat.com> | 2021-09-03 17:55:05 +0200 |
---|---|---|
committer | Thomas Huth <thuth@redhat.com> | 2021-09-06 16:24:05 +0200 |
commit | eaa0feea7532429c3a9bec357ec4f77cb156fab0 (patch) | |
tree | 4cdb62c716adf06d53b248bda1f6276d3d7f4f19 /target | |
parent | 06d8a10a70b7ef14ebf88b874858f73f2dee1109 (diff) |
s390x/tcg: check for addressing exceptions for RRBE, SSKE and ISKE
Let's replace the ram_size check by a proper physical address space
check (for example, to prepare for memory hotplug), trigger addressing
exceptions and trace the return value of the storage key getter/setter.
Provide an helper mmu_absolute_addr_valid() to be used in other context
soon. Always test for "read" instead of "write" as we are not actually
modifying the page itself.
Signed-off-by: David Hildenbrand <david@redhat.com>
Acked-by: Thomas Huth <thuth@redhat.com>
Message-Id: <20210903155514.44772-5-david@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
Diffstat (limited to 'target')
-rw-r--r-- | target/s390x/helper.h | 6 | ||||
-rw-r--r-- | target/s390x/mmu_helper.c | 8 | ||||
-rw-r--r-- | target/s390x/s390x-internal.h | 1 | ||||
-rw-r--r-- | target/s390x/tcg/mem_helper.c | 36 |
4 files changed, 35 insertions, 16 deletions
diff --git a/target/s390x/helper.h b/target/s390x/helper.h index 6215ca00bc..271b081e8c 100644 --- a/target/s390x/helper.h +++ b/target/s390x/helper.h @@ -336,9 +336,9 @@ DEF_HELPER_FLAGS_4(stctl, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_4(stctg, TCG_CALL_NO_WG, void, env, i32, i64, i32) DEF_HELPER_FLAGS_2(testblock, TCG_CALL_NO_WG, i32, env, i64) DEF_HELPER_FLAGS_3(tprot, TCG_CALL_NO_WG, i32, env, i64, i64) -DEF_HELPER_FLAGS_2(iske, TCG_CALL_NO_RWG_SE, i64, env, i64) -DEF_HELPER_FLAGS_3(sske, TCG_CALL_NO_RWG, void, env, i64, i64) -DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_NO_RWG, i32, env, i64) +DEF_HELPER_2(iske, i64, env, i64) +DEF_HELPER_3(sske, void, env, i64, i64) +DEF_HELPER_2(rrbe, i32, env, i64) DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) DEF_HELPER_4(sigp, i32, env, i64, i32, i32) diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index d779a9fc51..0620b1803e 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -94,6 +94,14 @@ target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr) return raddr; } +bool mmu_absolute_addr_valid(target_ulong addr, bool is_write) +{ + return address_space_access_valid(&address_space_memory, + addr & TARGET_PAGE_MASK, + TARGET_PAGE_SIZE, is_write, + MEMTXATTRS_UNSPECIFIED); +} + static inline bool read_table_entry(CPUS390XState *env, hwaddr gaddr, uint64_t *entry) { diff --git a/target/s390x/s390x-internal.h b/target/s390x/s390x-internal.h index 5506f185e8..d246d26b04 100644 --- a/target/s390x/s390x-internal.h +++ b/target/s390x/s390x-internal.h @@ -373,6 +373,7 @@ void probe_write_access(CPUS390XState *env, uint64_t addr, uint64_t len, /* mmu_helper.c */ +bool mmu_absolute_addr_valid(target_ulong addr, bool is_write); int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, target_ulong *raddr, int *flags, uint64_t *tec); int mmu_translate_real(CPUS390XState *env, target_ulong raddr, int rw, diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index dd506d8d17..a44a107374 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -28,6 +28,7 @@ #include "qemu/int128.h" #include "qemu/atomic128.h" #include "tcg/tcg.h" +#include "trace.h" #if !defined(CONFIG_USER_ONLY) #include "hw/s390x/storage-keys.h" @@ -2171,15 +2172,15 @@ uint32_t HELPER(tprot)(CPUS390XState *env, uint64_t a1, uint64_t a2) /* insert storage key extended */ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) { - MachineState *ms = MACHINE(qdev_get_machine()); static S390SKeysState *ss; static S390SKeysClass *skeyclass; uint64_t addr = wrap_address(env, r2); uint8_t key; + int rc; addr = mmu_real2abs(env, addr); - if (addr > ms->ram_size) { - return 0; + if (!mmu_absolute_addr_valid(addr, false)) { + tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC()); } if (unlikely(!ss)) { @@ -2187,7 +2188,9 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) skeyclass = S390_SKEYS_GET_CLASS(ss); } - if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) { + rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); + if (rc) { + trace_get_skeys_nonzero(rc); return 0; } return key; @@ -2196,15 +2199,15 @@ uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) /* set storage key extended */ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) { - MachineState *ms = MACHINE(qdev_get_machine()); static S390SKeysState *ss; static S390SKeysClass *skeyclass; uint64_t addr = wrap_address(env, r2); uint8_t key; + int rc; addr = mmu_real2abs(env, addr); - if (addr > ms->ram_size) { - return; + if (!mmu_absolute_addr_valid(addr, false)) { + tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC()); } if (unlikely(!ss)) { @@ -2213,7 +2216,10 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) } key = r1 & 0xfe; - skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); + rc = skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); + if (rc) { + trace_set_skeys_nonzero(rc); + } /* * As we can only flush by virtual address and not all the entries * that point to a physical address we have to flush the whole TLB. @@ -2224,15 +2230,15 @@ void HELPER(sske)(CPUS390XState *env, uint64_t r1, uint64_t r2) /* reset reference bit extended */ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) { - MachineState *ms = MACHINE(qdev_get_machine()); uint64_t addr = wrap_address(env, r2); static S390SKeysState *ss; static S390SKeysClass *skeyclass; uint8_t re, key; + int rc; addr = mmu_real2abs(env, addr); - if (addr > ms->ram_size) { - return 0; + if (!mmu_absolute_addr_valid(addr, false)) { + tcg_s390_program_interrupt(env, PGM_ADDRESSING, GETPC()); } if (unlikely(!ss)) { @@ -2240,14 +2246,18 @@ uint32_t HELPER(rrbe)(CPUS390XState *env, uint64_t r2) skeyclass = S390_SKEYS_GET_CLASS(ss); } - if (skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) { + rc = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); + if (rc) { + trace_get_skeys_nonzero(rc); return 0; } re = key & (SK_R | SK_C); key &= ~SK_R; - if (skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key)) { + rc = skeyclass->set_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); + if (rc) { + trace_set_skeys_nonzero(rc); return 0; } /* |