diff options
author | David Hildenbrand <david@redhat.com> | 2019-09-03 14:52:25 +0200 |
---|---|---|
committer | David Hildenbrand <david@redhat.com> | 2019-09-23 09:28:29 +0200 |
commit | fbc17598d509be10d5d2349090bbb889ccb4f055 (patch) | |
tree | 42179a74d817d385157a85d091b7b0e8dfd6d7c5 /target/s390x/mem_helper.c | |
parent | d292671ade5408197e36887dc554427a91edc498 (diff) | |
download | qemu-fbc17598d509be10d5d2349090bbb889ccb4f055.zip qemu-fbc17598d509be10d5d2349090bbb889ccb4f055.tar.gz qemu-fbc17598d509be10d5d2349090bbb889ccb4f055.tar.bz2 |
s390x/tcg: MVCL: Detect destructive overlaps
We'll have to zero-out unused bit positions, so make sure to write the
addresses back.
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: David Hildenbrand <david@redhat.com>
Diffstat (limited to 'target/s390x/mem_helper.c')
-rw-r--r-- | target/s390x/mem_helper.c | 19 |
1 files changed, 18 insertions, 1 deletions
diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index b02ad14..223312a 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -52,6 +52,19 @@ static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key) return true; } +static bool is_destructive_overlap(CPUS390XState *env, uint64_t dest, + uint64_t src, uint32_t len) +{ + if (!len || src == dest) { + return false; + } + /* Take care of wrapping at the end of address space. */ + if (unlikely(wrap_address(env, src + len - 1) < src)) { + return dest > src || dest <= wrap_address(env, src + len - 1); + } + return dest > src && dest <= src + len - 1; +} + /* Reduce the length so that addr + len doesn't cross a page boundary. */ static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr) { @@ -787,7 +800,11 @@ uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) uint8_t pad = env->regs[r2 + 1] >> 24; uint32_t cc; - cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra); + if (is_destructive_overlap(env, dest, src, MIN(srclen, destlen))) { + cc = 3; + } else { + cc = do_mvcl(env, &dest, &destlen, &src, &srclen, pad, 1, ra); + } env->regs[r1 + 1] = deposit64(env->regs[r1 + 1], 0, 24, destlen); env->regs[r2 + 1] = deposit64(env->regs[r2 + 1], 0, 24, srclen); |