* [PATCH 0/1] target/i386/mshv: fix read and write memory across the page boundary
@ 2026-04-09 17:53 Doru Blânzeanu
2026-04-09 17:53 ` [PATCH 1/1] target/i386/mshv: fix read/write " Doru Blânzeanu
0 siblings, 1 reply; 5+ messages in thread
From: Doru Blânzeanu @ 2026-04-09 17:53 UTC (permalink / raw)
To: qemu-devel; +Cc: Wei Liu, Magnus Kulke
This fixes the guest memory reading and writing spanning multiple pages for mshv Port I/O.
Currently, the read_memory and write_memory functions only translate GVA-to-GPA once per buffer.
In case the buffer is bigger than a page, the translation is only valid for the first page.
Doru Blânzeanu (1):
target/i386/mshv: fix read/write memory across the page boundary
target/i386/mshv/mshv-cpu.c | 71 +++++++++++++++++++++++++++----------
1 file changed, 52 insertions(+), 19 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/1] target/i386/mshv: fix read/write memory across the page boundary
2026-04-09 17:53 [PATCH 0/1] target/i386/mshv: fix read and write memory across the page boundary Doru Blânzeanu
@ 2026-04-09 17:53 ` Doru Blânzeanu
2026-04-09 23:38 ` Mohamed Mediouni
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Doru Blânzeanu @ 2026-04-09 17:53 UTC (permalink / raw)
To: qemu-devel; +Cc: Wei Liu, Magnus Kulke
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>
---
target/i386/mshv/mshv-cpu.c | 71 +++++++++++++++++++++++++++----------
1 file changed, 52 insertions(+), 19 deletions(-)
diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
index 2bc978deb2..afdb6b6e29 100644
--- a/target/i386/mshv/mshv-cpu.c
+++ b/target/i386/mshv/mshv-cpu.c
@@ -1316,21 +1316,38 @@ static int read_memory(const CPUState *cpu, uint64_t initial_gva,
{
int ret;
uint64_t gpa, flags;
-
- 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;
+ uint64_t cur_gva = gva;
+ size_t page_left, chunk;
+ uint8_t *cur_data = data;
+
+ /*
+ * 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;
@@ -1341,18 +1358,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;
+
+ /*
+ * 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);
+
+ 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;
+ }
- 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;
- }
+ ret = mshv_guest_mem_write(gpa, cur_data, chunk, false);
+ if (ret != MEMTX_OK) {
+ error_report("failed to write to mmio");
+ return -1;
+ }
- ret = mshv_guest_mem_write(gpa, data, len, 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.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH 1/1] target/i386/mshv: fix read/write memory across the page boundary
2026-04-09 17:53 ` [PATCH 1/1] target/i386/mshv: fix read/write " Doru Blânzeanu
@ 2026-04-09 23:38 ` Mohamed Mediouni
2026-04-10 14:52 ` Magnus Kulke
2026-04-13 11:57 ` Magnus Kulke
2 siblings, 0 replies; 5+ messages in thread
From: Mohamed Mediouni @ 2026-04-09 23:38 UTC (permalink / raw)
To: Doru Blânzeanu; +Cc: qemu-devel, Wei Liu, Magnus Kulke
> On 9. Apr 2026, at 19:53, Doru Blânzeanu <dblanzeanu@linux.microsoft.com> wrote:
>
> 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>
Hi,
Reviewed-by: Mohamed Mediouni <mohamed@unpredictable.fr>
> ---
> target/i386/mshv/mshv-cpu.c | 71 +++++++++++++++++++++++++++----------
> 1 file changed, 52 insertions(+), 19 deletions(-)
>
> diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
> index 2bc978deb2..afdb6b6e29 100644
> --- a/target/i386/mshv/mshv-cpu.c
> +++ b/target/i386/mshv/mshv-cpu.c
> @@ -1316,21 +1316,38 @@ static int read_memory(const CPUState *cpu, uint64_t initial_gva,
> {
> int ret;
> uint64_t gpa, flags;
> -
> - 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;
> + uint64_t cur_gva = gva;
> + size_t page_left, chunk;
> + uint8_t *cur_data = data;
> +
> + /*
> + * 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;
> @@ -1341,18 +1358,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;
> +
> + /*
> + * 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);
> +
> + 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;
> + }
>
> - 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;
> - }
> + ret = mshv_guest_mem_write(gpa, cur_data, chunk, false);
> + if (ret != MEMTX_OK) {
> + error_report("failed to write to mmio");
> + return -1;
> + }
>
> - ret = mshv_guest_mem_write(gpa, data, len, 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.53.0
>
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/1] target/i386/mshv: fix read/write memory across the page boundary
2026-04-09 17:53 ` [PATCH 1/1] target/i386/mshv: fix read/write " Doru Blânzeanu
2026-04-09 23:38 ` Mohamed Mediouni
@ 2026-04-10 14:52 ` Magnus Kulke
2026-04-13 11:57 ` Magnus Kulke
2 siblings, 0 replies; 5+ messages in thread
From: Magnus Kulke @ 2026-04-10 14:52 UTC (permalink / raw)
To: Doru Blânzeanu; +Cc: qemu-devel, Wei Liu
On Thu, Apr 09, 2026 at 08:53:34PM +0300, Doru Blânzeanu wrote:
> 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>
Thanks, looks good. Confirmed with tests that the issue is resolved.
Reviewed-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 1/1] target/i386/mshv: fix read/write memory across the page boundary
2026-04-09 17:53 ` [PATCH 1/1] target/i386/mshv: fix read/write " Doru Blânzeanu
2026-04-09 23:38 ` Mohamed Mediouni
2026-04-10 14:52 ` Magnus Kulke
@ 2026-04-13 11:57 ` Magnus Kulke
2 siblings, 0 replies; 5+ messages in thread
From: Magnus Kulke @ 2026-04-13 11:57 UTC (permalink / raw)
To: Doru Blânzeanu; +Cc: qemu-devel, Wei Liu
On Thu, Apr 09, 2026 at 08:53:34PM +0300, Doru Blânzeanu wrote:
> 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>
> ---
> target/i386/mshv/mshv-cpu.c | 71 +++++++++++++++++++++++++++----------
> 1 file changed, 52 insertions(+), 19 deletions(-)
>
> diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
> index 2bc978deb2..afdb6b6e29 100644
> --- a/target/i386/mshv/mshv-cpu.c
> +++ b/target/i386/mshv/mshv-cpu.c
> @@ -1316,21 +1316,38 @@ static int read_memory(const CPUState *cpu, uint64_t initial_gva,
> {
> int ret;
> uint64_t gpa, flags;
> -
> - 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;
> + uint64_t cur_gva = gva;
> + size_t page_left, chunk;
> + uint8_t *cur_data = data;
> +
> + /*
> + * 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;
> @@ -1341,18 +1358,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;
> +
> + /*
> + * 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);
> +
> + 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;
> + }
>
> - 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;
> - }
> + ret = mshv_guest_mem_write(gpa, cur_data, chunk, false);
> + if (ret != MEMTX_OK) {
> + error_report("failed to write to mmio");
> + return -1;
> + }
>
> - ret = mshv_guest_mem_write(gpa, data, len, 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.53.0
Fixes: 6dec60528c (target/i386/mshv: Implement mshv_vcpu_run())
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-13 11:58 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-09 17:53 [PATCH 0/1] target/i386/mshv: fix read and write memory across the page boundary Doru Blânzeanu
2026-04-09 17:53 ` [PATCH 1/1] target/i386/mshv: fix read/write " Doru Blânzeanu
2026-04-09 23:38 ` Mohamed Mediouni
2026-04-10 14:52 ` Magnus Kulke
2026-04-13 11:57 ` Magnus Kulke
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.