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
