Commit 0eb8ae4de0 for qemu.org

commit 0eb8ae4de0a3fbe08a8e58f99f7eee4df71bf238
Author: Doru Blânzeanu <dblanzeanu@linux.microsoft.com>
Date:   Thu Apr 9 20:53:34 2026 +0300

    target/i386/mshv: fix read/write memory across the page boundary

    Previously, read_memory and write_memory performed a single GVA-to-GPA
    translation for the entire buffer. If the buffer spanned a page
    boundary, the translated GPA was only valid for the first page, causing
    incorrect reads/writes for the remainder.

    Fix both functions to loop over pages, translating and accessing each
    page-aligned chunk separately.

    Signed-off-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com>
    Fixes: 6dec60528c (target/i386/mshv: Implement mshv_vcpu_run())
    Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
    Reviewed-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
    Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com>

diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index f528dd2b9a..b8a6924088 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -1831,21 +1831,38 @@ static int read_memory(const CPUState *cpu, uint64_t initial_gva,
 {
     int ret;
     uint64_t gpa, flags;
+    uint64_t cur_gva = gva;
+    size_t page_left, chunk;
+    uint8_t *cur_data = data;

-    if (gva == initial_gva) {
-        gpa = initial_gpa;
-    } else {
-        flags = HV_TRANSLATE_GVA_VALIDATE_READ;
-        ret = translate_gva(cpu, gva, &gpa, flags);
-        if (ret < 0) {
-            return -1;
+    /*
+     * If the read spans multiple pages,
+     * we need to translate and read each page separately
+     */
+    while (len > 0) {
+        page_left = HV_HYP_PAGE_SIZE - (cur_gva & (HV_HYP_PAGE_SIZE - 1));
+        chunk = MIN(len, page_left);
+
+        if (cur_gva == initial_gva) {
+            gpa = initial_gpa;
+        } else {
+            flags = HV_TRANSLATE_GVA_VALIDATE_READ;
+            ret = translate_gva(cpu, cur_gva, &gpa, flags);
+            if (ret < 0) {
+                return -1;
+            }
         }

-        ret = mshv_guest_mem_read(gpa, data, len, false, false);
+        ret = mshv_guest_mem_read(gpa, cur_data, chunk,
+                                  false, false);
         if (ret < 0) {
             error_report("failed to read guest mem");
             return -1;
         }
+
+        cur_gva += chunk;
+        cur_data += chunk;
+        len -= chunk;
     }

     return 0;
@@ -1856,18 +1873,34 @@ static int write_memory(const CPUState *cpu, uint64_t gva, const uint8_t *data,
 {
     int ret;
     uint64_t gpa, flags;
+    uint64_t cur_gva = gva;
+    size_t page_left, chunk;
+    const uint8_t *cur_data = data;

-    flags = HV_TRANSLATE_GVA_VALIDATE_WRITE;
-    ret = translate_gva(cpu, gva, &gpa, flags);
-    if (ret < 0) {
-        error_report("failed to translate gva to gpa");
-        return -1;
-    }
+    /*
+     * If the write spans multiple pages,
+     * we need to translate and write each page separately
+     */
+    while (len > 0) {
+        page_left = HV_HYP_PAGE_SIZE - (cur_gva & (HV_HYP_PAGE_SIZE - 1));
+        chunk = MIN(len, page_left);

-    ret = mshv_guest_mem_write(gpa, data, len, false);
-    if (ret != MEMTX_OK) {
-        error_report("failed to write to mmio");
-        return -1;
+        flags = HV_TRANSLATE_GVA_VALIDATE_WRITE;
+        ret = translate_gva(cpu, cur_gva, &gpa, flags);
+        if (ret < 0) {
+            error_report("failed to translate gva to gpa");
+            return -1;
+        }
+
+        ret = mshv_guest_mem_write(gpa, cur_data, chunk, false);
+        if (ret != MEMTX_OK) {
+            error_report("failed to write to mmio");
+            return -1;
+        }
+
+        cur_gva += chunk;
+        cur_data += chunk;
+        len -= chunk;
     }

     return 0;