On Mon, Jul 27, 2026 at 05:28:07PM +0300, Doru Blânzeanu wrote:
> Single-step by toggling RFLAGS.TF around the vCPU run, as WHPX does.
> TF is set only on the live register, never in env->eflags, so it is not read
> back and re-applied by a later register store.
> The resulting #DB is reported to gdb by mshv_handle_debug() whenever the vCPU
> is single-stepping.
> 
> Signed-off-by: Doru Blânzeanu <[email protected]>
> ---
>  target/i386/mshv/mshv-cpu.c | 50 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
> 
> diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c
> index 2333d3304a..036b142113 100644
> --- a/target/i386/mshv/mshv-cpu.c
> +++ b/target/i386/mshv/mshv-cpu.c
> @@ -1974,17 +1974,67 @@ static int handle_debug(CPUState *cpu, hv_message 
> *msg)
>      return 0;
>  }
>  
> +/*
> + * Flip RFLAGS.TF like WHPX. Set it only on the live register, not 
> env->eflags,
> + * so a later store won't put it back.
> + */
> +static int arch_set_single_step(CPUState *cpu, bool enable)
> +{
> +    X86CPU *x86cpu = X86_CPU(cpu);
> +    CPUX86State *env = &x86cpu->env;
> +    hv_register_assoc assoc = { .name = HV_X64_REGISTER_RFLAGS };
> +    uint64_t rflags;
> +    int ret;
> +
> +    if (env->regs_page && env->regs_page->isvalid != 0) {
> +        rflags = env->regs_page->rflags;
> +        rflags = enable ? (rflags | TF_MASK) : (rflags & ~TF_MASK);
> +        env->regs_page->rflags = rflags;
> +        env->regs_page->dirty |= (1u << HV_X64_REGISTER_CLASS_FLAGS);
> +        return 0;
> +    }
> +
> +    ret = mshv_get_generic_regs(cpu, &assoc, 1);
> +    if (ret < 0) {
> +        return ret;
> +    }
> +    rflags = assoc.value.reg64;
> +    rflags = enable ? (rflags | TF_MASK) : (rflags & ~TF_MASK);
> +    assoc.value.reg64 = rflags;
> +    return mshv_set_generic_regs(cpu, &assoc, 1);
> +}
> +
>  int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit 
> *exit)
>  {
>      int ret;
>      enum MshvVmExit exit_reason;
>      int cpu_fd = mshv_vcpufd(cpu);
> +    bool single_step;
> +
> +    /* enable single stepping by flipping RFLAGS.TF */
> +    single_step = cpu_single_stepping(cpu);
> +    if (single_step) {
> +        ret = arch_set_single_step(cpu, true);
> +        if (ret < 0) {
> +            error_report("Failed to arm single-step (TF) on vcpu %d: %s",
> +                         cpu->cpu_index, strerror(-ret));
> +            *exit = MshvVmExitShutdown;
> +            return -1;
> +        }
> +    }
>  
>      ret = ioctl(cpu_fd, MSHV_RUN_VP, msg);
>      if (ret < 0) {
>          return MshvVmExitShutdown;
>      }
>  
> +    /* disable single stepping by flipping RFLAGS.TF */
> +    if (single_step && arch_set_single_step(cpu, false) < 0) {
> +        error_report("Failed to clear single-step (TF) on vcpu %d",
> +                     cpu->cpu_index);
> +        return -1;
> +    }
> +
>      switch (msg->header.message_type) {
>      case HVMSG_UNRECOVERABLE_EXCEPTION:
>          return MshvVmExitShutdown;
> -- 
> 2.53.0

Reviewed-by: Magnus Kulke <[email protected]>

Reply via email to