summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--target-s390x/mem_helper.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index 04500ab06a..b4e5d44011 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -213,21 +213,22 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
     if (dest == (src + 1)) {
         memset(g2h(dest), cpu_ldub_data(env, src), l + 1);
         return;
-    } else {
+    /* mvc and memmove do not behave the same when areas overlap! */
+    } else if ((dest < src) || (src + l < dest)) {
         memmove(g2h(dest), g2h(src), l + 1);
         return;
     }
 #endif
 
     /* handle the parts that fit into 8-byte loads/stores */
-    if (dest != (src + 1)) {
+    if ((dest + 8 <= src) || (src + 8 <= dest)) {
         for (i = 0; i < l_64; i++) {
             cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x));
             x += 8;
         }
     }
 
-    /* slow version crossing pages with byte accesses */
+    /* slow version with byte accesses which always work */
     for (i = x; i <= l; i++) {
         cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
     }