From: Doru Blânzeanu <[email protected]>

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 <[email protected]>
Fixes: 6dec60528c (target/i386/mshv: Implement mshv_vcpu_run())
Reviewed-by: Mohamed Mediouni <[email protected]>
Reviewed-by: Magnus Kulke <[email protected]>
Signed-off-by: Magnus Kulke <[email protected]>
---
 target/i386/mshv/mshv-cpu.c | 69 +++++++++++++++++++++++++++----------
 1 file changed, 51 insertions(+), 18 deletions(-)

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;
-- 
2.34.1


Reply via email to