From: Magnus Kulke <magnuskulke@linux.microsoft.com>
To: "Doru Blânzeanu" <dblanzeanu@linux.microsoft.com>
Cc: qemu-devel@nongnu.org, Zhao Liu <zhao1.liu@intel.com>,
Wei Liu <wei.liu@kernel.org>, Paolo Bonzini <pbonzini@redhat.com>
Subject: Re: [PATCH v2 7/7] target/i386/mshv: fix pio handlers clobbering device-modified registers
Date: Wed, 6 May 2026 16:38:57 +0200 [thread overview]
Message-ID: <aftSgerKdLtpmMMR@example.com> (raw)
In-Reply-To: <20260505185028.237207-8-dblanzeanu@linux.microsoft.com>
On Tue, May 05, 2026 at 09:50:28PM +0300, Doru Blânzeanu wrote:
> When a device handler (e.g. vmport) calls cpu_synchronize_state() during
> I/O port dispatch, it sets cpu->accel->dirty = true and may modify
> registers directly in env. The old PIO code ignored this: it
> unconditionally wrote the stale info->rax from the VM-exit intercept
> message back to the hypervisor and then cleared dirty, discarding any
> register changes made by the device.
>
> Bifurcate both handlers on cpu->accel->dirty:
>
> handle_pio_non_str:
> - dirty path: update env->eip directly. For reads (IN), merge the I/O
> result into env->regs[R_EAX] (which may have been modified by the
> device) rather than info->rax. For writes (OUT), leave RAX untouched.
> Flush all registers via mshv_store_regs() and clear dirty.
> - non-dirty path: write RIP and RAX via set_x64_registers hypercall as
> before.
>
> handle_pio_str:
> - dirty path: update env->eip and the appropriate index register
> (RSI for OUTS, RDI for INS) directly. Flush via mshv_store_regs()
> and clear dirty.
> - non-dirty path: write the index register and RIP via
> set_x64_registers. Drop the RAX assignment that was here before;
> string I/O does not modify RAX, and set_x64_registers is hardcoded
> to write only 2 registers so the third slot was silently ignored
> anyway.
>
> Remove the unconditional "cpu->accel->dirty = false" at the end of both
> handlers. In the non-dirty fast path it was redundant (already false).
> In the dirty path it was actively harmful: it told the vcpu run loop
> that env was clean when it was not, losing the device's modifications.
>
> Signed-off-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com>
> ---
> target/i386/mshv/mshv-cpu.c | 82 ++++++++++++++++++++++++++-----------
> 1 file changed, 59 insertions(+), 23 deletions(-)
>
> diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
> index 0cfac26a5c..7be3fdcc45 100644
> --- a/target/i386/mshv/mshv-cpu.c
> +++ b/target/i386/mshv/mshv-cpu.c
> @@ -1348,7 +1348,7 @@ static int pio_write(uint64_t port, const uint8_t *data, uintptr_t size,
> return ret;
> }
>
> -static int handle_pio_non_str(const CPUState *cpu,
> +static int handle_pio_non_str(CPUState *cpu,
> hv_x64_io_port_intercept_message *info)
> {
> size_t len = info->access_info.access_size;
> @@ -1357,10 +1357,12 @@ static int handle_pio_non_str(const CPUState *cpu,
> uint32_t val, eax;
> const uint32_t eax_mask = 0xffffffffu >> (32 - len * 8);
> size_t insn_len;
> - uint64_t rip, rax;
> + uint64_t rip;
> uint32_t reg_names[2];
> uint64_t reg_values[2];
> uint16_t port = info->port_number;
> + X86CPU *x86_cpu = X86_CPU(cpu);
> + CPUX86State *env = &x86_cpu->env;
>
> if (access_type == HV_X64_INTERCEPT_ACCESS_TYPE_WRITE) {
> union {
> @@ -1391,21 +1393,40 @@ static int handle_pio_non_str(const CPUState *cpu,
>
> /* Advance RIP and update RAX */
> rip = info->header.rip + insn_len;
> - rax = info->rax;
>
> - reg_names[0] = HV_X64_REGISTER_RIP;
> - reg_values[0] = rip;
> - reg_names[1] = HV_X64_REGISTER_RAX;
> - reg_values[1] = rax;
> + if (cpu->accel->dirty) {
> + env->eip = rip;
> + if (access_type != HV_X64_INTERCEPT_ACCESS_TYPE_WRITE) {
> + /*
> + * For reads, merge the I/O result into the current RAX.
> + * Use env->regs[R_EAX] as the base since a device handler
> + * (e.g. vmport) may have called cpu_synchronize_state()
> + * and modified registers.
> + */
> + eax = (((uint32_t)env->regs[R_EAX]) & ~eax_mask)
> + | (val & eax_mask);
> + env->regs[R_EAX] = (uint64_t)eax;
> + }
> + /* Sync modified standard registers back and clear dirty. */
> + ret = mshv_store_regs(cpu);
> + if (ret < 0) {
> + error_report("Failed to store registers after PIO");
> + return -1;
> + }
> + cpu->accel->dirty = false;
> + } else {
> + reg_names[0] = HV_X64_REGISTER_RIP;
> + reg_values[0] = rip;
> + reg_names[1] = HV_X64_REGISTER_RAX;
> + reg_values[1] = info->rax;
>
> - ret = set_x64_registers(cpu, reg_names, reg_values);
> - if (ret < 0) {
> - error_report("Failed to set x64 registers");
> - return -1;
> + ret = set_x64_registers(cpu, reg_names, reg_values);
> + if (ret < 0) {
> + error_report("Failed to set x64 registers");
> + return -1;
> + }
> }
>
> - cpu->accel->dirty = false;
> -
> return 0;
> }
>
> @@ -1521,6 +1542,7 @@ static int handle_pio_str(CPUState *cpu, hv_x64_io_port_intercept_message *info)
> bool repop = info->access_info.rep_prefix == 1;
> size_t repeat = repop ? info->rcx : 1;
> size_t insn_len = info->header.instruction_length;
> + uint64_t rip;
> bool direction_flag;
> uint32_t reg_names[3];
> uint64_t reg_values[3];
> @@ -1554,18 +1576,32 @@ static int handle_pio_str(CPUState *cpu, hv_x64_io_port_intercept_message *info)
> reg_values[0] = info->rdi;
> }
>
> - reg_names[1] = HV_X64_REGISTER_RIP;
> - reg_values[1] = info->header.rip + insn_len;
> - reg_names[2] = HV_X64_REGISTER_RAX;
> - reg_values[2] = info->rax;
> + rip = info->header.rip + insn_len;
>
> - ret = set_x64_registers(cpu, reg_names, reg_values);
> - if (ret < 0) {
> - error_report("Failed to set x64 registers");
> - return -1;
> - }
> + if (cpu->accel->dirty) {
> + env->eip = rip;
> + if (access_type == HV_X64_INTERCEPT_ACCESS_TYPE_WRITE) {
> + env->regs[R_ESI] = info->rsi;
> + } else {
> + env->regs[R_EDI] = info->rdi;
> + }
> + /* Sync modified standard registers back and clear dirty. */
> + ret = mshv_store_regs(cpu);
> + if (ret < 0) {
> + error_report("Failed to store registers after string PIO");
> + return -1;
> + }
> + cpu->accel->dirty = false;
> + } else {
> + reg_names[1] = HV_X64_REGISTER_RIP;
> + reg_values[1] = rip;
>
> - cpu->accel->dirty = false;
> + ret = set_x64_registers(cpu, reg_names, reg_values);
> + if (ret < 0) {
> + error_report("Failed to set x64 registers");
> + return -1;
> + }
> + }
>
> return 0;
> }
> --
> 2.53.0
Reviewed-by: Magnus Kulke <magnuskulke@linux.microsoft.com>
next prev parent reply other threads:[~2026-05-06 14:39 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-05 18:50 [PATCH v2 0/7] target/i386/mshv: use hv_vp_register_page for fast register access Doru Blânzeanu
2026-05-05 18:50 ` [PATCH v2 1/7] target/i386/mshv: remove duplicate function for reading vcpu registers Doru Blânzeanu
2026-05-06 10:34 ` Magnus Kulke
2026-05-06 10:35 ` Magnus Kulke
2026-05-07 13:12 ` Anirudh Rayabharam
2026-05-05 18:50 ` [PATCH v2 2/7] accel/mshv: move vcpu arch specific initialization after vcpu creation Doru Blânzeanu
2026-05-06 14:31 ` Magnus Kulke
2026-05-07 13:12 ` Anirudh Rayabharam
2026-05-05 18:50 ` [PATCH v2 3/7] include/hw/hyperv: add hv_vp_register_page struct definition Doru Blânzeanu
2026-05-06 10:38 ` Magnus Kulke
2026-05-07 13:15 ` Anirudh Rayabharam
2026-05-05 18:50 ` [PATCH v2 4/7] target/i386/mshv: hv_vp_register_page setup for the vcpu Doru Blânzeanu
2026-05-06 14:36 ` Magnus Kulke
2026-05-05 18:50 ` [PATCH v2 5/7] target/i386/mshv: use the register page to get registers Doru Blânzeanu
2026-05-07 13:23 ` Anirudh Rayabharam
2026-05-05 18:50 ` [PATCH v2 6/7] target/i386/mshv: use the register page to set registers Doru Blânzeanu
2026-05-07 13:29 ` Anirudh Rayabharam
2026-05-05 18:50 ` [PATCH v2 7/7] target/i386/mshv: fix pio handlers clobbering device-modified registers Doru Blânzeanu
2026-05-06 14:38 ` Magnus Kulke [this message]
2026-05-06 14:43 ` [PATCH v2 0/7] target/i386/mshv: use hv_vp_register_page for fast register access Magnus Kulke
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aftSgerKdLtpmMMR@example.com \
--to=magnuskulke@linux.microsoft.com \
--cc=dblanzeanu@linux.microsoft.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=wei.liu@kernel.org \
--cc=zhao1.liu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.