From nobody Mon Sep 28 02:05:28 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785523652; cv=none; d=zohomail.com; s=zohoarc; b=mM1/jkON2VMxwFUSA5K8icZL92xSPqOC73EaJbIY25yJEuDWoe0TQjGrsZ7jjRhxwHajltTcbIjAfcgYSvp0dyyI0N/xP4iGi9KUPbCvCef5XiYELb8uTQfoqyCsSF7HcF8swyJNGPGVAzTPusNo/eWyyddshwDjSy+JLzIHGRY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785523652; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=zX5yTOow2rpg7OVRkUI8/A9eA3aPrnOgzFBXmaniZmI=; b=KQoN0dLBU85bXii+KiEmCWmyf+HCYBEhTakHADQB/IkY1gfk3+IHG2rUsH1CYrpdl7DAdQaDQOKFKFBwm2gdjg8rs+tNfAO+G1vTK7bTdqB7ZyA2qtZt0yFm9wePHmDql7LnxdGQFIjIeSuaZifwSVWWC0m5R0jGs8RRcyzpc7Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785523652502183.30072899914057; Fri, 31 Jul 2026 11:47:32 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsGC-0003wF-0h; Fri, 31 Jul 2026 14:47:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpsFz-0003vS-K1 for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:46:56 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsFx-0000ke-Sc for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:46:55 -0400 Received: from laptop.localdomain (unknown [86.121.140.206]) by linux.microsoft.com (Postfix) with ESMTPSA id 1EE5E20B7168; Fri, 31 Jul 2026 11:46:32 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 1EE5E20B7168 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785523594; bh=zX5yTOow2rpg7OVRkUI8/A9eA3aPrnOgzFBXmaniZmI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dd9edWlD9hRcApwvTGoyyrMFYzuhwHGEf45b6O4Xhz9tdc4uW1kXwvihpWVLDwoDI cgrHjpxT4YDUIODwgcsLMenYAOR2JmcjAXP22+VKbPx5T3p+C/79A+TQihO+mbrfvr ee7YNQJ1vR88FSKaAzmIk47l4deayhM6cWYIVIWQ= From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= To: qemu-devel@nongnu.org Cc: Wei Liu , Wei Liu , Magnus Kulke , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , Magnus Kulke Subject: [PATCH v2 1/4] include/hw/hyperv: add ABI for exception intercepts and pending events Date: Fri, 31 Jul 2026 21:46:39 +0300 Message-ID: <20260731184643.89604-2-dblanzeanu@linux.microsoft.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> References: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=dblanzeanu@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785523654065158500 Import the hypervisor definitions needed to intercept guest exceptions and to inject events back into a guest, in preparation for gdbstub debugging support in the MSHV accelerator. Add: - union hv_intercept_parameters, struct hv_input_install_intercept and HVCALL_INSTALL_INTERCEPT, used to install an exception intercept on the partition; - struct hv_x64_exception_intercept_message, the message delivered on an intercepted exception, carrying the faulting RIP, the exception vector and the instruction bytes; - HV_X64_PENDING_EVENT_EXCEPTION, the pending-event type for an exception. These definitions mirror the hypervisor headers and have no functional effect on their own. Signed-off-by: Doru Bl=C3=A2nzeanu Reviewed-by: Magnus Kulke --- include/hw/hyperv/hvgdk_mini.h | 56 ++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/include/hw/hyperv/hvgdk_mini.h b/include/hw/hyperv/hvgdk_mini.h index f8838a31bb..c81928d0c2 100644 --- a/include/hw/hyperv/hvgdk_mini.h +++ b/include/hw/hyperv/hvgdk_mini.h @@ -22,6 +22,9 @@ #define HV_X64_MSR_TSC_FREQUENCY 0x40000022 #define HV_X64_MSR_APIC_FREQUENCY 0x40000023 =20 +/* event_type values for hv_x64_pending_exception_event */ +#define HV_X64_PENDING_EVENT_EXCEPTION 0 + typedef enum hv_register_name { /* Pending Interruption Register */ HV_REGISTER_PENDING_INTERRUPTION =3D 0x00010002, @@ -236,6 +239,29 @@ enum hv_intercept_type { HV_INTERCEPT_TYPE_INVALID =3D 0XFFFFFFFF, }; =20 +union hv_intercept_parameters { + /* HV_INTERCEPT_PARAMETERS is defined to be an 8-byte field. */ + uint64_t as_uint64; + /* HV_INTERCEPT_TYPE_X64_IO_PORT */ + uint16_t io_port; + /* HV_INTERCEPT_TYPE_X64_CPUID */ + uint32_t cpuid_index; + /* HV_INTERCEPT_TYPE_X64_APIC_WRITE */ + uint32_t apic_write_mask; + /* HV_INTERCEPT_TYPE_EXCEPTION */ + uint16_t exception_vector; + /* HV_INTERCEPT_TYPE_X64_MSR_INDEX */ + uint32_t msr_index; + /* N.B. Other intercept types do not have any parameters. */ +}; + +struct hv_input_install_intercept { + uint64_t partition_id; + uint32_t access_type; /* mask */ + uint32_t intercept_type; /* enum hv_intercept_type */ + union hv_intercept_parameters intercept_parameter; +} QEMU_PACKED; + struct hv_u128 { uint64_t low_part; uint64_t high_part; @@ -836,6 +862,35 @@ struct hv_x64_memory_intercept_message { uint8_t instruction_bytes[16]; } QEMU_PACKED; =20 +struct hv_x64_exception_intercept_message { + struct hv_x64_intercept_message_header header; + uint16_t exception_vector; + uint8_t exception_info; + uint8_t instruction_byte_count; + uint32_t error_code; + uint64_t exception_parameter; /* DR6 for #DB, CR2 for #PF */ + uint64_t reserved; + uint8_t instruction_bytes[16]; + struct hv_x64_segment_register ds_segment; + struct hv_x64_segment_register ss_segment; + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; +} QEMU_PACKED; + union hv_message_flags { uint8_t asu8; struct { @@ -943,6 +998,7 @@ struct hv_cpuid { =20 #define HVCALL_GET_PARTITION_PROPERTY 0x0044 #define HVCALL_SET_PARTITION_PROPERTY 0x0045 +#define HVCALL_INSTALL_INTERCEPT 0x004d #define HVCALL_GET_VP_REGISTERS 0x0050 #define HVCALL_SET_VP_REGISTERS 0x0051 #define HVCALL_TRANSLATE_VIRTUAL_ADDRESS 0x0052 --=20 2.53.0 From nobody Mon Sep 28 02:05:28 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785523690; cv=none; d=zohomail.com; s=zohoarc; b=BJqSddyaj06ff2XA2p+rl0hpOpKHwroj2hlFTj33+5djiMPl0C1rQbWR7b7RGY2SwKM2RwvP3kW69duMeyGr8T7k5nAgrUrhlqOvTUODNPFMuWh1hKhTFuCbRSvm/v6n6q733Ej8ThQBmnjdm7uqChHOPleAC/WFpgEml7L0kMY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785523690; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=Q5BW1cxV5Rye1cq7JV2V7aYyYQyjcZY2OOGFiPkv7nM=; b=TRGg0RYkWR3zuW7xn71sjuXiTnYpWJ/sms+udkaDLFMPQED1wZcWlbuKLbBHhsCza5sUZ+iPXzLqBNuMVV8+7zDm2fOtq+Fz21MJHCFHK5Kj+9IhnxA/D7vevyRs13cGAfqlYVxoyqs0gdZ4KjDqLxoypoMHWWeispnWRwxO6EU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785523690782290.3718899488299; Fri, 31 Jul 2026 11:48:10 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsGG-0003xU-EB; Fri, 31 Jul 2026 14:47:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpsG3-0003vh-88 for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:46:59 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsG0-0000ky-RX for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:46:59 -0400 Received: from laptop.localdomain (unknown [86.121.140.206]) by linux.microsoft.com (Postfix) with ESMTPSA id 9772220B7167; Fri, 31 Jul 2026 11:46:35 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 9772220B7167 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785523597; bh=Q5BW1cxV5Rye1cq7JV2V7aYyYQyjcZY2OOGFiPkv7nM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ViCAQV2JiSMUJeut96+Pegb6TE3QyCj+XrmifbKjv4W7n6jy5b+csu1BTS5HMmp26 ssbmWkkuG5nL63SzZS4Kyzsg72RXYVlz/FyMlNS+gk4gNCRXcmW1EFSmHdRWenkTJz /TEvz7A7P7OC1MyTKnYOcy30OdyFn0kt66Q8kkFY= From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= To: qemu-devel@nongnu.org Cc: Wei Liu , Wei Liu , Magnus Kulke , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , Magnus Kulke Subject: [PATCH v2 2/4] accel/mshv: add gdbstub software breakpoint support Date: Fri, 31 Jul 2026 21:46:40 +0300 Message-ID: <20260731184643.89604-3-dblanzeanu@linux.microsoft.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> References: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=dblanzeanu@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785523692011158500 Implement software breakpoint based guest debugging for the MSHV accelerator, modeled on the WHPX backend. The guest-visible debug registers are not used: a breakpoint is an INT1 (opcode 0xf1) patched into guest memory, which raises a #DB when executed. A partition-wide intercept on #DB is installed the first time a breakpoint (or single step) is requested. The intercept is not uninstalled, so it stays for the lifetime of the VM and every vmexit mshv_handle_debug() decides whether the #DB belongs to gdb (it hit one of our INT1 breakpoints)= or to the guest; a guest-owned #DB is handed back through a pending exception event so the guest takes it through its own IDT. Guest INT3 (#BP) is deliberately left to the guest's own IDT and is never intercepted. Signed-off-by: Doru Bl=C3=A2nzeanu Reviewed-by: Magnus Kulke --- accel/mshv/mshv-all.c | 165 +++++++++++++++++++++++++++++++++++- include/system/mshv_int.h | 14 +++ target/i386/mshv/mshv-cpu.c | 104 +++++++++++++++++++++++ 3 files changed, 282 insertions(+), 1 deletion(-) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index 72721d0f0d..afcb87b3b8 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -29,6 +29,7 @@ =20 #include "qemu/accel.h" #include "qemu/guest-random.h" +#include "gdbstub/enums.h" #include "accel/accel-ops.h" #include "accel/accel-cpu-ops.h" #include "exec/cpu-common.h" @@ -583,6 +584,10 @@ static int mshv_init(AccelState *as, MachineState *ms) s->nr_as =3D 1; s->as =3D g_new0(MshvAddressSpace, s->nr_as); =20 + QTAILQ_INIT(&s->sw_breakpoints); + + as->gdbstub.sstep_flags =3D SSTEP_ENABLE; + mshv_state =3D s; =20 mshv_init_irq_routing(s); @@ -607,6 +612,153 @@ static int mshv_destroy_vcpu(CPUState *cpu) return 0; } =20 +struct MshvSwBreakpoint *mshv_find_sw_breakpoint(CPUState *cpu, vaddr pc) +{ + struct MshvSwBreakpoint *bp; + + QTAILQ_FOREACH(bp, &mshv_state->sw_breakpoints, entry) { + if (bp->pc =3D=3D pc) { + return bp; + } + } + return NULL; +} + +static int mshv_install_exception_intercept(int vm_fd, uint16_t vector) +{ + struct hv_input_install_intercept in =3D {0}; + struct mshv_root_hvcall args =3D {0}; + int ret; + + in.access_type =3D 1 << HV_X64_INTERCEPT_ACCESS_TYPE_EXECUTE; + in.intercept_type =3D HV_INTERCEPT_TYPE_EXCEPTION; + in.intercept_parameter.as_uint64 =3D vector; + + args.code =3D HVCALL_INSTALL_INTERCEPT; + args.in_sz =3D sizeof(in); + args.in_ptr =3D (uint64_t)∈ + + ret =3D mshv_hvcall(vm_fd, &args); + if (ret < 0) { + error_report("Failed to install exception intercept for vector %u", + vector); + } + return ret; +} + +/* + * Install the #DB intercept. This is a permanent, partition-wide latch: i= t is + * installed once on the first debug use and stays for the lifetime of the= VM. + */ +static int mshv_init_exception_intercept(void) +{ + int ret; + + if (mshv_state->exception_intercepts_installed) { + return 0; + } + + /* Only #DB is needed: gdb breakpoints are INT1 (0xf1) */ + ret =3D mshv_install_exception_intercept(mshv_state->vm, 1); /* #DB */ + if (ret < 0) { + return ret; + } + + mshv_state->exception_intercepts_installed =3D true; + return 0; +} + +static int mshv_update_guest_debug(CPUState *cpu) +{ + if (cpu_single_stepping(cpu)) { + /* Installs exception intercept only on the first call */ + return mshv_init_exception_intercept(); + } + return 0; +} + +static int mshv_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType= type, + vaddr addr, vaddr len) +{ + struct MshvSwBreakpoint *bp; + int err; + + /* We don't use the guest's debug registers. */ + if (type !=3D GDB_BREAKPOINT_SW) { + return -ENOSYS; + } + + bp =3D mshv_find_sw_breakpoint(cpu, addr); + if (bp) { + bp->use_count++; + return 0; + } + + bp =3D g_new(struct MshvSwBreakpoint, 1); + bp->pc =3D addr; + bp->use_count =3D 1; + err =3D mshv_arch_insert_sw_breakpoint(cpu, bp); + if (err) { + g_free(bp); + return err; + } + + QTAILQ_INSERT_HEAD(&mshv_state->sw_breakpoints, bp, entry); + + /* Installs exception intercept only on the first call */ + return mshv_init_exception_intercept(); +} + +static int mshv_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType= type, + vaddr addr, vaddr len) +{ + struct MshvSwBreakpoint *bp; + int err; + + if (type !=3D GDB_BREAKPOINT_SW) { + return -ENOSYS; + } + + bp =3D mshv_find_sw_breakpoint(cpu, addr); + if (!bp) { + return -ENOENT; + } + + if (bp->use_count > 1) { + bp->use_count--; + return 0; + } + + err =3D mshv_arch_remove_sw_breakpoint(cpu, bp); + if (err) { + return err; + } + + QTAILQ_REMOVE(&mshv_state->sw_breakpoints, bp, entry); + g_free(bp); + + return 0; +} + +static void mshv_remove_all_gdbstub_breakpoints(CPUState *cpu) +{ + struct MshvSwBreakpoint *bp, *next; + CPUState *tmpcpu; + + QTAILQ_FOREACH_SAFE(bp, &mshv_state->sw_breakpoints, entry, next) { + if (mshv_arch_remove_sw_breakpoint(cpu, bp) !=3D 0) { + /* Fall back to whichever CPU still has it mapped. */ + CPU_FOREACH(tmpcpu) { + if (mshv_arch_remove_sw_breakpoint(tmpcpu, bp) =3D=3D 0) { + break; + } + } + } + QTAILQ_REMOVE(&mshv_state->sw_breakpoints, bp, entry); + g_free(bp); + } +} + static int mshv_cpu_exec(CPUState *cpu) { hv_message mshv_msg; @@ -637,6 +789,9 @@ static int mshv_cpu_exec(CPUState *cpu) switch (exit_reason) { case MshvVmExitIgnore: break; + case MshvVmExitDebug: + ret =3D EXCP_DEBUG; + break; default: ret =3D EXCP_INTERRUPT; break; @@ -708,7 +863,10 @@ static void *mshv_vcpu_thread(void *arg) do { qemu_process_cpu_events(cpu); if (cpu_can_run(cpu)) { - mshv_cpu_exec(cpu); + ret =3D mshv_cpu_exec(cpu); + if (ret =3D=3D EXCP_DEBUG) { + cpu_handle_guest_debug(cpu); + } } } while (!cpu->unplug || cpu_can_run(cpu)); =20 @@ -852,6 +1010,11 @@ static void mshv_accel_ops_class_init(ObjectClass *oc= , const void *data) ops->synchronize_pre_loadvm =3D mshv_cpu_synchronize_pre_loadvm; ops->cpus_are_resettable =3D mshv_cpus_are_resettable; ops->handle_interrupt =3D generic_handle_interrupt; + + ops->update_guest_debug =3D mshv_update_guest_debug; + ops->insert_gdbstub_breakpoint =3D mshv_insert_gdbstub_breakpoint; + ops->remove_gdbstub_breakpoint =3D mshv_remove_gdbstub_breakpoint; + ops->remove_all_gdbstub_breakpoints =3D mshv_remove_all_gdbstub_breakp= oints; } =20 static const TypeInfo mshv_accel_ops_type =3D { diff --git a/include/system/mshv_int.h b/include/system/mshv_int.h index b91c4d661a..9244915eb6 100644 --- a/include/system/mshv_int.h +++ b/include/system/mshv_int.h @@ -15,6 +15,7 @@ #define QEMU_MSHV_INT_H =20 #include "hw/hyperv/hvhdk.h" +#include "exec/vaddr.h" =20 #define MSHV_MSR_ENTRIES_COUNT 64 =20 @@ -56,6 +57,13 @@ typedef struct MshvAddressSpace { AddressSpace *as; } MshvAddressSpace; =20 +struct MshvSwBreakpoint { + vaddr pc; + vaddr saved_insn; + int use_count; + QTAILQ_ENTRY(MshvSwBreakpoint) entry; +}; + struct MshvState { AccelState parent_obj; int vm; @@ -70,6 +78,8 @@ struct MshvState { unsigned long *used_gsi_bitmap; unsigned int gsi_count; union hv_partition_processor_features processor_features; + QTAILQ_HEAD(, MshvSwBreakpoint) sw_breakpoints; + bool exception_intercepts_installed; }; =20 typedef struct MshvMsiControl { @@ -85,6 +95,7 @@ typedef enum MshvVmExit { MshvVmExitIgnore =3D 0, MshvVmExitShutdown =3D 1, MshvVmExitSpecial =3D 2, + MshvVmExitDebug =3D 3, } MshvVmExit; =20 void mshv_init_mmio_emu(void); @@ -98,6 +109,9 @@ int mshv_get_generic_regs(CPUState *cpu, hv_register_ass= oc *assocs, size_t n_regs); int mshv_arch_store_vcpu_state(const CPUState *cpu); int mshv_arch_load_vcpu_state(CPUState *cpu); +int mshv_arch_insert_sw_breakpoint(CPUState *cpu, struct MshvSwBreakpoint = *bp); +int mshv_arch_remove_sw_breakpoint(CPUState *cpu, struct MshvSwBreakpoint = *bp); +struct MshvSwBreakpoint *mshv_find_sw_breakpoint(CPUState *cpu, vaddr pc); void mshv_arch_init_vcpu(CPUState *cpu); void mshv_arch_destroy_vcpu(CPUState *cpu); void mshv_arch_amend_proc_features( diff --git a/target/i386/mshv/mshv-cpu.c b/target/i386/mshv/mshv-cpu.c index 1c433c408c..b15776b9bd 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -12,6 +12,7 @@ =20 #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/main-loop.h" #include "qemu/memalign.h" =20 #include "system/mshv.h" @@ -28,6 +29,7 @@ #include "emulate/x86_decode.h" #include "emulate/x86_emu.h" #include "emulate/x86_flags.h" +#include "gdbstub/enums.h" =20 #include "accel/accel-cpu-target.h" =20 @@ -1932,6 +1934,72 @@ static int handle_pio(CPUState *cpu, const struct hy= perv_message *msg) return handle_pio_non_str(cpu, &info); } =20 +/* Re-inject a guest-owned #DB via a pending event */ +static int reinject_exception(CPUState *cpu, + const struct hv_x64_exception_intercept_message *info) +{ + hv_register_assoc assoc =3D { .name =3D HV_REGISTER_PENDING_EVENT0 }; + + assoc.value.pending_exception_event.event_pending =3D 1; + assoc.value.pending_exception_event.event_type =3D + HV_X64_PENDING_EVENT_EXCEPTION; + assoc.value.pending_exception_event.exception_parameter =3D + info->exception_parameter; + assoc.value.pending_exception_event.vector =3D info->exception_vector; + + return mshv_set_generic_regs(cpu, &assoc, 1); +} + +/* Check if the intercepted #DB has been set by gdb. */ +static bool is_debug_exception(CPUState *cpu, const hv_message *msg) +{ + struct hv_x64_exception_intercept_message *info =3D (void *)msg->paylo= ad; + + /* Only #DB is intercepted */ + if (info->exception_vector !=3D EXCP01_DB) { + return false; + } + + /* INT1 hit: RIP points at the breakpoint */ + if (mshv_find_sw_breakpoint(cpu, info->header.rip) !=3D NULL) { + return true; + } + + /* Check if single stepping */ + if (cpu_single_stepping(cpu)) { + return true; + } + + /* The guest's own #DB; caller re-injects it. */ + return false; +} + +static int handle_exception_interrupt(CPUState *cpu, + const struct hyperv_message *msg, + MshvVmExit *exit_reason) +{ + int ret; + + if (is_debug_exception(cpu, msg)) { + /* Exit early reporting debug exception */ + *exit_reason =3D MshvVmExitDebug; + return 0; + } + + /* Not ours - hand the #DB back to the guest and keep running. */ + ret =3D reinject_exception(cpu, + (struct hv_x64_exception_intercept_message *) msg->payload); + if (ret < 0) { + error_report("failed to reinject exception on vcpu %d", + cpu->cpu_index); + return -1; + } + + *exit_reason =3D MshvVmExitIgnore; + + return 0; +} + int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *e= xit) { int ret; @@ -1960,6 +2028,16 @@ int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_messa= ge *msg, MshvVmExit *exit) return MshvVmExitSpecial; } return MshvVmExitIgnore; + case HVMSG_X64_EXCEPTION_INTERCEPT: + bql_lock(); + ret =3D handle_exception_interrupt(cpu, msg, &exit_reason); + bql_unlock(); + if (ret < 0) { + error_report("failed to handle exception intercept"); + return -1; + } + *exit =3D exit_reason; + return exit_reason; default: break; } @@ -1973,6 +2051,32 @@ void mshv_remove_vcpu(int vm_fd, int cpu_fd) close(cpu_fd); } =20 +int mshv_arch_insert_sw_breakpoint(CPUState *cpu, struct MshvSwBreakpoint = *bp) +{ + static const uint8_t int1 =3D 0xf1; + + if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 1, 0)= || + cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&int1, 1, 1)) { + return -EINVAL; + } + return 0; +} + +int mshv_arch_remove_sw_breakpoint(CPUState *cpu, struct MshvSwBreakpoint = *bp) +{ + uint8_t int1; + + if (cpu_memory_rw_debug(cpu, bp->pc, &int1, 1, 0)) { + return -EINVAL; + } + if (int1 !=3D 0xf1) { + return 0; + } + if (cpu_memory_rw_debug(cpu, bp->pc, (uint8_t *)&bp->saved_insn, 1, 1)= ) { + return -EINVAL; + } + return 0; +} =20 int mshv_create_vcpu(int vm_fd, uint8_t vp_index, int *cpu_fd) { --=20 2.53.0 From nobody Mon Sep 28 02:05:28 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785523671; cv=none; d=zohomail.com; s=zohoarc; b=mzU02FahTGWLljFe22NS8pNqBDzRsnq7bh8RNK0Lifrrlr4X+hwyV5Mz5J36HaGm4Q7+K5XAorSe/xu4o4f92Zd44PCFH/zugPlleBnjSeUzfjQMIj7zlcOfvrQcWLR6jQsOXylFhAXx0NJnmOywzS0kD02dCIuYsTgvHPLo5TE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785523671; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=5+UQpHggV+ssrmgk4pMyPIETP+XYPgitYa5UPuD2ZXs=; b=R8BpA0IJq9+t0CnVbv2ZD5HwLNHj7yryCUKUJBPIf5SV/Fm2aSgPqDYcVnXwgW+lde0iCZmVFvzIaYF49IpMDCp/2hWmKPR4CWfc+FIZmLmzOjwiYwZ5lj9+8eclnTnpyuRohm510Yw3bFMvTHXUXEVpWjM+vVe6GKz5FYrnvsM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785523671907309.2131035127836; Fri, 31 Jul 2026 11:47:51 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsGJ-0003y3-MJ; Fri, 31 Jul 2026 14:47:15 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpsG5-0003w6-EJ for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:47:02 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsG3-0000lB-SK for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:47:01 -0400 Received: from laptop.localdomain (unknown [86.121.140.206]) by linux.microsoft.com (Postfix) with ESMTPSA id 97A6820B7166; Fri, 31 Jul 2026 11:46:38 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 97A6820B7166 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785523600; bh=5+UQpHggV+ssrmgk4pMyPIETP+XYPgitYa5UPuD2ZXs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nFTkD8VePD7U+ImkVk1jLApKq/k7UACBdGXoYKtUslH43HcsWyyv7JrPU+NO8fr84 r6fkytJc+k9bD/PpsypdBIxxPr2tiMuRSXqwf1rkKS8QfRZY72KRnDYsxE981EYTAn qneLOygOANbkIoK2xHeCvcheO691VJ429xvHfm+k= From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= To: qemu-devel@nongnu.org Cc: Wei Liu , Wei Liu , Magnus Kulke , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , Magnus Kulke Subject: [PATCH v2 3/4] target/i386/mshv: support single-stepping Date: Fri, 31 Jul 2026 21:46:41 +0300 Message-ID: <20260731184643.89604-4-dblanzeanu@linux.microsoft.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> References: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=dblanzeanu@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785523673894158500 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 vC= PU is single-stepping. Signed-off-by: Doru Bl=C3=A2nzeanu Reviewed-by: Magnus Kulke --- 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 b15776b9bd..af4f90385e 100644 --- a/target/i386/mshv/mshv-cpu.c +++ b/target/i386/mshv/mshv-cpu.c @@ -2000,17 +2000,67 @@ static int handle_exception_interrupt(CPUState *cpu, return 0; } =20 +/* + * Flip RFLAGS.TF like WHPX. Set it only on the live register, not env->ef= lags, + * so a later store won't put it back. + */ +static int arch_set_single_step(CPUState *cpu, bool enable) +{ + X86CPU *x86cpu =3D X86_CPU(cpu); + CPUX86State *env =3D &x86cpu->env; + hv_register_assoc assoc =3D { .name =3D HV_X64_REGISTER_RFLAGS }; + uint64_t rflags; + int ret; + + if (env->regs_page && env->regs_page->isvalid !=3D 0) { + rflags =3D env->regs_page->rflags; + rflags =3D enable ? (rflags | TF_MASK) : (rflags & ~TF_MASK); + env->regs_page->rflags =3D rflags; + env->regs_page->dirty |=3D (1u << HV_X64_REGISTER_CLASS_FLAGS); + return 0; + } + + ret =3D mshv_get_generic_regs(cpu, &assoc, 1); + if (ret < 0) { + return ret; + } + rflags =3D assoc.value.reg64; + rflags =3D enable ? (rflags | TF_MASK) : (rflags & ~TF_MASK); + assoc.value.reg64 =3D rflags; + return mshv_set_generic_regs(cpu, &assoc, 1); +} + int mshv_run_vcpu(int vm_fd, CPUState *cpu, hv_message *msg, MshvVmExit *e= xit) { int ret; enum MshvVmExit exit_reason; int cpu_fd =3D mshv_vcpufd(cpu); + bool single_step; + + /* enable single stepping by flipping RFLAGS.TF */ + single_step =3D cpu_single_stepping(cpu); + if (single_step) { + ret =3D 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 =3D MshvVmExitShutdown; + return -1; + } + } =20 ret =3D ioctl(cpu_fd, MSHV_RUN_VP, msg); if (ret < 0) { return MshvVmExitShutdown; } =20 + /* 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; --=20 2.53.0 From nobody Mon Sep 28 02:05:28 2026 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=linux.microsoft.com ARC-Seal: i=1; a=rsa-sha256; t=1785523693; cv=none; d=zohomail.com; s=zohoarc; b=SvWQgS/jeYegn8gofbcTqavflhGE6aRRcRhozrWEj0tHeuTDXJsrTF/ZFXcpfNfInDrTNR8VJjuc80y1Jvv8GgNw5P7amQHtW3XHJg/XQDkX0tgCjpbAdnOV2KzEV71HYGy6BnOXRgARu389jIGbb4VQRUrMu5ENILxpfew26yw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1785523693; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=qzAKGinRpTm7h9cD+exUNPykINEVxI273EsPRDaQ1E8=; b=W4cAIYMsmSqfmx8Q1diUscRhNE52ysYfYbe19H66upOWBDvap7ynbxtFdGLDmr+kjtb0Vc8SsgTIJdT3mX38NTSqRrumq4PymIhGLcS7oWIGsEDy7cfUdiroMEWNSWOdg5gz/yxahCzRgnE93B6sK02nfsEBWQgl9SI4cAYSCS8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists1p.gnu.org (lists1p.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1785523693790546.0588031448106; Fri, 31 Jul 2026 11:48:13 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists1p.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsGG-0003xI-3d; Fri, 31 Jul 2026 14:47:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists1p.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1wpsG7-0003wG-Jx for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:47:04 -0400 Received: from linux.microsoft.com ([13.77.154.182]) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1wpsG6-0000lM-8H for qemu-devel@nongnu.org; Fri, 31 Jul 2026 14:47:03 -0400 Received: from laptop.localdomain (unknown [86.121.140.206]) by linux.microsoft.com (Postfix) with ESMTPSA id 85E1A20B7167; Fri, 31 Jul 2026 11:46:41 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 85E1A20B7167 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1785523603; bh=qzAKGinRpTm7h9cD+exUNPykINEVxI273EsPRDaQ1E8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jmbONyokHCE5sRvjv4mErLWcOwkosw3KQ/aUoiQDw4/eZ53A2P9b2qfMib47tNTjG Ftn08YevzjzzyqfLQl/hXZ8gI46+r6aaIicOBDtZRp4puoAkGXYFRn/AP1C+iJNjjM CVIQwp1O8PXXq/B9gqLWkWfef2yJ7G/71s3acz/w= From: =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= To: qemu-devel@nongnu.org Cc: Wei Liu , Wei Liu , Magnus Kulke , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , =?UTF-8?q?Doru=20Bl=C3=A2nzeanu?= , Magnus Kulke Subject: [PATCH v2 4/4] accel/mshv: break the vCPU run loop on exit_request Date: Fri, 31 Jul 2026 21:46:42 +0300 Message-ID: <20260731184643.89604-5-dblanzeanu@linux.microsoft.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> References: <20260731184643.89604-1-dblanzeanu@linux.microsoft.com> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists1p.gnu.org; Received-SPF: pass client-ip=13.77.154.182; envelope-from=dblanzeanu@linux.microsoft.com; helo=linux.microsoft.com X-Spam_score_int: -19 X-Spam_score: -2.0 X-Spam_bar: -- X-Spam_report: (-2.0 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @linux.microsoft.com) X-ZM-MESSAGEID: 1785523695796158500 Ignored VM exits can cause mshv_cpu_exec() to re-enter MSHV_RUN_VP without returning to qemu_process_cpu_events(). A busy vCPU may prevent pause_all_vcpus() from completing. Check exit_request before re-entering MSHV_RUN_VP and return EXCP_INTERRUPT so pending stop requests can be processed. Signed-off-by: Doru Bl=C3=A2nzeanu --- accel/mshv/mshv-all.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/accel/mshv/mshv-all.c b/accel/mshv/mshv-all.c index afcb87b3b8..b7c1126fe0 100644 --- a/accel/mshv/mshv-all.c +++ b/accel/mshv/mshv-all.c @@ -780,6 +780,16 @@ static int mshv_cpu_exec(CPUState *cpu) cpu->vcpu_dirty =3D false; } =20 + /* + * A kick/stop can't reliably break MSHV_RUN_VP out, so leave the = run + * loop here too; otherwise a busy vCPU never reaches + * qemu_process_cpu_events() and pause_all_vcpus() hangs under the= BQL. + */ + if (cpu->stop || qatomic_load_acquire(&cpu->exit_request)) { + ret =3D EXCP_INTERRUPT; + break; + } + ret =3D mshv_run_vcpu(mshv_state->vm, cpu, &mshv_msg, &exit_reason= ); if (ret < 0) { error_report("Failed to run on vcpu %d", cpu->cpu_index); --=20 2.53.0