Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH 00/23] kvm: introduce KVMCPUOps
@ 2026-10-20 10:42 Alex Bennée
  2026-10-20 10:42 ` [PATCH 01/23] accel: introduce KVMAccelClass and KVMCPUOps Alex Bennée
                   ` (23 more replies)
  0 siblings, 24 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

There is a world coming where we can have a KVM interface which
supports multiple architectures. The old style approach of using
linking to resolve per arch kvm_arch_foo handlers won't scale and is
also slightly antithetical to the flexible not-quite object orientated
way we do things in QEMU.

Taking TCGCpuOps as a reference this implements KVMCpuOps as the
shared function dispatcher for CPU specific KVM operations.

A couple of open questions:

  - should we consider some sort of shared AccelInfo region for
  CPUState instead of a bunch of mutually unused bits
  - how can we improve coverage of KVM testing?

The main driver for writing:

  Message-ID: <20261019192704.3220373-1-alex.bennee@linaro.org>
  Date: Mon, 19 Oct 2026 20:26:45 +0100
  Subject: [PATCH v3 00/19] testing/next: functional testing updates for gdb (pre-PR)
  From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>

was so I could be sure the KVMCpuOps where properly working. I don't
think we have that much that exercises KVM in our CI system anyway
because most runners don't give access to HW virtualisation. I have
tested this on:

  - x86_64 (on my dev box)
  - aarch64 (on my personal dev box and the aarch64 ci machine)
  - s390x (on devcloud instance, same as the s390x runner)

Notably I wasn't able to test the riscv64, loongarch64 or ppc64
behaviour. I do have access to the OSUL ppc runner but it doesn't
support nested virt and testing on that machine needs some love anyway
(see #3207).

Anyway I await your discussion ;-)

Alex.

Alex Bennée (23):
  accel: introduce KVMAccelClass and KVMCPUOps
  target/i386: wire up empty KVMAccelCPUClass
  target/ppc: wire up empty KVMAccelCPUClass
  target/riscv: wire up empty KVMAccelCPUClass
  target/arm: wire up empty KVMAccelCPUClass
  target/s390x: wire up empty KVMAccelCPUClass
  target/loongarch: wire up empty KVMAccelCPUClass
  accel/kvm: port kvm_arch_pre_run to KVMCPUOps
  accel/kvm: port kvm_arch_post_run to KVMCPUOps
  accel/kvm: port kvm_arch_handle_exit to KVMCPUOps
  accel/kvm: port kvm_arch_process_async_events to KVMCPUOps
  accel/kvm: port kvm_arch_[put|get]_registers to KVMCPUOps
  accel/kvm: port kvm_arch_pre_create_vcpu to KVMCPUOps
  accel/kvm: port kvm_arch_init_vcpu to KVMCPUOps
  accel/kvm: port kvm_arch_destroy_vcpu to KVMCPUOps
  accel/kvm: port kvm_arch_vpcu_id to KVMCPUOps
  accel/kvm: port kvm_arch_update_guest_debug to KVMCPUOps
  accel/kvm: port kvm_arch_[insert|remove]_hw_breakpoints to KVMCPUOps
  accel/kvm: remove TARGET_KVM_HAVE_GUEST_DEBUG
  accel/kvm: port kvm_arch_stop_on_emulation_error to KVMCPUOps
  accel/kvm: port kvm_arch_on_sigbus_vcpu to KVMCPUOps
  accel/kvm: cache KVMCPUOps
  accel/kvm: remove redundant ops checks for kvm_get_cpu_ops

 docs/specs/acpi_hest_ghes.rst           |   3 +-
 configs/targets/aarch64-softmmu.mak     |   1 -
 configs/targets/i386-softmmu.mak        |   1 -
 configs/targets/loongarch64-softmmu.mak |   1 -
 configs/targets/ppc-softmmu.mak         |   1 -
 configs/targets/ppc64-softmmu.mak       |   1 -
 configs/targets/riscv64-softmmu.mak     |   1 -
 configs/targets/s390x-softmmu.mak       |   1 -
 configs/targets/x86_64-softmmu.mak      |   1 -
 include/accel/kvm/cpu-ops.h             | 171 ++++++++++++++++++++++
 include/hw/core/cpu.h                   |   3 +
 include/system/kvm.h                    |  42 +-----
 include/system/kvm_int.h                |   2 -
 target/i386/kvm/kvm_i386.h              |  20 +++
 accel/kvm/kvm-accel-ops.c               |  13 +-
 accel/kvm/kvm-all.c                     | 183 +++++++++++++++++-------
 accel/tcg/cpu-exec.c                    |   2 +-
 hw/i386/kvm/xen_evtchn.c                |   6 +-
 hw/intc/openpic_kvm.c                   |   4 +-
 hw/intc/spapr_xive_kvm.c                |  10 +-
 hw/intc/xics_kvm.c                      |   6 +-
 target/arm/kvm.c                        |  96 +++++++------
 target/i386/kvm/kvm-cpu.c               |  26 +++-
 target/i386/kvm/kvm.c                   |  42 +++---
 target/loongarch/cpu.c                  |   8 +-
 target/loongarch/kvm/kvm.c              |  96 ++++++-------
 target/ppc/kvm.c                        |  75 +++++-----
 target/riscv/kvm/kvm-cpu.c              |  95 +++++-------
 target/s390x/kvm/kvm.c                  |  89 +++++++-----
 29 files changed, 628 insertions(+), 372 deletions(-)
 create mode 100644 include/accel/kvm/cpu-ops.h

-- 
2.47.3


^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH 01/23] accel: introduce KVMAccelClass and KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
@ 2026-10-20 10:42 ` Alex Bennée
  2026-10-20 10:42 ` [PATCH 02/23] target/i386: wire up empty KVMAccelCPUClass Alex Bennée
                   ` (22 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Introduce a new class derived from AccelCPUClass. It only exists to to
contain the new KVMCPUOps which will allow for a QOM-ified access to
what was previously kvm_arch_foo direct linking. This anticipates a
world where we have a KVM interface capable of launching multiple
architectures.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 53 +++++++++++++++++++++++++++++++++++++
 accel/kvm/kvm-accel-ops.c   |  9 +++++++
 2 files changed, 62 insertions(+)
 create mode 100644 include/accel/kvm/cpu-ops.h

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
new file mode 100644
index 00000000000..662d0c553c7
--- /dev/null
+++ b/include/accel/kvm/cpu-ops.h
@@ -0,0 +1,53 @@
+/*
+ * KVM CPU-specific operations
+ *
+ * Copyright 2026 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ACCEL_KVM_CPU_OPS_H
+#define ACCEL_KVM_CPU_OPS_H
+
+#include "qom/object.h"
+#include "hw/core/cpu.h"
+#include "accel/accel-cpu-target.h"
+
+/**
+ * struct KVMCPUOps - Target-specific per-vCPU operations for KVM
+ */
+typedef struct KVMCPUOps {
+} KVMCPUOps;
+
+#define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
+
+/**
+ * struct KVMAccelCPUClass - KVM-specific accelerator CPU class
+ *
+ * @parent_class: The parent #AccelCPUClass
+ */
+typedef struct KVMAccelCPUClass {
+    AccelCPUClass parent_class;
+
+    const KVMCPUOps *cpu_ops;
+} KVMAccelCPUClass;
+
+DECLARE_CLASS_CHECKERS(KVMAccelCPUClass, KVM_ACCEL_CPU, TYPE_KVM_ACCEL_CPU)
+
+/**
+ * kvm_get_cpu_ops - Retrieve the KVMCPUOps table for a CPU
+ * @cpu: The #CPUState
+ *
+ * Returns: A pointer to the active #KVMCPUOps, or NULL if the CPU class does
+ *          not have an attached KVM accelerator class.
+ */
+static inline const KVMCPUOps *kvm_get_cpu_ops(const CPUState *cpu)
+{
+    if (cpu->cc->accel_cpu) {
+        KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(cpu->cc->accel_cpu);
+        return kacc->cpu_ops;
+    }
+    return NULL;
+}
+
+#endif /* ACCEL_KVM_CPU_OPS_H */
diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index 47244d33f7d..445d7d7f545 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -18,6 +18,7 @@
 #include "qemu/main-loop.h"
 #include "exec/cpu-common.h"
 #include "accel/accel-cpu-ops.h"
+#include "accel/kvm/cpu-ops.h"
 #include "system/kvm.h"
 #include "system/kvm_int.h"
 #include "system/runstate.h"
@@ -121,8 +122,16 @@ static const TypeInfo kvm_accel_ops_type = {
     .abstract = true,
 };
 
+static const TypeInfo kvm_accel_cpu_type = {
+    .name = TYPE_KVM_ACCEL_CPU,
+    .parent = TYPE_ACCEL_CPU,
+    .class_size = sizeof(KVMAccelCPUClass),
+    .abstract = true,
+};
+
 static void kvm_accel_ops_register_types(void)
 {
     type_register_static(&kvm_accel_ops_type);
+    type_register_static(&kvm_accel_cpu_type);
 }
 type_init(kvm_accel_ops_register_types);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 02/23] target/i386: wire up empty KVMAccelCPUClass
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
  2026-10-20 10:42 ` [PATCH 01/23] accel: introduce KVMAccelClass and KVMCPUOps Alex Bennée
@ 2026-10-20 10:42 ` Alex Bennée
  2026-10-20 10:42 ` [PATCH 03/23] target/ppc: " Alex Bennée
                   ` (21 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We will fill in the functions in future commits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/i386/kvm/kvm-cpu.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index da8d77ade06..9de107a18d5 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -17,6 +17,7 @@
 
 #include "kvm_i386.h"
 #include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 
 static void kvm_set_guest_phys_bits(CPUState *cs)
 {
@@ -233,17 +234,22 @@ static void kvm_cpu_instance_init(CPUState *cs)
     kvm_cpu_xsave_init();
 }
 
+static const KVMCPUOps x86_kvm_cpu_ops = {
+};
+
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
 {
     AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+    KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(oc);
 
     acc->cpu_target_realize = kvm_cpu_realizefn;
     acc->cpu_instance_init = kvm_cpu_instance_init;
+    kacc->cpu_ops = &x86_kvm_cpu_ops;
 }
 static const TypeInfo kvm_cpu_accel_type_info = {
     .name = ACCEL_CPU_NAME("kvm"),
 
-    .parent = TYPE_ACCEL_CPU,
+    .parent = TYPE_KVM_ACCEL_CPU,
     .class_init = kvm_cpu_accel_class_init,
     .abstract = true,
 };
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 03/23] target/ppc: wire up empty KVMAccelCPUClass
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
  2026-10-20 10:42 ` [PATCH 01/23] accel: introduce KVMAccelClass and KVMCPUOps Alex Bennée
  2026-10-20 10:42 ` [PATCH 02/23] target/i386: wire up empty KVMAccelCPUClass Alex Bennée
@ 2026-10-20 10:42 ` Alex Bennée
  2026-10-20 10:42 ` [PATCH 04/23] target/riscv: " Alex Bennée
                   ` (20 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We will fill in the functions in future commits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/ppc/kvm.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 8e89a6c665c..8e9328beeb9 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -50,6 +50,7 @@
 #include "system/kvm_int.h"
 #include "system/kvm.h"
 #include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 
 #include CONFIG_DEVICES
 
@@ -3080,17 +3081,22 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 {
 }
 
+static const KVMCPUOps ppc_kvm_cpu_ops = {
+};
+
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
 {
     AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+    KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(oc);
 
     acc->cpu_target_realize = kvmppc_cpu_realize;
+    kacc->cpu_ops = &ppc_kvm_cpu_ops;
 }
 
 static const TypeInfo kvm_cpu_accel_type_info = {
     .name = ACCEL_CPU_NAME("kvm"),
 
-    .parent = TYPE_ACCEL_CPU,
+    .parent = TYPE_KVM_ACCEL_CPU,
     .class_init = kvm_cpu_accel_class_init,
     .abstract = true,
 };
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 04/23] target/riscv: wire up empty KVMAccelCPUClass
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (2 preceding siblings ...)
  2026-10-20 10:42 ` [PATCH 03/23] target/ppc: " Alex Bennée
@ 2026-10-20 10:42 ` Alex Bennée
  2026-10-20 10:42 ` [PATCH 05/23] target/arm: " Alex Bennée
                   ` (19 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We will fill in the functions in future commits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/riscv/kvm/kvm-cpu.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 45ad5e1525a..b3fa0548c8a 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -33,6 +33,7 @@
 #include "cpu.h"
 #include "trace.h"
 #include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 #include "hw/pci/pci.h"
 #include "exec/memattrs.h"
 #include "system/address-spaces.h"
@@ -2195,18 +2196,23 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
 }
 
+static const KVMCPUOps riscv_kvm_cpu_ops = {
+};
+
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
 {
     AccelCPUClass *acc = ACCEL_CPU_CLASS(oc);
+    KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(oc);
 
     acc->cpu_instance_init = kvm_cpu_instance_init;
     acc->cpu_target_realize = kvm_cpu_realize;
+    kacc->cpu_ops = &riscv_kvm_cpu_ops;
 }
 
 static const TypeInfo kvm_cpu_accel_type_info = {
     .name = ACCEL_CPU_NAME("kvm"),
 
-    .parent = TYPE_ACCEL_CPU,
+    .parent = TYPE_KVM_ACCEL_CPU,
     .class_init = kvm_cpu_accel_class_init,
     .abstract = true,
 };
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 05/23] target/arm: wire up empty KVMAccelCPUClass
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (3 preceding siblings ...)
  2026-10-20 10:42 ` [PATCH 04/23] target/riscv: " Alex Bennée
@ 2026-10-20 10:42 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 06/23] target/s390x: " Alex Bennée
                   ` (18 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:42 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We will fill in the functions in future commits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/arm/kvm.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 3d905f8565d..7a3c957c3a5 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -42,6 +42,8 @@
 #include "hw/acpi/ghes.h"
 #include "target/arm/gtimer.h"
 #include "migration/blocker.h"
+#include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_INFO(DEVICE_CTRL),
@@ -2662,3 +2664,26 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
 
     kvm_arm_destroy_scratch_host_vcpu(fdarray);
 }
+
+static const KVMCPUOps arm_kvm_cpu_ops = {
+};
+
+static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
+{
+    KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(oc);
+
+    kacc->cpu_ops = &arm_kvm_cpu_ops;
+}
+
+static const TypeInfo kvm_cpu_accel_type_info = {
+    .name = ACCEL_CPU_NAME("kvm"),
+    .parent = TYPE_KVM_ACCEL_CPU,
+    .class_init = kvm_cpu_accel_class_init,
+    .abstract = true,
+};
+
+static void kvm_cpu_accel_register_types(void)
+{
+    type_register_static(&kvm_cpu_accel_type_info);
+}
+type_init(kvm_cpu_accel_register_types);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 06/23] target/s390x: wire up empty KVMAccelCPUClass
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (4 preceding siblings ...)
  2026-10-20 10:42 ` [PATCH 05/23] target/arm: " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 07/23] target/loongarch: " Alex Bennée
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We will fill in the functions in future commits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/s390x/kvm/kvm.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index dc67e848864..69e49b7d151 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -52,6 +52,8 @@
 #include "hw/s390x/s390-virtio-ccw.h"
 #include "hw/s390x/s390-hypercall.h"
 #include "target/s390x/kvm/pv.h"
+#include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 #include CONFIG_DEVICES
 
 #define kvm_vm_check_mem_attr(s, attr) \
@@ -2655,3 +2657,26 @@ int kvm_s390_topology_set_mtcr(uint64_t attr)
 void kvm_arch_accel_class_init(ObjectClass *oc)
 {
 }
+
+static const KVMCPUOps s390x_kvm_cpu_ops = {
+};
+
+static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
+{
+    KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(oc);
+
+    kacc->cpu_ops = &s390x_kvm_cpu_ops;
+}
+
+static const TypeInfo kvm_cpu_accel_type_info = {
+    .name = ACCEL_CPU_NAME("kvm"),
+    .parent = TYPE_KVM_ACCEL_CPU,
+    .class_init = kvm_cpu_accel_class_init,
+    .abstract = true,
+};
+
+static void kvm_cpu_accel_register_types(void)
+{
+    type_register_static(&kvm_cpu_accel_type_info);
+}
+type_init(kvm_cpu_accel_register_types);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 07/23] target/loongarch: wire up empty KVMAccelCPUClass
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (5 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 06/23] target/s390x: " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 08/23] accel/kvm: port kvm_arch_pre_run to KVMCPUOps Alex Bennée
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We will fill in the functions in future commits.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 target/loongarch/kvm/kvm.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 941142305e4..4bc08f195ed 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -29,6 +29,8 @@
 #include "cpu-csr.h"
 #include "kvm_loongarch.h"
 #include "trace.h"
+#include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 
 static bool cap_has_mp_state;
 static unsigned int brk_insn;
@@ -1648,3 +1650,26 @@ int kvm_loongarch_set_interrupt(LoongArchCPU *cpu, int irq, int level)
 void kvm_arch_accel_class_init(ObjectClass *oc)
 {
 }
+
+static const KVMCPUOps loongarch_kvm_cpu_ops = {
+};
+
+static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
+{
+    KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(oc);
+
+    kacc->cpu_ops = &loongarch_kvm_cpu_ops;
+}
+
+static const TypeInfo kvm_cpu_accel_type_info = {
+    .name = ACCEL_CPU_NAME("kvm"),
+    .parent = TYPE_KVM_ACCEL_CPU,
+    .class_init = kvm_cpu_accel_class_init,
+    .abstract = true,
+};
+
+static void kvm_cpu_accel_register_types(void)
+{
+    type_register_static(&kvm_cpu_accel_type_info);
+}
+type_init(kvm_cpu_accel_register_types);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 08/23] accel/kvm: port kvm_arch_pre_run to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (6 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 07/23] target/loongarch: " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 09/23] accel/kvm: port kvm_arch_post_run " Alex Bennée
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Port our first function. As a number of arches don't do anything at
this point they become nops and the call becomes optional.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 11 +++++++++++
 include/system/kvm.h        |  1 -
 target/i386/kvm/kvm_i386.h  |  1 +
 accel/kvm/kvm-all.c         |  7 ++++++-
 accel/tcg/cpu-exec.c        |  2 +-
 target/arm/kvm.c            |  3 ++-
 target/i386/kvm/kvm-cpu.c   |  1 +
 target/i386/kvm/kvm.c       |  2 +-
 target/loongarch/kvm/kvm.c  |  4 ----
 target/ppc/kvm.c            |  4 ----
 target/riscv/kvm/kvm-cpu.c  |  4 ----
 target/s390x/kvm/kvm.c      |  4 ----
 12 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 662d0c553c7..2c04fa5adf5 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -13,10 +13,19 @@
 #include "hw/core/cpu.h"
 #include "accel/accel-cpu-target.h"
 
+struct kvm_run;
+
 /**
  * struct KVMCPUOps - Target-specific per-vCPU operations for KVM
+ *
+ * @pre_run: Optional callback executed immediately prior to entering the
+ *           KVM_RUN ioctl in the vCPU thread loop. Used by architectures
+ *           that need to inject pending events (e.g. x86 NMI/SMI) or verify
+ *           injected exceptions (e.g. ARM external data aborts).
+ *           May be NULL if the target does not require pre-run handling.
  */
 typedef struct KVMCPUOps {
+    void (*pre_run)(CPUState *cpu, struct kvm_run *run);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
@@ -25,6 +34,8 @@ typedef struct KVMCPUOps {
  * struct KVMAccelCPUClass - KVM-specific accelerator CPU class
  *
  * @parent_class: The parent #AccelCPUClass
+ * @cpu_ops: Target-specific KVM operations table. Must be non-NULL when
+ *           KVM acceleration is initialized for the target CPU.
  */
 typedef struct KVMAccelCPUClass {
     AccelCPUClass parent_class;
diff --git a/include/system/kvm.h b/include/system/kvm.h
index d29624034cb..e9d7b86ea4a 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -333,7 +333,6 @@ extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
 void kvm_arch_accel_class_init(ObjectClass *oc);
 
-void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run);
 MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run);
 
 int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run);
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 2b653442f4d..218ae8f09ce 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -33,6 +33,7 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
 
 int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
+void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index db8fba53f33..4dca5467f4a 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -55,6 +55,8 @@
 
 #include "hw/core/boards.h"
 #include "system/stats.h"
+#include "accel/accel-cpu-target.h"
+#include "accel/kvm/cpu-ops.h"
 
 /* This check must be after config-host.h is included */
 #ifdef CONFIG_EVENTFD
@@ -3451,6 +3453,7 @@ out_unref:
 
 int kvm_cpu_exec(CPUState *cpu)
 {
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     struct kvm_run *run = cpu->kvm_run;
     int ret, run_ret;
 
@@ -3474,7 +3477,9 @@ int kvm_cpu_exec(CPUState *cpu)
             }
         }
 
-        kvm_arch_pre_run(cpu, run);
+        if (ops->pre_run) {
+            ops->pre_run(cpu, run);
+        }
         /* Corresponding store-release is in cpu_exit. */
         if (qatomic_load_acquire(&cpu->exit_request)) {
             trace_kvm_interrupt_exit_request();
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 5b4bca5084f..4d2a0aefe89 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -758,7 +758,7 @@ void tcg_kick_vcpu_thread(CPUState *cpu)
      * Ensure cpu_exec will see the reason why the exit request was set.
      * FIXME: this is not always needed.  Other accelerators instead
      * read interrupt_request and set exit_request on demand from the
-     * CPU thread; see kvm_arch_pre_run() for example.
+     * CPU thread; see KVMCPUOps::pre_run for example.
      */
     qatomic_store_release(&cpu->exit_request, true);
 
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 7a3c957c3a5..4475fd1a9d9 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1377,7 +1377,7 @@ static bool kvm_arm_verify_ext_dabt_pending(ARMCPU *cpu)
     return false;
 }
 
-void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
+static void arm_kvm_pre_run(CPUState *cs, struct kvm_run *run)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     CPUARMState *env = &cpu->env;
@@ -2666,6 +2666,7 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
 }
 
 static const KVMCPUOps arm_kvm_cpu_ops = {
+    .pre_run = arm_kvm_pre_run,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 9de107a18d5..eab5ab46d45 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -235,6 +235,7 @@ static void kvm_cpu_instance_init(CPUState *cs)
 }
 
 static const KVMCPUOps x86_kvm_cpu_ops = {
+    .pre_run = x86_kvm_pre_run,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index da922f72d71..e9bcda70dac 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5898,7 +5898,7 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
     return ret;
 }
 
-void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
+void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run)
 {
     X86CPU *x86_cpu = X86_CPU(cpu);
     CPUX86State *env = &x86_cpu->env;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 4bc08f195ed..b8fb2094062 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1517,10 +1517,6 @@ int kvm_arch_irqchip_create(KVMState *s)
     return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
 }
 
-void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
-{
-}
-
 MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
 {
     return MEMTXATTRS_UNSPECIFIED;
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 8e9328beeb9..17b16e33881 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1336,10 +1336,6 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
     return 0;
 }
 
-void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
-{
-}
-
 MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
 {
     return MEMTXATTRS_UNSPECIFIED;
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index b3fa0548c8a..8575e673811 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1640,10 +1640,6 @@ int kvm_arch_process_async_events(CPUState *cs)
     return 0;
 }
 
-void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run)
-{
-}
-
 MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
 {
     return MEMTXATTRS_UNSPECIFIED;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 69e49b7d151..827816e5b98 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -984,10 +984,6 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
     }
 }
 
-void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run)
-{
-}
-
 MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
 {
     return MEMTXATTRS_UNSPECIFIED;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 09/23] accel/kvm: port kvm_arch_post_run to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (7 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 08/23] accel/kvm: port kvm_arch_pre_run to KVMCPUOps Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 10/23] accel/kvm: port kvm_arch_handle_exit " Alex Bennée
                   ` (14 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Again not all arches do something for this so default to set
MEMTXATTRS_UNSPECIFIED for any potential MMIO we might handle next.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 8 ++++++++
 include/system/kvm.h        | 2 --
 target/i386/kvm/kvm_i386.h  | 1 +
 accel/kvm/kvm-all.c         | 6 +++++-
 target/arm/kvm.c            | 3 ++-
 target/i386/kvm/kvm-cpu.c   | 1 +
 target/i386/kvm/kvm.c       | 2 +-
 target/loongarch/kvm/kvm.c  | 5 -----
 target/ppc/kvm.c            | 5 -----
 target/riscv/kvm/kvm-cpu.c  | 5 -----
 target/s390x/kvm/kvm.c      | 5 -----
 11 files changed, 18 insertions(+), 25 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 2c04fa5adf5..e74081eb133 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -23,9 +23,17 @@ struct kvm_run;
  *           that need to inject pending events (e.g. x86 NMI/SMI) or verify
  *           injected exceptions (e.g. ARM external data aborts).
  *           May be NULL if the target does not require pre-run handling.
+ * @post_run: Optional callback executed immediately after the KVM_RUN ioctl
+ *            returns in the vCPU thread loop. Used by architectures to
+ *            inspect or process hardware registers/flags (e.g. x86 APIC/TPR
+ *            or ARM timer interrupt synchronization) and return the
+ *            #MemTxAttrs to use for handling MMIO exits.
+ *            May be NULL if the target does not require post-run handling,
+ *            in which case MEMTXATTRS_UNSPECIFIED is assumed.
  */
 typedef struct KVMCPUOps {
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
+    MemTxAttrs (*post_run)(CPUState *cpu, struct kvm_run *run);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index e9d7b86ea4a..82785d37600 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -333,8 +333,6 @@ extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
 void kvm_arch_accel_class_init(ObjectClass *oc);
 
-MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run);
-
 int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run);
 
 int kvm_arch_process_async_events(CPUState *cpu);
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 218ae8f09ce..6fb1da6a40c 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -34,6 +34,7 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
 int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
+MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 4dca5467f4a..41229774068 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3500,7 +3500,11 @@ int kvm_cpu_exec(CPUState *cpu)
          * as true, cpu->exit_request will always read as true.
          */
 
-        attrs = kvm_arch_post_run(cpu, run);
+        if (ops->post_run) {
+            attrs = ops->post_run(cpu, run);
+        } else {
+            attrs = MEMTXATTRS_UNSPECIFIED;
+        }
 
 #ifdef KVM_HAVE_MCE_INJECTION
         if (unlikely(have_sigbus_pending)) {
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 4475fd1a9d9..d5f9b7c088c 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1404,7 +1404,7 @@ static void arm_kvm_pre_run(CPUState *cs, struct kvm_run *run)
     }
 }
 
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
+static MemTxAttrs arm_kvm_post_run(CPUState *cs, struct kvm_run *run)
 {
     ARMCPU *cpu;
     uint32_t switched_level;
@@ -2667,6 +2667,7 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
 
 static const KVMCPUOps arm_kvm_cpu_ops = {
     .pre_run = arm_kvm_pre_run,
+    .post_run = arm_kvm_post_run,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index eab5ab46d45..64af85cd113 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -236,6 +236,7 @@ static void kvm_cpu_instance_init(CPUState *cs)
 
 static const KVMCPUOps x86_kvm_cpu_ops = {
     .pre_run = x86_kvm_pre_run,
+    .post_run = x86_kvm_post_run,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index e9bcda70dac..a1b91d502f0 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5995,7 +5995,7 @@ static void kvm_rate_limit_on_bus_lock(void)
     }
 }
 
-MemTxAttrs kvm_arch_post_run(CPUState *cpu, struct kvm_run *run)
+MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run)
 {
     X86CPU *x86_cpu = X86_CPU(cpu);
     CPUX86State *env = &x86_cpu->env;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index b8fb2094062..192538c0aa9 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1517,11 +1517,6 @@ int kvm_arch_irqchip_create(KVMState *s)
     return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
 }
 
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
-{
-    return MEMTXATTRS_UNSPECIFIED;
-}
-
 int kvm_arch_process_async_events(CPUState *cs)
 {
     return cs->halted;
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 17b16e33881..5ef4722cd6f 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1336,11 +1336,6 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
     return 0;
 }
 
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
-{
-    return MEMTXATTRS_UNSPECIFIED;
-}
-
 int kvm_arch_process_async_events(CPUState *cs)
 {
     return cs->halted;
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 8575e673811..9580b6c1b20 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1640,11 +1640,6 @@ int kvm_arch_process_async_events(CPUState *cs)
     return 0;
 }
 
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
-{
-    return MEMTXATTRS_UNSPECIFIED;
-}
-
 bool kvm_arch_stop_on_emulation_error(CPUState *cs)
 {
     return true;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 827816e5b98..ad1145c4ec1 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -984,11 +984,6 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
     }
 }
 
-MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
-{
-    return MEMTXATTRS_UNSPECIFIED;
-}
-
 int kvm_arch_process_async_events(CPUState *cs)
 {
     return cs->halted;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 10/23] accel/kvm: port kvm_arch_handle_exit to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (8 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 09/23] accel/kvm: port kvm_arch_post_run " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 11/23] accel/kvm: port kvm_arch_process_async_events " Alex Bennée
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

This is the first mandatory operation although currently none of our
x86 tests trip up this handling.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 6 ++++++
 include/system/kvm.h        | 2 --
 target/i386/kvm/kvm_i386.h  | 1 +
 accel/kvm/kvm-all.c         | 4 ++--
 target/arm/kvm.c            | 3 ++-
 target/i386/kvm/kvm-cpu.c   | 1 +
 target/i386/kvm/kvm.c       | 2 +-
 target/loongarch/kvm/kvm.c  | 3 ++-
 target/ppc/kvm.c            | 3 ++-
 target/riscv/kvm/kvm-cpu.c  | 3 ++-
 target/s390x/kvm/kvm.c      | 3 ++-
 11 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index e74081eb133..8b2aabd3c2f 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -30,10 +30,16 @@ struct kvm_run;
  *            #MemTxAttrs to use for handling MMIO exits.
  *            May be NULL if the target does not require post-run handling,
  *            in which case MEMTXATTRS_UNSPECIFIED is assumed.
+ * @handle_exit: Mandatory callback executed to handle target-specific VM
+ *               exits from KVM_RUN that are not handled by common KVM code
+ *               (or unhandled sub-cases of KVM_EXIT_SYSTEM_EVENT).
+ *               Returns 0 to continue execution, or an EXCP_* code (or negative
+ *               error code) to exit the CPU execution loop.
  */
 typedef struct KVMCPUOps {
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
     MemTxAttrs (*post_run)(CPUState *cpu, struct kvm_run *run);
+    int (*handle_exit)(CPUState *cpu, struct kvm_run *run);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 82785d37600..82d18d79dc0 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -333,8 +333,6 @@ extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
 void kvm_arch_accel_class_init(ObjectClass *oc);
 
-int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run);
-
 int kvm_arch_process_async_events(CPUState *cpu);
 
 int kvm_arch_get_registers(CPUState *cpu, Error **errp);
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 6fb1da6a40c..5bcc9b51214 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -35,6 +35,7 @@ int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
 MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run);
+int x86_kvm_handle_exit(CPUState *cs, struct kvm_run *run);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 41229774068..33fa47bddf0 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3616,7 +3616,7 @@ int kvm_cpu_exec(CPUState *cpu)
                 ret = 0;
                 break;
             default:
-                ret = kvm_arch_handle_exit(cpu, run);
+                ret = ops->handle_exit(cpu, run);
                 break;
             }
             break;
@@ -3634,7 +3634,7 @@ int kvm_cpu_exec(CPUState *cpu)
                                      run->memory_fault.flags & KVM_MEMORY_EXIT_FLAG_PRIVATE);
             break;
         default:
-            ret = kvm_arch_handle_exit(cpu, run);
+            ret = ops->handle_exit(cpu, run);
             break;
         }
     } while (ret == 0);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d5f9b7c088c..914f8e3b089 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1590,7 +1590,7 @@ static bool kvm_arm_handle_debug(ARMCPU *cpu,
     return false;
 }
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+static int arm_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     ARMCPU *cpu = ARM_CPU(cs);
     int ret = 0;
@@ -2668,6 +2668,7 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
 static const KVMCPUOps arm_kvm_cpu_ops = {
     .pre_run = arm_kvm_pre_run,
     .post_run = arm_kvm_post_run,
+    .handle_exit = arm_kvm_handle_exit,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 64af85cd113..6b75eb038e1 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -237,6 +237,7 @@ static void kvm_cpu_instance_init(CPUState *cs)
 static const KVMCPUOps x86_kvm_cpu_ops = {
     .pre_run = x86_kvm_pre_run,
     .post_run = x86_kvm_post_run,
+    .handle_exit = x86_kvm_handle_exit,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index a1b91d502f0..dfc70eac3db 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6529,7 +6529,7 @@ static int kvm_handle_hypercall(X86CPU *cpu, struct kvm_run *run)
 
 #define VMX_INVALID_GUEST_STATE 0x80000021
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+int x86_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     X86CPU *cpu = X86_CPU(cs);
     uint64_t code;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 192538c0aa9..b23031007c2 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1590,7 +1590,7 @@ static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
     return false;
 }
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+static int loongarch_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     int ret = 0;
     CPULoongArchState *env = cpu_env(cs);
@@ -1643,6 +1643,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps loongarch_kvm_cpu_ops = {
+    .handle_exit = loongarch_kvm_handle_exit,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 5ef4722cd6f..25aaefd7649 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1653,7 +1653,7 @@ static int kvm_handle_debug(PowerPCCPU *cpu, struct kvm_run *run)
     return DEBUG_RETURN_GUEST;
 }
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+static int ppc_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
@@ -3073,6 +3073,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps ppc_kvm_cpu_ops = {
+    .handle_exit = ppc_kvm_handle_exit,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 9580b6c1b20..8944961a939 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1787,7 +1787,7 @@ static bool kvm_riscv_handle_debug(CPUState *cs)
     return false;
 }
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+static int riscv_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     int ret = 0;
     switch (run->exit_reason) {
@@ -2188,6 +2188,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
 }
 
 static const KVMCPUOps riscv_kvm_cpu_ops = {
+    .handle_exit = riscv_kvm_handle_exit,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index ad1145c4ec1..967706a87e1 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -1904,7 +1904,7 @@ static int kvm_arch_handle_debug_exit(S390CPU *cpu)
     return ret;
 }
 
-int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
+static int s390x_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
 {
     S390CPU *cpu = S390_CPU(cs);
     int ret = 0;
@@ -2650,6 +2650,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps s390x_kvm_cpu_ops = {
+    .handle_exit = s390x_kvm_handle_exit,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 11/23] accel/kvm: port kvm_arch_process_async_events to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (9 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 10/23] accel/kvm: port kvm_arch_handle_exit " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 12/23] accel/kvm: port kvm_arch_[put|get]_registers " Alex Bennée
                   ` (12 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

The most complex async handling is for x86 which checks for various
exceptions and if the irqchip is not handled in the kernel for
interrupts. Most of the others just reflect if cs->halted has been
set.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 9 +++++++++
 include/system/kvm.h        | 2 --
 target/i386/kvm/kvm_i386.h  | 1 +
 accel/kvm/kvm-all.c         | 2 +-
 target/arm/kvm.c            | 5 -----
 target/i386/kvm/kvm-cpu.c   | 1 +
 target/i386/kvm/kvm.c       | 2 +-
 target/loongarch/kvm/kvm.c  | 3 ++-
 target/ppc/kvm.c            | 3 ++-
 target/riscv/kvm/kvm-cpu.c  | 5 -----
 target/s390x/kvm/kvm.c      | 3 ++-
 11 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 8b2aabd3c2f..cbd3935ba4d 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -35,11 +35,20 @@ struct kvm_run;
  *               (or unhandled sub-cases of KVM_EXIT_SYSTEM_EVENT).
  *               Returns 0 to continue execution, or an EXCP_* code (or negative
  *               error code) to exit the CPU execution loop.
+ * @process_async_events: Optional callback executed at the start of
+ *                        kvm_cpu_exec() while holding the BQL to process
+ *                        pending asynchronous events (such as interrupts,
+ *                        resets, or MCEs). Returns non-zero (typically
+ *                        cpu->halted) if the vCPU should not run and should
+ *                        return EXCP_HLT, or 0 if execution can proceed.
+ *                        May be NULL if the target does not require event
+ *                        processing before execution.
  */
 typedef struct KVMCPUOps {
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
     MemTxAttrs (*post_run)(CPUState *cpu, struct kvm_run *run);
     int (*handle_exit)(CPUState *cpu, struct kvm_run *run);
+    int (*process_async_events)(CPUState *cpu);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 82d18d79dc0..8c705d21f79 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -333,8 +333,6 @@ extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
 void kvm_arch_accel_class_init(ObjectClass *oc);
 
-int kvm_arch_process_async_events(CPUState *cpu);
-
 int kvm_arch_get_registers(CPUState *cpu, Error **errp);
 
 typedef enum kvm_put_state {
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 5bcc9b51214..bff587a56de 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -36,6 +36,7 @@ void kvm_arch_reset_vcpu(X86CPU *cs);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
 MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run);
 int x86_kvm_handle_exit(CPUState *cs, struct kvm_run *run);
+int x86_kvm_process_async_events(CPUState *cs);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 33fa47bddf0..e8a26a9f067 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3459,7 +3459,7 @@ int kvm_cpu_exec(CPUState *cpu)
 
     trace_kvm_cpu_exec();
 
-    if (kvm_arch_process_async_events(cpu)) {
+    if (ops->process_async_events && ops->process_async_events(cpu)) {
         return EXCP_HLT;
     }
 
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 914f8e3b089..06b133ebf53 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1619,11 +1619,6 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs)
     return true;
 }
 
-int kvm_arch_process_async_events(CPUState *cs)
-{
-    return 0;
-}
-
 /**
  * kvm_arm_hw_debug_active:
  * @cpu: ARMCPU
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 6b75eb038e1..163d60a1060 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -238,6 +238,7 @@ static const KVMCPUOps x86_kvm_cpu_ops = {
     .pre_run = x86_kvm_pre_run,
     .post_run = x86_kvm_post_run,
     .handle_exit = x86_kvm_handle_exit,
+    .process_async_events = x86_kvm_process_async_events,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index dfc70eac3db..83c4451cf31 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6040,7 +6040,7 @@ MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run)
     return cpu_get_mem_attrs(env);
 }
 
-int kvm_arch_process_async_events(CPUState *cs)
+int x86_kvm_process_async_events(CPUState *cs)
 {
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *env = &cpu->env;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index b23031007c2..600903a2280 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1517,7 +1517,7 @@ int kvm_arch_irqchip_create(KVMState *s)
     return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
 }
 
-int kvm_arch_process_async_events(CPUState *cs)
+static int loongarch_kvm_process_async_events(CPUState *cs)
 {
     return cs->halted;
 }
@@ -1644,6 +1644,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 
 static const KVMCPUOps loongarch_kvm_cpu_ops = {
     .handle_exit = loongarch_kvm_handle_exit,
+    .process_async_events = loongarch_kvm_process_async_events,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 25aaefd7649..e52f0b84ee3 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1336,7 +1336,7 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level)
     return 0;
 }
 
-int kvm_arch_process_async_events(CPUState *cs)
+static int ppc_kvm_process_async_events(CPUState *cs)
 {
     return cs->halted;
 }
@@ -3074,6 +3074,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 
 static const KVMCPUOps ppc_kvm_cpu_ops = {
     .handle_exit = ppc_kvm_handle_exit,
+    .process_async_events = ppc_kvm_process_async_events,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 8944961a939..a5333083765 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1635,11 +1635,6 @@ int kvm_arch_irqchip_create(KVMState *s)
     return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
 }
 
-int kvm_arch_process_async_events(CPUState *cs)
-{
-    return 0;
-}
-
 bool kvm_arch_stop_on_emulation_error(CPUState *cs)
 {
     return true;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 967706a87e1..420703f7683 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -984,7 +984,7 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
     }
 }
 
-int kvm_arch_process_async_events(CPUState *cs)
+static int s390x_kvm_process_async_events(CPUState *cs)
 {
     return cs->halted;
 }
@@ -2651,6 +2651,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 
 static const KVMCPUOps s390x_kvm_cpu_ops = {
     .handle_exit = s390x_kvm_handle_exit,
+    .process_async_events = s390x_kvm_process_async_events,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 12/23] accel/kvm: port kvm_arch_[put|get]_registers to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (10 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 11/23] accel/kvm: port kvm_arch_process_async_events " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 13/23] accel/kvm: port kvm_arch_pre_create_vcpu " Alex Bennée
                   ` (11 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

The ability to save and restore register state from KVM is required
for both migration and the gdbstub. These hooks are mandatory for any
KVM implementation.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 11 +++++++++++
 include/system/kvm.h        |  4 ----
 target/i386/kvm/kvm_i386.h  |  2 ++
 accel/kvm/kvm-all.c         |  6 ++++--
 target/arm/kvm.c            |  6 ++++--
 target/i386/kvm/kvm-cpu.c   |  2 ++
 target/i386/kvm/kvm.c       |  4 ++--
 target/loongarch/kvm/kvm.c  |  7 +++++--
 target/ppc/kvm.c            |  6 ++++--
 target/riscv/kvm/kvm-cpu.c  |  7 +++++--
 target/s390x/kvm/kvm.c      |  7 +++++--
 11 files changed, 44 insertions(+), 18 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index cbd3935ba4d..b3f6b8e47b7 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -12,12 +12,21 @@
 #include "qom/object.h"
 #include "hw/core/cpu.h"
 #include "accel/accel-cpu-target.h"
+#include "system/kvm.h"
 
 struct kvm_run;
 
 /**
  * struct KVMCPUOps - Target-specific per-vCPU operations for KVM
  *
+ * @get_registers: Mandatory callback to synchronize architecture-specific
+ *                 vCPU register state from KVM into QEMU's CPUState.
+ *                 Returns 0 on success, or a negative errno on failure.
+ * @put_registers: Mandatory callback to synchronize architecture-specific
+ *                 vCPU register state from QEMU's CPUState into KVM.
+ *                 The @level parameter specifies whether to write runtime,
+ *                 reset, or full state.
+ *                 Returns 0 on success, or a negative errno on failure.
  * @pre_run: Optional callback executed immediately prior to entering the
  *           KVM_RUN ioctl in the vCPU thread loop. Used by architectures
  *           that need to inject pending events (e.g. x86 NMI/SMI) or verify
@@ -45,6 +54,8 @@ struct kvm_run;
  *                        processing before execution.
  */
 typedef struct KVMCPUOps {
+    int (*get_registers)(CPUState *cpu, Error **errp);
+    int (*put_registers)(CPUState *cpu, KvmPutState level, Error **errp);
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
     MemTxAttrs (*post_run)(CPUState *cpu, struct kvm_run *run);
     int (*handle_exit)(CPUState *cpu, struct kvm_run *run);
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 8c705d21f79..b2d76f99df0 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -333,8 +333,6 @@ extern const KVMCapabilityInfo kvm_arch_required_capabilities[];
 
 void kvm_arch_accel_class_init(ObjectClass *oc);
 
-int kvm_arch_get_registers(CPUState *cpu, Error **errp);
-
 typedef enum kvm_put_state {
     /* state subset only touched by the VCPU itself during runtime */
     KVM_PUT_RUNTIME_STATE = 1,
@@ -344,8 +342,6 @@ typedef enum kvm_put_state {
     KVM_PUT_FULL_STATE = 3,
 } KvmPutState;
 
-int kvm_arch_put_registers(CPUState *cpu, KvmPutState level, Error **errp);
-
 int kvm_arch_get_default_type(MachineState *ms);
 
 int kvm_arch_init(MachineState *ms, KVMState *s);
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index bff587a56de..2c92afc3320 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -33,6 +33,8 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
 
 int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
+int x86_kvm_get_registers(CPUState *cs, Error **errp);
+int x86_kvm_put_registers(CPUState *cpu, KvmPutState level, Error **errp);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
 MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run);
 int x86_kvm_handle_exit(CPUState *cs, struct kvm_run *run);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index e8a26a9f067..3de05bb8bb8 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3214,8 +3214,9 @@ void kvm_flush_coalesced_mmio_buffer(void)
 static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
 {
     if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
+        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
         Error *err = NULL;
-        int ret = kvm_arch_get_registers(cpu, &err);
+        int ret = ops->get_registers(cpu, &err);
         if (ret) {
             if (err) {
                 error_reportf_err(err, "Failed to synchronize CPU state: ");
@@ -3241,8 +3242,9 @@ void kvm_cpu_synchronize_state(CPUState *cpu)
 static bool kvm_cpu_synchronize_put(CPUState *cpu, KvmPutState state,
                                     const char *desc)
 {
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     Error *err = NULL;
-    int ret = kvm_arch_put_registers(cpu, state, &err);
+    int ret = ops->put_registers(cpu, state, &err);
     if (ret) {
         if (err) {
             error_reportf_err(err, "Restoring resisters %s: ", desc);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 06b133ebf53..ea8c4d02ee8 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -2198,7 +2198,7 @@ static int kvm_arch_put_sve(CPUState *cs, uint32_t vq, bool have_ffr)
     return 0;
 }
 
-int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+static int arm_kvm_put_registers(CPUState *cs, KvmPutState level, Error **errp)
 {
     uint64_t val;
     uint32_t fpr;
@@ -2383,7 +2383,7 @@ static int kvm_arch_get_sve(CPUState *cs, uint32_t vq, bool have_ffr)
     return 0;
 }
 
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+static int arm_kvm_get_registers(CPUState *cs, Error **errp)
 {
     uint64_t val;
     unsigned int el;
@@ -2661,6 +2661,8 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
 }
 
 static const KVMCPUOps arm_kvm_cpu_ops = {
+    .get_registers = arm_kvm_get_registers,
+    .put_registers = arm_kvm_put_registers,
     .pre_run = arm_kvm_pre_run,
     .post_run = arm_kvm_post_run,
     .handle_exit = arm_kvm_handle_exit,
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 163d60a1060..08308ef8a80 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -235,6 +235,8 @@ static void kvm_cpu_instance_init(CPUState *cs)
 }
 
 static const KVMCPUOps x86_kvm_cpu_ops = {
+    .get_registers = x86_kvm_get_registers,
+    .put_registers = x86_kvm_put_registers,
     .pre_run = x86_kvm_pre_run,
     .post_run = x86_kvm_post_run,
     .handle_exit = x86_kvm_handle_exit,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 83c4451cf31..7ee6d3d4f38 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -5712,7 +5712,7 @@ static int kvm_get_nested_state(X86CPU *cpu)
     return ret;
 }
 
-int kvm_arch_put_registers(CPUState *cpu, KvmPutState level, Error **errp)
+int x86_kvm_put_registers(CPUState *cpu, KvmPutState level, Error **errp)
 {
     X86CPU *x86_cpu = X86_CPU(cpu);
     int ret;
@@ -5817,7 +5817,7 @@ int kvm_arch_put_registers(CPUState *cpu, KvmPutState level, Error **errp)
     return 0;
 }
 
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+int x86_kvm_get_registers(CPUState *cs, Error **errp)
 {
     X86CPU *cpu = X86_CPU(cs);
     int ret;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 600903a2280..1e7565732e8 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -823,7 +823,7 @@ static int kvm_loongarch_put_cpucfg(CPUState *cs)
     return ret;
 }
 
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+static int loongarch_kvm_get_registers(CPUState *cs, Error **errp)
 {
     int ret;
 
@@ -861,7 +861,8 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
     return ret;
 }
 
-int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+static int loongarch_kvm_put_registers(CPUState *cs, KvmPutState level,
+                                       Error **errp)
 {
     int ret;
     static int once;
@@ -1643,6 +1644,8 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps loongarch_kvm_cpu_ops = {
+    .get_registers = loongarch_kvm_get_registers,
+    .put_registers = loongarch_kvm_put_registers,
     .handle_exit = loongarch_kvm_handle_exit,
     .process_async_events = loongarch_kvm_process_async_events,
 };
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index e52f0b84ee3..25f797cb2d8 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -908,7 +908,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu)
     return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs);
 }
 
-int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+static int ppc_kvm_put_registers(CPUState *cs, KvmPutState level, Error **errp)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
@@ -1213,7 +1213,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu)
     return 0;
 }
 
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+static int ppc_kvm_get_registers(CPUState *cs, Error **errp)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *env = &cpu->env;
@@ -3073,6 +3073,8 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps ppc_kvm_cpu_ops = {
+    .get_registers = ppc_kvm_get_registers,
+    .put_registers = ppc_kvm_put_registers,
     .handle_exit = ppc_kvm_handle_exit,
     .process_async_events = ppc_kvm_process_async_events,
 };
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index a5333083765..c38c07a563b 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1389,7 +1389,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_LAST_INFO
 };
 
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+static int riscv_kvm_get_registers(CPUState *cs, Error **errp)
 {
     int ret = 0;
 
@@ -1444,7 +1444,8 @@ static int kvm_riscv_put_mp_state(CPUState *cs)
     return kvm_vcpu_ioctl(cs, KVM_SET_MP_STATE, &mp_state);
 }
 
-int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+static int riscv_kvm_put_registers(CPUState *cs, KvmPutState level,
+                                   Error **errp)
 {
     int ret = 0;
 
@@ -2183,6 +2184,8 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
 }
 
 static const KVMCPUOps riscv_kvm_cpu_ops = {
+    .get_registers = riscv_kvm_get_registers,
+    .put_registers = riscv_kvm_put_registers,
     .handle_exit = riscv_kvm_handle_exit,
 };
 
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 420703f7683..c85d286288b 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -471,7 +471,8 @@ static int can_sync_regs(CPUState *cs, int regs)
                                 KVM_SYNC_CRS | KVM_SYNC_PREFIX | \
                                 KVM_SYNC_PFAULT)
 
-int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
+static int s390x_kvm_put_registers(CPUState *cs, KvmPutState level,
+                                   Error **errp)
 {
     CPUS390XState *env = cpu_env(cs);
     struct kvm_fpu fpu = {};
@@ -582,7 +583,7 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
     return 0;
 }
 
-int kvm_arch_get_registers(CPUState *cs, Error **errp)
+static int s390x_kvm_get_registers(CPUState *cs, Error **errp)
 {
     CPUS390XState *env = cpu_env(cs);
     struct kvm_fpu fpu;
@@ -2650,6 +2651,8 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps s390x_kvm_cpu_ops = {
+    .get_registers = s390x_kvm_get_registers,
+    .put_registers = s390x_kvm_put_registers,
     .handle_exit = s390x_kvm_handle_exit,
     .process_async_events = s390x_kvm_process_async_events,
 };
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 13/23] accel/kvm: port kvm_arch_pre_create_vcpu to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (11 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 12/23] accel/kvm: port kvm_arch_[put|get]_registers " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 14/23] accel/kvm: port kvm_arch_init_vcpu " Alex Bennée
                   ` (10 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Only x86 actually does anything for this.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h |  7 +++++++
 include/system/kvm.h        |  1 -
 target/i386/kvm/kvm_i386.h  |  1 +
 accel/kvm/kvm-all.c         | 19 +++++++++++++------
 target/arm/kvm.c            |  5 -----
 target/i386/kvm/kvm-cpu.c   |  1 +
 target/i386/kvm/kvm.c       |  2 +-
 target/loongarch/kvm/kvm.c  |  5 -----
 target/ppc/kvm.c            |  5 -----
 target/riscv/kvm/kvm-cpu.c  |  5 -----
 target/s390x/kvm/kvm.c      |  5 -----
 11 files changed, 23 insertions(+), 33 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index b3f6b8e47b7..9b8a54253b1 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -19,6 +19,12 @@ struct kvm_run;
 /**
  * struct KVMCPUOps - Target-specific per-vCPU operations for KVM
  *
+ * @pre_create_vcpu: Optional callback executed before creating the KVM vCPU
+ *                   (via KVM_CREATE_VCPU). Used by architectures that need
+ *                   to configure VM-level capabilities or features before
+ *                   vCPUs are created (e.g. x86 PMU disable or TDX).
+ *                   May be NULL if the target does not require pre-creation
+ *                   handling.
  * @get_registers: Mandatory callback to synchronize architecture-specific
  *                 vCPU register state from KVM into QEMU's CPUState.
  *                 Returns 0 on success, or a negative errno on failure.
@@ -54,6 +60,7 @@ struct kvm_run;
  *                        processing before execution.
  */
 typedef struct KVMCPUOps {
+    int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
     int (*get_registers)(CPUState *cpu, Error **errp);
     int (*put_registers)(CPUState *cpu, KvmPutState level, Error **errp);
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
diff --git a/include/system/kvm.h b/include/system/kvm.h
index b2d76f99df0..3b08eb4f5d0 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -346,7 +346,6 @@ int kvm_arch_get_default_type(MachineState *ms);
 
 int kvm_arch_init(MachineState *ms, KVMState *s);
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp);
 int kvm_arch_init_vcpu(CPUState *cpu);
 int kvm_arch_destroy_vcpu(CPUState *cpu);
 
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 2c92afc3320..b5dace5d3be 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -33,6 +33,7 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
 
 int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
+int x86_kvm_pre_create_vcpu(CPUState *cpu, Error **errp);
 int x86_kvm_get_registers(CPUState *cs, Error **errp);
 int x86_kvm_put_registers(CPUState *cpu, KvmPutState level, Error **errp);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 3de05bb8bb8..dbd4cfc7c7a 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -460,6 +460,8 @@ static int kvm_rebind_vcpus(Error **errp)
     int kvm_fd, ret = 0;
 
     CPU_FOREACH(cpu) {
+        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+
         vcpu_id = kvm_arch_vcpu_id(cpu);
 
         if (cpu->kvm_fd) {
@@ -480,9 +482,11 @@ static int kvm_rebind_vcpus(Error **errp)
             goto err;
         }
 
-        ret = kvm_arch_pre_create_vcpu(cpu, errp);
-        if (ret < 0) {
-            goto err;
+        if (ops->pre_create_vcpu) {
+            ret = ops->pre_create_vcpu(cpu, errp);
+            if (ret < 0) {
+                goto err;
+            }
         }
 
         kvm_fd = kvm_vm_ioctl(s, KVM_CREATE_VCPU, vcpu_id);
@@ -723,14 +727,17 @@ static int map_kvm_dirty_gfns(KVMState *s, CPUState *cpu, Error **errp)
 
 int kvm_init_vcpu(CPUState *cpu, Error **errp)
 {
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     KVMState *s = kvm_state;
     int ret;
 
     trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
 
-    ret = kvm_arch_pre_create_vcpu(cpu, errp);
-    if (ret < 0) {
-        goto err;
+    if (ops->pre_create_vcpu) {
+        ret = ops->pre_create_vcpu(cpu, errp);
+        if (ret < 0) {
+            goto err;
+        }
     }
 
     ret = kvm_create_vcpu(cpu);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ea8c4d02ee8..da6c3e0b3d3 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1994,11 +1994,6 @@ static int kvm_arm_sve_set_vls(ARMCPU *cpu)
 
 #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
-{
-    return 0;
-}
-
 int kvm_arch_init_vcpu(CPUState *cs)
 {
     int ret;
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 08308ef8a80..e2cf42a126e 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -235,6 +235,7 @@ static void kvm_cpu_instance_init(CPUState *cs)
 }
 
 static const KVMCPUOps x86_kvm_cpu_ops = {
+    .pre_create_vcpu = x86_kvm_pre_create_vcpu,
     .get_registers = x86_kvm_get_registers,
     .put_registers = x86_kvm_put_registers,
     .pre_run = x86_kvm_pre_run,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 7ee6d3d4f38..1c53b62a1f7 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -2056,7 +2056,7 @@ full:
     abort();
 }
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
+int x86_kvm_pre_create_vcpu(CPUState *cpu, Error **errp)
 {
     static bool first = true;
     int ret;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 1e7565732e8..9ce6e9e65b4 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1297,11 +1297,6 @@ static int kvm_cpu_check_misc_v1_1(CPUState *cs, Error **errp)
     return 0;
 }
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
-{
-    return 0;
-}
-
 int kvm_arch_init_vcpu(CPUState *cs)
 {
     uint64_t val;
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 25f797cb2d8..8a2d2421dc2 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -480,11 +480,6 @@ static void kvmppc_hw_debug_points_init(CPUPPCState *cenv)
     }
 }
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
-{
-    return 0;
-}
-
 int kvm_arch_init_vcpu(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index c38c07a563b..cef9d90c66f 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1579,11 +1579,6 @@ static int kvm_vcpu_enable_sbi_dbcn(RISCVCPU *cpu, CPUState *cs)
     return kvm_set_one_reg(cs, kvm_sbi_dbcn.kvm_reg_id, &reg);
 }
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
-{
-    return 0;
-}
-
 int kvm_arch_init_vcpu(CPUState *cs)
 {
     int ret = 0;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index c85d286288b..64020450dec 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -400,11 +400,6 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
     return cpu->cpu_index;
 }
 
-int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp)
-{
-    return 0;
-}
-
 int kvm_arch_init_vcpu(CPUState *cs)
 {
     unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 14/23] accel/kvm: port kvm_arch_init_vcpu to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (12 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 13/23] accel/kvm: port kvm_arch_pre_create_vcpu " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 15/23] accel/kvm: port kvm_arch_destroy_vcpu " Alex Bennée
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Every architecture needs to implement this. I did note that loongarch
references init_vcpu for feature detection but maybe that should be
moved to kvm_arch_pre_create_vcpu?

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 4 ++++
 include/system/kvm.h        | 1 -
 target/i386/kvm/kvm_i386.h  | 1 +
 accel/kvm/kvm-all.c         | 8 ++++----
 target/arm/kvm.c            | 3 ++-
 target/i386/kvm/kvm-cpu.c   | 1 +
 target/i386/kvm/kvm.c       | 2 +-
 target/loongarch/cpu.c      | 8 ++++----
 target/loongarch/kvm/kvm.c  | 3 ++-
 target/ppc/kvm.c            | 3 ++-
 target/riscv/kvm/kvm-cpu.c  | 3 ++-
 target/s390x/kvm/kvm.c      | 3 ++-
 12 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 9b8a54253b1..23557a42ba7 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -25,6 +25,9 @@ struct kvm_run;
  *                   vCPUs are created (e.g. x86 PMU disable or TDX).
  *                   May be NULL if the target does not require pre-creation
  *                   handling.
+ * @init_vcpu: Mandatory callback executed to perform architecture-specific
+ *             initialization of a newly created KVM vCPU.
+ *             Returns 0 on success, or a negative errno on failure.
  * @get_registers: Mandatory callback to synchronize architecture-specific
  *                 vCPU register state from KVM into QEMU's CPUState.
  *                 Returns 0 on success, or a negative errno on failure.
@@ -61,6 +64,7 @@ struct kvm_run;
  */
 typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
+    int (*init_vcpu)(CPUState *cpu);
     int (*get_registers)(CPUState *cpu, Error **errp);
     int (*put_registers)(CPUState *cpu, KvmPutState level, Error **errp);
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 3b08eb4f5d0..a722f266dae 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -346,7 +346,6 @@ int kvm_arch_get_default_type(MachineState *ms);
 
 int kvm_arch_init(MachineState *ms, KVMState *s);
 
-int kvm_arch_init_vcpu(CPUState *cpu);
 int kvm_arch_destroy_vcpu(CPUState *cpu);
 
 #ifdef TARGET_KVM_HAVE_RESET_PARKED_VCPU
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index b5dace5d3be..8af5a9dc0ef 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -34,6 +34,7 @@ bool kvm_hyperv_expand_features(X86CPU *cpu, Error **errp);
 int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
 int x86_kvm_pre_create_vcpu(CPUState *cpu, Error **errp);
+int x86_kvm_init_vcpu(CPUState *cs);
 int x86_kvm_get_registers(CPUState *cs, Error **errp);
 int x86_kvm_put_registers(CPUState *cpu, KvmPutState level, Error **errp);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index dbd4cfc7c7a..d877edaa5e8 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -510,10 +510,10 @@ static int kvm_rebind_vcpus(Error **errp)
             }
         }
 
-        ret = kvm_arch_init_vcpu(cpu);
+        ret = ops->init_vcpu(cpu);
         if (ret < 0) {
             error_setg_errno(errp, -ret,
-                             "kvm_init_vcpu: kvm_arch_init_vcpu failed (%lu)",
+                             "kvm_init_vcpu: init_vcpu failed (%lu)",
                              vcpu_id);
         }
 
@@ -760,10 +760,10 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
         }
     }
 
-    ret = kvm_arch_init_vcpu(cpu);
+    ret = ops->init_vcpu(cpu);
     if (ret < 0) {
         error_setg_errno(errp, -ret,
-                         "kvm_init_vcpu: kvm_arch_init_vcpu failed (%lu)",
+                         "kvm_init_vcpu: init_vcpu failed (%lu)",
                          kvm_arch_vcpu_id(cpu));
     }
     cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index da6c3e0b3d3..b62f40623c3 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1994,7 +1994,7 @@ static int kvm_arm_sve_set_vls(ARMCPU *cpu)
 
 #define ARM_CPU_ID_MPIDR       3, 0, 0, 0, 5
 
-int kvm_arch_init_vcpu(CPUState *cs)
+static int arm_kvm_init_vcpu(CPUState *cs)
 {
     int ret;
     uint64_t mpidr;
@@ -2656,6 +2656,7 @@ void arm_gic_cap_kvm_probe(GICCapability *v2, GICCapability *v3)
 }
 
 static const KVMCPUOps arm_kvm_cpu_ops = {
+    .init_vcpu = arm_kvm_init_vcpu,
     .get_registers = arm_kvm_get_registers,
     .put_registers = arm_kvm_put_registers,
     .pre_run = arm_kvm_pre_run,
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index e2cf42a126e..6c547f204f8 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -236,6 +236,7 @@ static void kvm_cpu_instance_init(CPUState *cs)
 
 static const KVMCPUOps x86_kvm_cpu_ops = {
     .pre_create_vcpu = x86_kvm_pre_create_vcpu,
+    .init_vcpu = x86_kvm_init_vcpu,
     .get_registers = x86_kvm_get_registers,
     .put_registers = x86_kvm_put_registers,
     .pre_run = x86_kvm_pre_run,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 1c53b62a1f7..46b7e497aaf 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -2218,7 +2218,7 @@ static void kvm_init_pmu_info(struct kvm_cpuid2 *cpuid, X86CPU *cpu)
     }
 }
 
-int kvm_arch_init_vcpu(CPUState *cs)
+int x86_kvm_init_vcpu(CPUState *cs)
 {
     struct {
         struct kvm_cpuid2 cpuid;
diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c
index 54c26998979..d8f54a5526c 100644
--- a/target/loongarch/cpu.c
+++ b/target/loongarch/cpu.c
@@ -177,7 +177,7 @@ static void loongarch_set_lsx(Object *obj, bool value, Error **errp)
     }
 
     if (kvm_enabled()) {
-        /* kvm feature detection in function kvm_arch_init_vcpu */
+        /* kvm feature detection in loongarch_kvm_init_vcpu */
         return;
     }
 
@@ -213,7 +213,7 @@ static void loongarch_set_lasx(Object *obj, bool value, Error **errp)
     }
 
     if (kvm_enabled()) {
-        /* kvm feature detection in function kvm_arch_init_vcpu */
+        /* kvm feature detection in loongarch_kvm_init_vcpu */
         return;
     }
 
@@ -241,7 +241,7 @@ static void loongarch_set_msgint(Object *obj, bool value, Error **errp)
     cpu->msgint = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
 
     if (kvm_enabled()) {
-        /* kvm feature detection in function kvm_arch_init_vcpu */
+        /* kvm feature detection in loongarch_kvm_init_vcpu */
         return;
     }
 
@@ -260,7 +260,7 @@ static void loongarch_set_ptw(Object *obj, bool value, Error **errp)
     cpu->ptw = value ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
 
     if (kvm_enabled()) {
-        /* kvm feature detection in function kvm_arch_init_vcpu */
+        /* kvm feature detection in loongarch_kvm_init_vcpu */
         return;
     }
 
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 9ce6e9e65b4..8f2ceb50a78 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1297,7 +1297,7 @@ static int kvm_cpu_check_misc_v1_1(CPUState *cs, Error **errp)
     return 0;
 }
 
-int kvm_arch_init_vcpu(CPUState *cs)
+static int loongarch_kvm_init_vcpu(CPUState *cs)
 {
     uint64_t val;
     int ret;
@@ -1639,6 +1639,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps loongarch_kvm_cpu_ops = {
+    .init_vcpu = loongarch_kvm_init_vcpu,
     .get_registers = loongarch_kvm_get_registers,
     .put_registers = loongarch_kvm_put_registers,
     .handle_exit = loongarch_kvm_handle_exit,
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 8a2d2421dc2..075999b553a 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -480,7 +480,7 @@ static void kvmppc_hw_debug_points_init(CPUPPCState *cenv)
     }
 }
 
-int kvm_arch_init_vcpu(CPUState *cs)
+static int ppc_kvm_init_vcpu(CPUState *cs)
 {
     PowerPCCPU *cpu = POWERPC_CPU(cs);
     CPUPPCState *cenv = &cpu->env;
@@ -3068,6 +3068,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps ppc_kvm_cpu_ops = {
+    .init_vcpu = ppc_kvm_init_vcpu,
     .get_registers = ppc_kvm_get_registers,
     .put_registers = ppc_kvm_put_registers,
     .handle_exit = ppc_kvm_handle_exit,
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index cef9d90c66f..b202882a155 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1579,7 +1579,7 @@ static int kvm_vcpu_enable_sbi_dbcn(RISCVCPU *cpu, CPUState *cs)
     return kvm_set_one_reg(cs, kvm_sbi_dbcn.kvm_reg_id, &reg);
 }
 
-int kvm_arch_init_vcpu(CPUState *cs)
+static int riscv_kvm_init_vcpu(CPUState *cs)
 {
     int ret = 0;
     RISCVCPU *cpu = RISCV_CPU(cs);
@@ -2179,6 +2179,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
 }
 
 static const KVMCPUOps riscv_kvm_cpu_ops = {
+    .init_vcpu = riscv_kvm_init_vcpu,
     .get_registers = riscv_kvm_get_registers,
     .put_registers = riscv_kvm_put_registers,
     .handle_exit = riscv_kvm_handle_exit,
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 64020450dec..478b21a57fd 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -400,7 +400,7 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu)
     return cpu->cpu_index;
 }
 
-int kvm_arch_init_vcpu(CPUState *cs)
+static int s390x_kvm_init_vcpu(CPUState *cs)
 {
     unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
     S390CPU *cpu = S390_CPU(cs);
@@ -2646,6 +2646,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 }
 
 static const KVMCPUOps s390x_kvm_cpu_ops = {
+    .init_vcpu = s390x_kvm_init_vcpu,
     .get_registers = s390x_kvm_get_registers,
     .put_registers = s390x_kvm_put_registers,
     .handle_exit = s390x_kvm_handle_exit,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 15/23] accel/kvm: port kvm_arch_destroy_vcpu to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (13 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 14/23] accel/kvm: port kvm_arch_init_vcpu " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 16/23] accel/kvm: port kvm_arch_vpcu_id " Alex Bennée
                   ` (8 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Not every architecture was doing something here so we can make it an
optional hook.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h |  6 ++++++
 include/system/kvm.h        |  2 --
 target/i386/kvm/kvm_i386.h  |  1 +
 accel/kvm/kvm-all.c         | 17 +++++++++++------
 target/arm/kvm.c            |  5 -----
 target/i386/kvm/kvm-cpu.c   |  1 +
 target/i386/kvm/kvm.c       |  2 +-
 target/loongarch/kvm/kvm.c  |  3 ++-
 target/ppc/kvm.c            |  5 -----
 target/riscv/kvm/kvm-cpu.c  |  5 -----
 target/s390x/kvm/kvm.c      |  3 ++-
 11 files changed, 24 insertions(+), 26 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 23557a42ba7..171568e08cb 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -28,6 +28,11 @@ struct kvm_run;
  * @init_vcpu: Mandatory callback executed to perform architecture-specific
  *             initialization of a newly created KVM vCPU.
  *             Returns 0 on success, or a negative errno on failure.
+ * @destroy_vcpu: Optional callback executed when destroying a KVM vCPU
+ *                (e.g. to free architecture-specific buffers or deregister
+ *                state change handlers).
+ *                May be NULL if no architecture-specific cleanup is required.
+ *                Returns 0 on success, or a negative errno on failure.
  * @get_registers: Mandatory callback to synchronize architecture-specific
  *                 vCPU register state from KVM into QEMU's CPUState.
  *                 Returns 0 on success, or a negative errno on failure.
@@ -65,6 +70,7 @@ struct kvm_run;
 typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
     int (*init_vcpu)(CPUState *cpu);
+    int (*destroy_vcpu)(CPUState *cpu);
     int (*get_registers)(CPUState *cpu, Error **errp);
     int (*put_registers)(CPUState *cpu, KvmPutState level, Error **errp);
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
diff --git a/include/system/kvm.h b/include/system/kvm.h
index a722f266dae..a66344cc70c 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -346,8 +346,6 @@ int kvm_arch_get_default_type(MachineState *ms);
 
 int kvm_arch_init(MachineState *ms, KVMState *s);
 
-int kvm_arch_destroy_vcpu(CPUState *cpu);
-
 #ifdef TARGET_KVM_HAVE_RESET_PARKED_VCPU
 void kvm_arch_reset_parked_vcpu(unsigned long vcpu_id, int kvm_fd);
 #else
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 8af5a9dc0ef..c7ffed75c1d 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -35,6 +35,7 @@ int kvm_get_vm_type(MachineState *ms);
 void kvm_arch_reset_vcpu(X86CPU *cs);
 int x86_kvm_pre_create_vcpu(CPUState *cpu, Error **errp);
 int x86_kvm_init_vcpu(CPUState *cs);
+int x86_kvm_destroy_vcpu(CPUState *cs);
 int x86_kvm_get_registers(CPUState *cs, Error **errp);
 int x86_kvm_put_registers(CPUState *cpu, KvmPutState level, Error **errp);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index d877edaa5e8..69117271fa3 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -468,9 +468,11 @@ static int kvm_rebind_vcpus(Error **errp)
             close(cpu->kvm_fd);
         }
 
-        ret = kvm_arch_destroy_vcpu(cpu);
-        if (ret < 0) {
-            goto err;
+        if (ops->destroy_vcpu) {
+            ret = ops->destroy_vcpu(cpu);
+            if (ret < 0) {
+                goto err;
+            }
         }
 
         if (s->coalesced_mmio_ring == (void *)cpu->kvm_run + PAGE_SIZE) {
@@ -647,14 +649,17 @@ static int vcpu_unmap_regions(KVMState *s, CPUState *cpu)
 
 static int do_kvm_destroy_vcpu(CPUState *cpu)
 {
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     KVMState *s = kvm_state;
     int ret = 0;
 
     trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
 
-    ret = kvm_arch_destroy_vcpu(cpu);
-    if (ret < 0) {
-        goto err;
+    if (ops->destroy_vcpu) {
+        ret = ops->destroy_vcpu(cpu);
+        if (ret < 0) {
+            goto err;
+        }
     }
 
     /* If I am the CPU that created coalesced_mmio_ring, then discard it */
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index b62f40623c3..042a075e612 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -2093,11 +2093,6 @@ static int arm_kvm_init_vcpu(CPUState *cs)
     return kvm_arm_init_cpreg_list(cpu);
 }
 
-int kvm_arch_destroy_vcpu(CPUState *cs)
-{
-    return 0;
-}
-
 /* Callers must hold the iothread mutex lock */
 static void kvm_inject_arm_sea(CPUState *c)
 {
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 6c547f204f8..8d250b3a847 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -237,6 +237,7 @@ static void kvm_cpu_instance_init(CPUState *cs)
 static const KVMCPUOps x86_kvm_cpu_ops = {
     .pre_create_vcpu = x86_kvm_pre_create_vcpu,
     .init_vcpu = x86_kvm_init_vcpu,
+    .destroy_vcpu = x86_kvm_destroy_vcpu,
     .get_registers = x86_kvm_get_registers,
     .put_registers = x86_kvm_put_registers,
     .pre_run = x86_kvm_pre_run,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 46b7e497aaf..a8109004e43 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -2533,7 +2533,7 @@ int x86_kvm_init_vcpu(CPUState *cs)
     return r;
 }
 
-int kvm_arch_destroy_vcpu(CPUState *cs)
+int x86_kvm_destroy_vcpu(CPUState *cs)
 {
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *env = &cpu->env;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 8f2ceb50a78..6705e6698bd 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1437,7 +1437,7 @@ void kvm_loongarch_cpu_post_init(LoongArchCPU *cpu)
                                     "Set off to disable KVM steal time.");
 }
 
-int kvm_arch_destroy_vcpu(CPUState *cs)
+static int loongarch_kvm_destroy_vcpu(CPUState *cs)
 {
     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
 
@@ -1640,6 +1640,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 
 static const KVMCPUOps loongarch_kvm_cpu_ops = {
     .init_vcpu = loongarch_kvm_init_vcpu,
+    .destroy_vcpu = loongarch_kvm_destroy_vcpu,
     .get_registers = loongarch_kvm_get_registers,
     .put_registers = loongarch_kvm_put_registers,
     .handle_exit = loongarch_kvm_handle_exit,
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 075999b553a..cb461963713 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -524,11 +524,6 @@ static int ppc_kvm_init_vcpu(CPUState *cs)
     return ret;
 }
 
-int kvm_arch_destroy_vcpu(CPUState *cs)
-{
-    return 0;
-}
-
 static void kvm_sw_tlb_put(PowerPCCPU *cpu)
 {
     CPUPPCState *env = &cpu->env;
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index b202882a155..4247cbec3d9 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1512,11 +1512,6 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
     return 0;
 }
 
-int kvm_arch_destroy_vcpu(CPUState *cs)
-{
-    return 0;
-}
-
 unsigned long kvm_arch_vcpu_id(CPUState *cpu)
 {
     return cpu->cpu_index;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 478b21a57fd..0dcd198afe3 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -409,7 +409,7 @@ static int s390x_kvm_init_vcpu(CPUState *cs)
     return 0;
 }
 
-int kvm_arch_destroy_vcpu(CPUState *cs)
+static int s390x_kvm_destroy_vcpu(CPUState *cs)
 {
     S390CPU *cpu = S390_CPU(cs);
 
@@ -2647,6 +2647,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 
 static const KVMCPUOps s390x_kvm_cpu_ops = {
     .init_vcpu = s390x_kvm_init_vcpu,
+    .destroy_vcpu = s390x_kvm_destroy_vcpu,
     .get_registers = s390x_kvm_get_registers,
     .put_registers = s390x_kvm_put_registers,
     .handle_exit = s390x_kvm_handle_exit,
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 16/23] accel/kvm: port kvm_arch_vpcu_id to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (14 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 15/23] accel/kvm: port kvm_arch_destroy_vcpu " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 17/23] accel/kvm: port kvm_arch_update_guest_debug " Alex Bennée
                   ` (7 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

This is probably one of the messier conversions so far because it's a
number that is used both by the generic KVM code but also the various
target specific interrupt controllers where the direct linking is
marginally beneficial.

A bunch of the targets just treat cpu->cpu_index directly at the vcpu
id so we take advantage of that default implementation with a common
helper.

**Q** is it worth in-lining the helper or indeed just finding to stash
the value in CPUState?

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h |  6 ++++++
 include/system/kvm.h        |  2 +-
 target/i386/kvm/kvm_i386.h  |  1 +
 accel/kvm/kvm-all.c         | 28 +++++++++++++++++++---------
 hw/i386/kvm/xen_evtchn.c    |  6 +++---
 hw/intc/openpic_kvm.c       |  4 ++--
 hw/intc/spapr_xive_kvm.c    | 10 +++++-----
 hw/intc/xics_kvm.c          |  6 +++---
 target/arm/kvm.c            |  5 -----
 target/i386/kvm/kvm-cpu.c   |  1 +
 target/i386/kvm/kvm.c       |  4 ++--
 target/loongarch/kvm/kvm.c  |  5 -----
 target/ppc/kvm.c            |  3 ++-
 target/riscv/kvm/kvm-cpu.c  |  7 +------
 target/s390x/kvm/kvm.c      |  5 -----
 15 files changed, 46 insertions(+), 47 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 171568e08cb..be4031d9011 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -33,6 +33,11 @@ struct kvm_run;
  *                state change handlers).
  *                May be NULL if no architecture-specific cleanup is required.
  *                Returns 0 on success, or a negative errno on failure.
+ * @vcpu_id: Optional callback returning the architecture-specific KVM vCPU ID
+ *           to be passed to KVM_CREATE_VCPU and associated ioctls (such as
+ *           the APIC ID on x86 or the PPC vcpu_id).
+ *           May be NULL if the target uses cpu->cpu_index directly as the
+ *           vCPU ID.
  * @get_registers: Mandatory callback to synchronize architecture-specific
  *                 vCPU register state from KVM into QEMU's CPUState.
  *                 Returns 0 on success, or a negative errno on failure.
@@ -71,6 +76,7 @@ typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
     int (*init_vcpu)(CPUState *cpu);
     int (*destroy_vcpu)(CPUState *cpu);
+    unsigned long (*vcpu_id)(CPUState *cpu);
     int (*get_registers)(CPUState *cpu, Error **errp);
     int (*put_registers)(CPUState *cpu, KvmPutState level, Error **errp);
     void (*pre_run)(CPUState *cpu, struct kvm_run *run);
diff --git a/include/system/kvm.h b/include/system/kvm.h
index a66344cc70c..2ecae10cdff 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -357,7 +357,7 @@ static inline void kvm_arch_reset_parked_vcpu(unsigned long vcpu_id, int kvm_fd)
 bool kvm_vcpu_id_is_valid(int vcpu_id);
 
 /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */
-unsigned long kvm_arch_vcpu_id(CPUState *cpu);
+unsigned long kvm_vcpu_id(CPUState *cpu);
 
 void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
 
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index c7ffed75c1d..f189bb92bb9 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -36,6 +36,7 @@ void kvm_arch_reset_vcpu(X86CPU *cs);
 int x86_kvm_pre_create_vcpu(CPUState *cpu, Error **errp);
 int x86_kvm_init_vcpu(CPUState *cs);
 int x86_kvm_destroy_vcpu(CPUState *cs);
+unsigned long x86_kvm_vcpu_id(CPUState *cs);
 int x86_kvm_get_registers(CPUState *cs, Error **errp);
 int x86_kvm_put_registers(CPUState *cpu, KvmPutState level, Error **errp);
 void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 69117271fa3..f10d93a98df 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -452,6 +452,16 @@ static void kvm_create_vcpu_internal(CPUState *cpu, KVMState *s, int kvm_fd)
     return;
 }
 
+unsigned long kvm_vcpu_id(CPUState *cpu)
+{
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+
+    if (ops && ops->vcpu_id) {
+        return ops->vcpu_id(cpu);
+    }
+    return cpu->cpu_index;
+}
+
 static int kvm_rebind_vcpus(Error **errp)
 {
     CPUState *cpu;
@@ -462,7 +472,7 @@ static int kvm_rebind_vcpus(Error **errp)
     CPU_FOREACH(cpu) {
         const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
 
-        vcpu_id = kvm_arch_vcpu_id(cpu);
+        vcpu_id = kvm_vcpu_id(cpu);
 
         if (cpu->kvm_fd) {
             close(cpu->kvm_fd);
@@ -533,10 +543,10 @@ static void kvm_park_vcpu(CPUState *cpu)
 {
     struct KVMParkedVcpu *vcpu;
 
-    trace_kvm_park_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
+    trace_kvm_park_vcpu(cpu->cpu_index, kvm_vcpu_id(cpu));
 
     vcpu = g_malloc0(sizeof(*vcpu));
-    vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
+    vcpu->vcpu_id = kvm_vcpu_id(cpu);
     vcpu->kvm_fd = cpu->kvm_fd;
     QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
 }
@@ -577,7 +587,7 @@ static void kvm_reset_parked_vcpus(KVMState *s)
  */
 static int kvm_create_vcpu(CPUState *cpu)
 {
-    unsigned long vcpu_id = kvm_arch_vcpu_id(cpu);
+    unsigned long vcpu_id = kvm_vcpu_id(cpu);
     KVMState *s = kvm_state;
     int kvm_fd;
 
@@ -653,7 +663,7 @@ static int do_kvm_destroy_vcpu(CPUState *cpu)
     KVMState *s = kvm_state;
     int ret = 0;
 
-    trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
+    trace_kvm_destroy_vcpu(cpu->cpu_index, kvm_vcpu_id(cpu));
 
     if (ops->destroy_vcpu) {
         ret = ops->destroy_vcpu(cpu);
@@ -702,7 +712,7 @@ static int map_kvm_run(KVMState *s, CPUState *cpu, Error **errp)
         ret = -errno;
         error_setg_errno(errp, ret,
                          "kvm_init_vcpu: mmap'ing vcpu state failed (%lu)",
-                         kvm_arch_vcpu_id(cpu));
+                         kvm_vcpu_id(cpu));
         goto err;
     }
 
@@ -736,7 +746,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
     KVMState *s = kvm_state;
     int ret;
 
-    trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu));
+    trace_kvm_init_vcpu(cpu->cpu_index, kvm_vcpu_id(cpu));
 
     if (ops->pre_create_vcpu) {
         ret = ops->pre_create_vcpu(cpu, errp);
@@ -749,7 +759,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
     if (ret < 0) {
         error_setg_errno(errp, -ret,
                          "kvm_init_vcpu: kvm_create_vcpu failed (%lu)",
-                         kvm_arch_vcpu_id(cpu));
+                         kvm_vcpu_id(cpu));
         goto err;
     }
 
@@ -769,7 +779,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
     if (ret < 0) {
         error_setg_errno(errp, -ret,
                          "kvm_init_vcpu: init_vcpu failed (%lu)",
-                         kvm_arch_vcpu_id(cpu));
+                         kvm_vcpu_id(cpu));
     }
     cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
 
diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c
index 9379383e532..98630563b6b 100644
--- a/hw/i386/kvm/xen_evtchn.c
+++ b/hw/i386/kvm/xen_evtchn.c
@@ -575,7 +575,7 @@ static int assign_kernel_port(uint16_t type, evtchn_port_t port,
     ha.u.evtchn.type = type;
     ha.u.evtchn.flags = 0;
     ha.u.evtchn.deliver.port.port = port;
-    ha.u.evtchn.deliver.port.vcpu = kvm_arch_vcpu_id(cpu);
+    ha.u.evtchn.deliver.port.vcpu = kvm_vcpu_id(cpu);
     ha.u.evtchn.deliver.port.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL;
 
     return kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_SET_ATTR, &ha);
@@ -937,7 +937,7 @@ static int set_port_pending(XenEvtchnState *s, evtchn_port_t port)
         }
 
         evt.port = port;
-        evt.vcpu = kvm_arch_vcpu_id(cpu);
+        evt.vcpu = kvm_vcpu_id(cpu);
         evt.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL;
 
         return kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_EVTCHN_SEND, &evt);
@@ -1815,7 +1815,7 @@ int xen_evtchn_translate_pirq_msi(struct kvm_irq_routing_entry *route,
 
     route->type = KVM_IRQ_ROUTING_XEN_EVTCHN;
     route->u.xen_evtchn.port = port;
-    route->u.xen_evtchn.vcpu = kvm_arch_vcpu_id(cpu);
+    route->u.xen_evtchn.vcpu = kvm_vcpu_id(cpu);
     route->u.xen_evtchn.priority = KVM_IRQ_ROUTING_XEN_EVTCHN_PRIO_2LEVEL;
 
     return 0; /* Handled */
diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c
index b099da20eb9..4131292b02b 100644
--- a/hw/intc/openpic_kvm.c
+++ b/hw/intc/openpic_kvm.c
@@ -188,7 +188,7 @@ static int kvm_openpic_handle_vmfd_change(NotifierWithReturn *notifier,
 
     CPU_FOREACH(cs) {
         ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
-                                   kvm_arch_vcpu_id(cs));
+                                   kvm_vcpu_id(cs));
         if (ret < 0) {
             return ret;
         }
@@ -322,7 +322,7 @@ int kvm_openpic_connect_vcpu(DeviceState *d, CPUState *cs)
     KVMOpenPICState *opp = KVM_OPENPIC(d);
 
     return kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_MPIC, 0, opp->fd,
-                               kvm_arch_vcpu_id(cs));
+                               kvm_vcpu_id(cs));
 }
 
 static const Property kvm_openpic_properties[] = {
diff --git a/hw/intc/spapr_xive_kvm.c b/hw/intc/spapr_xive_kvm.c
index 26d30b41c15..9cbe536cc7c 100644
--- a/hw/intc/spapr_xive_kvm.c
+++ b/hw/intc/spapr_xive_kvm.c
@@ -40,7 +40,7 @@ static QLIST_HEAD(, KVMEnabledCPU)
 static bool kvm_cpu_is_enabled(CPUState *cs)
 {
     KVMEnabledCPU *enabled_cpu;
-    unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
+    unsigned long vcpu_id = kvm_vcpu_id(cs);
 
     QLIST_FOREACH(enabled_cpu, &kvm_enabled_cpus, node) {
         if (enabled_cpu->vcpu_id == vcpu_id) {
@@ -53,7 +53,7 @@ static bool kvm_cpu_is_enabled(CPUState *cs)
 static void kvm_cpu_enable(CPUState *cs)
 {
     KVMEnabledCPU *enabled_cpu;
-    unsigned long vcpu_id = kvm_arch_vcpu_id(cs);
+    unsigned long vcpu_id = kvm_vcpu_id(cs);
 
     enabled_cpu = g_malloc(sizeof(*enabled_cpu));
     enabled_cpu->vcpu_id = vcpu_id;
@@ -89,7 +89,7 @@ int kvmppc_xive_cpu_set_state(XiveTCTX *tctx, Error **errp)
     if (ret != 0) {
         error_setg_errno(errp, -ret,
                          "XIVE: could not restore KVM state of CPU %ld",
-                         kvm_arch_vcpu_id(tctx->cs));
+                         kvm_vcpu_id(tctx->cs));
         return ret;
     }
 
@@ -108,7 +108,7 @@ int kvmppc_xive_cpu_get_state(XiveTCTX *tctx, Error **errp)
     if (ret != 0) {
         error_setg_errno(errp, -ret,
                          "XIVE: could not capture KVM state of CPU %ld",
-                         kvm_arch_vcpu_id(tctx->cs));
+                         kvm_vcpu_id(tctx->cs));
         return ret;
     }
 
@@ -162,7 +162,7 @@ int kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp)
         return 0;
     }
 
-    vcpu_id = kvm_arch_vcpu_id(tctx->cs);
+    vcpu_id = kvm_vcpu_id(tctx->cs);
 
     trace_kvm_xive_cpu_connect(vcpu_id);
 
diff --git a/hw/intc/xics_kvm.c b/hw/intc/xics_kvm.c
index 61f66d1019d..fb16f628eca 100644
--- a/hw/intc/xics_kvm.c
+++ b/hw/intc/xics_kvm.c
@@ -80,7 +80,7 @@ void icp_get_kvm_state(ICPState *icp)
     ret = kvm_get_one_reg(icp->cs, KVM_REG_PPC_ICP_STATE, &state);
     if (ret != 0) {
         error_report("Unable to retrieve KVM interrupt controller state"
-                " for CPU %ld: %s", kvm_arch_vcpu_id(icp->cs), strerror(errno));
+                " for CPU %ld: %s", kvm_vcpu_id(icp->cs), strerror(errno));
         exit(1);
     }
 
@@ -127,7 +127,7 @@ int icp_set_kvm_state(ICPState *icp, Error **errp)
         error_setg_errno(errp, -ret,
                          "Unable to restore KVM interrupt controller state (0x%"
                          PRIx64 ") for CPU %ld", state,
-                         kvm_arch_vcpu_id(icp->cs));
+                         kvm_vcpu_id(icp->cs));
         return ret;
     }
 
@@ -148,7 +148,7 @@ void icp_kvm_realize(DeviceState *dev, Error **errp)
     }
 
     cs = icp->cs;
-    vcpu_id = kvm_arch_vcpu_id(cs);
+    vcpu_id = kvm_vcpu_id(cs);
 
     /*
      * If we are reusing a parked vCPU fd corresponding to the CPU
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 042a075e612..ad8166e0b41 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -708,11 +708,6 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
     return 0;
 }
 
-unsigned long kvm_arch_vcpu_id(CPUState *cpu)
-{
-    return cpu->cpu_index;
-}
-
 /* We track all the KVM devices which need their memory addresses
  * passing to the kernel in a list of these structures.
  * When board init is complete we run through the list and
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 8d250b3a847..6990cd8d5c4 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -238,6 +238,7 @@ static const KVMCPUOps x86_kvm_cpu_ops = {
     .pre_create_vcpu = x86_kvm_pre_create_vcpu,
     .init_vcpu = x86_kvm_init_vcpu,
     .destroy_vcpu = x86_kvm_destroy_vcpu,
+    .vcpu_id = x86_kvm_vcpu_id,
     .get_registers = x86_kvm_get_registers,
     .put_registers = x86_kvm_put_registers,
     .pre_run = x86_kvm_pre_run,
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index a8109004e43..a3076d43b45 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -862,7 +862,7 @@ static void cpu_update_state(void *opaque, bool running, RunState state)
     }
 }
 
-unsigned long kvm_arch_vcpu_id(CPUState *cs)
+unsigned long x86_kvm_vcpu_id(CPUState *cs)
 {
     X86CPU *cpu = X86_CPU(cs);
     return cpu->apic_id;
@@ -3046,7 +3046,7 @@ static void *kvm_msr_energy_thread(void *data)
                     thd_stat[i].is_vcpu = true;
                     thd_stat[i].vcpu_id = cpu->cpu_index;
                     pkg_stat[thd_stat[i].pkg_id].nb_vcpu++;
-                    thd_stat[i].acpi_id = kvm_arch_vcpu_id(cpu);
+                    thd_stat[i].acpi_id = kvm_vcpu_id(cpu);
                     break;
                 }
             }
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 6705e6698bd..97b6b448edf 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1445,11 +1445,6 @@ static int loongarch_kvm_destroy_vcpu(CPUState *cs)
     return 0;
 }
 
-unsigned long kvm_arch_vcpu_id(CPUState *cs)
-{
-    return cs->cpu_index;
-}
-
 int kvm_arch_release_virq_post(int virq)
 {
     return 0;
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index cb461963713..ffc7a33bf17 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -443,7 +443,7 @@ void kvm_check_mmu(PowerPCCPU *cpu, Error **errp)
 }
 #endif /* !defined (TARGET_PPC64) */
 
-unsigned long kvm_arch_vcpu_id(CPUState *cpu)
+static unsigned long ppc_kvm_vcpu_id(CPUState *cpu)
 {
     return POWERPC_CPU(cpu)->vcpu_id;
 }
@@ -3064,6 +3064,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
 
 static const KVMCPUOps ppc_kvm_cpu_ops = {
     .init_vcpu = ppc_kvm_init_vcpu,
+    .vcpu_id = ppc_kvm_vcpu_id,
     .get_registers = ppc_kvm_get_registers,
     .put_registers = ppc_kvm_put_registers,
     .handle_exit = ppc_kvm_handle_exit,
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 4247cbec3d9..d9984828048 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1512,11 +1512,6 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
     return 0;
 }
 
-unsigned long kvm_arch_vcpu_id(CPUState *cpu)
-{
-    return cpu->cpu_index;
-}
-
 static void kvm_riscv_vm_state_change(void *opaque, bool running,
                                       RunState state)
 {
@@ -1806,7 +1801,7 @@ void kvm_riscv_reset_vcpu(RISCVCPU *cpu)
         env->gpr[i] = 0;
     }
     env->pc = cpu->env.kernel_addr;
-    env->gpr[10] = kvm_arch_vcpu_id(CPU(cpu)); /* a0 */
+    env->gpr[10] = kvm_vcpu_id(CPU(cpu)); /* a0 */
     env->gpr[11] = cpu->env.fdt_addr;          /* a1 */
 
     kvm_riscv_reset_regs_csr(env);
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 0dcd198afe3..7400fe41f87 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -395,11 +395,6 @@ int kvm_arch_irqchip_create(KVMState *s)
     return 0;
 }
 
-unsigned long kvm_arch_vcpu_id(CPUState *cpu)
-{
-    return cpu->cpu_index;
-}
-
 static int s390x_kvm_init_vcpu(CPUState *cs)
 {
     unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 17/23] accel/kvm: port kvm_arch_update_guest_debug to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (15 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 16/23] accel/kvm: port kvm_arch_vpcu_id " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 18/23] accel/kvm: port kvm_arch_[insert|remove]_hw_breakpoints " Alex Bennée
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

As well as sw breakpoints.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 17 +++++++++++++++++
 include/system/kvm.h        |  8 +-------
 target/i386/kvm/kvm_i386.h  |  3 +++
 accel/kvm/kvm-all.c         | 34 +++++++++++++++++++++++++++++-----
 target/arm/kvm.c            | 12 +++++++++---
 target/i386/kvm/kvm-cpu.c   |  3 +++
 target/i386/kvm/kvm.c       |  6 +++---
 target/loongarch/kvm/kvm.c  | 12 +++++++++---
 target/ppc/kvm.c            | 12 +++++++++---
 target/riscv/kvm/kvm-cpu.c  | 19 ++++++++++++++++---
 target/s390x/kvm/kvm.c      | 12 +++++++++---
 11 files changed, 108 insertions(+), 30 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index be4031d9011..d2374e91cef 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -71,6 +71,20 @@ struct kvm_run;
  *                        return EXCP_HLT, or 0 if execution can proceed.
  *                        May be NULL if the target does not require event
  *                        processing before execution.
+ * @update_guest_debug: Optional callback executed when updating KVM guest
+ *                      debug structures for the vCPU. Used to configure
+ *                      architecture-specific debug control flags and hardware
+ *                      or software breakpoint descriptors in @dbg.
+ *                      May be NULL if the target does not require
+ *                      architecture-specific guest debug setup.
+ * @insert_sw_breakpoint: Optional callback to insert an architecture-specific
+ *                        software breakpoint instruction at @bp->pc and save
+ *                        the overwritten instruction in @bp->saved_insn.
+ *                        Returns 0 on success, or a negative errno on failure.
+ * @remove_sw_breakpoint: Optional callback to remove an architecture-specific
+ *                        software breakpoint, restoring @bp->saved_insn at
+ *                        @bp->pc.
+ *                        Returns 0 on success, or a negative errno on failure.
  */
 typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
@@ -83,6 +97,9 @@ typedef struct KVMCPUOps {
     MemTxAttrs (*post_run)(CPUState *cpu, struct kvm_run *run);
     int (*handle_exit)(CPUState *cpu, struct kvm_run *run);
     int (*process_async_events)(CPUState *cpu);
+    void (*update_guest_debug)(CPUState *cpu, struct kvm_guest_debug *dbg);
+    int (*insert_sw_breakpoint)(CPUState *cpu, struct kvm_sw_breakpoint *bp);
+    int (*remove_sw_breakpoint)(CPUState *cpu, struct kvm_sw_breakpoint *bp);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 2ecae10cdff..52b7a63a0b3 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -229,7 +229,7 @@ void kvm_irqchip_change_notify(void);
  * @reinject_trap: KVM trap injection control
  *
  * There are usually per-arch specifics which will be handled by
- * calling down to kvm_arch_update_guest_debug after the generic
+ * calling down to the KVMCPUOps::update_guest_debug callback after the generic
  * fields have been set.
  */
 #ifdef TARGET_KVM_HAVE_GUEST_DEBUG
@@ -394,18 +394,12 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
 
 int kvm_sw_breakpoints_active(CPUState *cpu);
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cpu,
-                                  struct kvm_sw_breakpoint *bp);
-int kvm_arch_remove_sw_breakpoint(CPUState *cpu,
-                                  struct kvm_sw_breakpoint *bp);
 int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
                                           GdbBreakpointType type);
 int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
                                           GdbBreakpointType type);
 void kvm_arch_remove_all_gdbstub_hw_breakpoints(void);
 
-void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg);
-
 bool kvm_arch_stop_on_emulation_error(CPUState *cpu);
 
 int kvm_vm_check_extension(KVMState *s, unsigned int extension);
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index f189bb92bb9..27eea1f65ff 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -43,6 +43,9 @@ void x86_kvm_pre_run(CPUState *cpu, struct kvm_run *run);
 MemTxAttrs x86_kvm_post_run(CPUState *cpu, struct kvm_run *run);
 int x86_kvm_handle_exit(CPUState *cs, struct kvm_run *run);
 int x86_kvm_process_async_events(CPUState *cs);
+void x86_kvm_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg);
+int x86_kvm_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp);
+int x86_kvm_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index f10d93a98df..24ded4b1804 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3866,6 +3866,7 @@ static void kvm_invoke_set_guest_debug(CPUState *cpu, run_on_cpu_data data)
 
 int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
 {
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     struct kvm_set_guest_debug_data data;
 
     data.dbg.control = reinject_trap;
@@ -3877,7 +3878,9 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
             data.dbg.control |= KVM_GUESTDBG_BLOCKIRQ;
         }
     }
-    kvm_arch_update_guest_debug(cpu, &data.dbg);
+    if (ops && ops->update_guest_debug) {
+        ops->update_guest_debug(cpu, &data.dbg);
+    }
 
     run_on_cpu(cpu, kvm_invoke_set_guest_debug,
                RUN_ON_CPU_HOST_PTR(&data));
@@ -3891,16 +3894,22 @@ int kvm_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
     int err;
 
     if (type == GDB_BREAKPOINT_SW) {
+        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+
         bp = kvm_find_sw_breakpoint(cpu, addr);
         if (bp) {
             bp->use_count++;
             return 0;
         }
 
+        if (!ops || !ops->insert_sw_breakpoint) {
+            return -ENOSYS;
+        }
+
         bp = g_new(struct kvm_sw_breakpoint, 1);
         bp->pc = addr;
         bp->use_count = 1;
-        err = kvm_arch_insert_sw_breakpoint(cpu, bp);
+        err = ops->insert_sw_breakpoint(cpu, bp);
         if (err) {
             g_free(bp);
             return err;
@@ -3930,6 +3939,8 @@ int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
     int err;
 
     if (type == GDB_BREAKPOINT_SW) {
+        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+
         bp = kvm_find_sw_breakpoint(cpu, addr);
         if (!bp) {
             return -ENOENT;
@@ -3940,7 +3951,11 @@ int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
             return 0;
         }
 
-        err = kvm_arch_remove_sw_breakpoint(cpu, bp);
+        if (!ops || !ops->remove_sw_breakpoint) {
+            return -ENOSYS;
+        }
+
+        err = ops->remove_sw_breakpoint(cpu, bp);
         if (err) {
             return err;
         }
@@ -3965,15 +3980,24 @@ int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
 
 void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu)
 {
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     struct kvm_sw_breakpoint *bp, *next;
     KVMState *s = cpu->kvm_state;
     CPUState *tmpcpu;
 
     QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
-        if (kvm_arch_remove_sw_breakpoint(cpu, bp) != 0) {
+        int ret = -ENOENT;
+
+        if (ops && ops->remove_sw_breakpoint) {
+            ret = ops->remove_sw_breakpoint(cpu, bp);
+        }
+        if (ret != 0) {
             /* Try harder to find a CPU that currently sees the breakpoint. */
             CPU_FOREACH(tmpcpu) {
-                if (kvm_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) {
+                const KVMCPUOps *tmpops = kvm_get_cpu_ops(tmpcpu);
+
+                if (tmpops && tmpops->remove_sw_breakpoint &&
+                    tmpops->remove_sw_breakpoint(tmpcpu, bp) == 0) {
                     break;
                 }
             }
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ad8166e0b41..a4f063f2efb 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1649,7 +1649,8 @@ static void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr)
     }
 }
 
-void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
+static void arm_kvm_update_guest_debug(CPUState *cs,
+                                       struct kvm_guest_debug *dbg)
 {
     if (kvm_sw_breakpoints_active(cs)) {
         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
@@ -2538,7 +2539,8 @@ void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
 /* C6.6.29 BRK instruction */
 static const uint32_t brk_insn = 0xd4200000;
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int arm_kvm_insert_sw_breakpoint(CPUState *cs,
+                                        struct kvm_sw_breakpoint *bp)
 {
     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
@@ -2547,7 +2549,8 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int arm_kvm_remove_sw_breakpoint(CPUState *cs,
+                                        struct kvm_sw_breakpoint *bp)
 {
     static uint32_t brk;
 
@@ -2652,6 +2655,9 @@ static const KVMCPUOps arm_kvm_cpu_ops = {
     .pre_run = arm_kvm_pre_run,
     .post_run = arm_kvm_post_run,
     .handle_exit = arm_kvm_handle_exit,
+    .update_guest_debug = arm_kvm_update_guest_debug,
+    .insert_sw_breakpoint = arm_kvm_insert_sw_breakpoint,
+    .remove_sw_breakpoint = arm_kvm_remove_sw_breakpoint,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 6990cd8d5c4..0cd0884be30 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -245,6 +245,9 @@ static const KVMCPUOps x86_kvm_cpu_ops = {
     .post_run = x86_kvm_post_run,
     .handle_exit = x86_kvm_handle_exit,
     .process_async_events = x86_kvm_process_async_events,
+    .update_guest_debug = x86_kvm_update_guest_debug,
+    .insert_sw_breakpoint = x86_kvm_insert_sw_breakpoint,
+    .remove_sw_breakpoint = x86_kvm_remove_sw_breakpoint,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index a3076d43b45..4ee7f53c2a8 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6128,7 +6128,7 @@ static int kvm_handle_tpr_access(X86CPU *cpu)
     return 1;
 }
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+int x86_kvm_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
     static const uint8_t int3 = 0xcc;
 
@@ -6139,7 +6139,7 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+int x86_kvm_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
 {
     uint8_t int3;
 
@@ -6292,7 +6292,7 @@ static int kvm_handle_debug(X86CPU *cpu,
     return ret;
 }
 
-void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+void x86_kvm_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
 {
     const uint8_t type_code[] = {
         [GDB_BREAKPOINT_HW] = 0x0,
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 97b6b448edf..0899aef552e 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1518,14 +1518,16 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs)
     return true;
 }
 
-void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+static void loongarch_kvm_update_guest_debug(CPUState *cpu,
+                                             struct kvm_guest_debug *dbg)
 {
     if (kvm_sw_breakpoints_active(cpu)) {
         dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
     }
 }
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int loongarch_kvm_insert_sw_breakpoint(CPUState *cs,
+                                              struct kvm_sw_breakpoint *bp)
 {
     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
         cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
@@ -1535,7 +1537,8 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int loongarch_kvm_remove_sw_breakpoint(CPUState *cs,
+                                              struct kvm_sw_breakpoint *bp)
 {
     static uint32_t brk;
 
@@ -1640,6 +1643,9 @@ static const KVMCPUOps loongarch_kvm_cpu_ops = {
     .put_registers = loongarch_kvm_put_registers,
     .handle_exit = loongarch_kvm_handle_exit,
     .process_async_events = loongarch_kvm_process_async_events,
+    .update_guest_debug = loongarch_kvm_update_guest_debug,
+    .insert_sw_breakpoint = loongarch_kvm_insert_sw_breakpoint,
+    .remove_sw_breakpoint = loongarch_kvm_remove_sw_breakpoint,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index ffc7a33bf17..4b2e42ef163 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1366,7 +1366,8 @@ static int kvmppc_handle_dcr_write(CPUPPCState *env,
     return 0;
 }
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int ppc_kvm_insert_sw_breakpoint(CPUState *cs,
+                                        struct kvm_sw_breakpoint *bp)
 {
     /* Mixed endian case is not handled */
     uint32_t sc = debug_inst_opcode;
@@ -1380,7 +1381,8 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int ppc_kvm_remove_sw_breakpoint(CPUState *cs,
+                                        struct kvm_sw_breakpoint *bp)
 {
     uint32_t sc;
 
@@ -1515,7 +1517,8 @@ void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
     nb_hw_breakpoint = nb_hw_watchpoint = 0;
 }
 
-void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
+static void ppc_kvm_update_guest_debug(CPUState *cs,
+                                       struct kvm_guest_debug *dbg)
 {
     int n;
 
@@ -3069,6 +3072,9 @@ static const KVMCPUOps ppc_kvm_cpu_ops = {
     .put_registers = ppc_kvm_put_registers,
     .handle_exit = ppc_kvm_handle_exit,
     .process_async_events = ppc_kvm_process_async_events,
+    .update_guest_debug = ppc_kvm_update_guest_debug,
+    .insert_sw_breakpoint = ppc_kvm_insert_sw_breakpoint,
+    .remove_sw_breakpoint = ppc_kvm_remove_sw_breakpoint,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index d9984828048..8a82160a7bf 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -2168,11 +2168,21 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
     kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
 }
 
+static int riscv_kvm_insert_sw_breakpoint(CPUState *cs,
+                                          struct kvm_sw_breakpoint *bp);
+static int riscv_kvm_remove_sw_breakpoint(CPUState *cs,
+                                          struct kvm_sw_breakpoint *bp);
+static void riscv_kvm_update_guest_debug(CPUState *cs,
+                                         struct kvm_guest_debug *dbg);
+
 static const KVMCPUOps riscv_kvm_cpu_ops = {
     .init_vcpu = riscv_kvm_init_vcpu,
     .get_registers = riscv_kvm_get_registers,
     .put_registers = riscv_kvm_put_registers,
     .handle_exit = riscv_kvm_handle_exit,
+    .update_guest_debug = riscv_kvm_update_guest_debug,
+    .insert_sw_breakpoint = riscv_kvm_insert_sw_breakpoint,
+    .remove_sw_breakpoint = riscv_kvm_remove_sw_breakpoint,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
@@ -2225,7 +2235,8 @@ DEFINE_TYPES(riscv_kvm_cpu_type_infos)
 static const uint32_t ebreak_insn = 0x00100073;
 static const uint16_t c_ebreak_insn = 0x9002;
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int riscv_kvm_insert_sw_breakpoint(CPUState *cs,
+                                          struct kvm_sw_breakpoint *bp)
 {
     if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 2, 0)) {
         return -EINVAL;
@@ -2245,7 +2256,8 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int riscv_kvm_remove_sw_breakpoint(CPUState *cs,
+                                          struct kvm_sw_breakpoint *bp)
 {
     uint32_t ebreak;
     uint16_t c_ebreak;
@@ -2286,7 +2298,8 @@ void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
     /* TODO; To be implemented later. */
 }
 
-void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
+static void riscv_kvm_update_guest_debug(CPUState *cs,
+                                         struct kvm_guest_debug *dbg)
 {
     if (kvm_sw_breakpoints_active(cs)) {
         dbg->control |= KVM_GUESTDBG_ENABLE;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 7400fe41f87..12695376442 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -825,7 +825,8 @@ static void determine_sw_breakpoint_instr(void)
         }
 }
 
-int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int s390x_kvm_insert_sw_breakpoint(CPUState *cs,
+                                          struct kvm_sw_breakpoint *bp)
 {
     determine_sw_breakpoint_instr();
 
@@ -837,7 +838,8 @@ int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
     return 0;
 }
 
-int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+static int s390x_kvm_remove_sw_breakpoint(CPUState *cs,
+                                          struct kvm_sw_breakpoint *bp)
 {
     uint8_t t[MAX_ILEN];
 
@@ -956,7 +958,8 @@ void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
     hw_breakpoints = NULL;
 }
 
-void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg)
+static void s390x_kvm_update_guest_debug(CPUState *cpu,
+                                         struct kvm_guest_debug *dbg)
 {
     int i;
 
@@ -2647,6 +2650,9 @@ static const KVMCPUOps s390x_kvm_cpu_ops = {
     .put_registers = s390x_kvm_put_registers,
     .handle_exit = s390x_kvm_handle_exit,
     .process_async_events = s390x_kvm_process_async_events,
+    .update_guest_debug = s390x_kvm_update_guest_debug,
+    .insert_sw_breakpoint = s390x_kvm_insert_sw_breakpoint,
+    .remove_sw_breakpoint = s390x_kvm_remove_sw_breakpoint,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 18/23] accel/kvm: port kvm_arch_[insert|remove]_hw_breakpoints to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (16 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 17/23] accel/kvm: port kvm_arch_update_guest_debug " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 19/23] accel/kvm: remove TARGET_KVM_HAVE_GUEST_DEBUG Alex Bennée
                   ` (5 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We are able to eliminate some NOP implementations with a default
fallback.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 15 +++++++++++++++
 include/system/kvm.h        |  6 ------
 target/i386/kvm/kvm_i386.h  |  5 +++++
 accel/kvm/kvm-all.c         | 18 ++++++++++++++----
 target/arm/kvm.c            | 13 ++++++++-----
 target/i386/kvm/kvm-cpu.c   |  3 +++
 target/i386/kvm/kvm.c       | 10 +++++-----
 target/loongarch/kvm/kvm.c  | 16 ----------------
 target/ppc/kvm.c            | 13 ++++++++-----
 target/riscv/kvm/kvm-cpu.c  | 19 -------------------
 target/s390x/kvm/kvm.c      |  9 ++++++---
 11 files changed, 64 insertions(+), 63 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index d2374e91cef..23a83eee6ed 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -85,6 +85,16 @@ struct kvm_run;
  *                        software breakpoint, restoring @bp->saved_insn at
  *                        @bp->pc.
  *                        Returns 0 on success, or a negative errno on failure.
+ * @insert_hw_breakpoint: Optional callback to insert an architecture-specific
+ *                        hardware breakpoint or watchpoint at address @addr
+ *                        with length @len and type @type.
+ *                        Returns 0 on success, or a negative errno on failure.
+ * @remove_hw_breakpoint: Optional callback to remove an architecture-specific
+ *                        hardware breakpoint or watchpoint at address @addr
+ *                        with length @len and type @type.
+ *                        Returns 0 on success, or a negative errno on failure.
+ * @remove_all_hw_breakpoints: Optional callback to remove all architecture-
+ *                             specific hardware breakpoints and watchpoints.
  */
 typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
@@ -100,6 +110,11 @@ typedef struct KVMCPUOps {
     void (*update_guest_debug)(CPUState *cpu, struct kvm_guest_debug *dbg);
     int (*insert_sw_breakpoint)(CPUState *cpu, struct kvm_sw_breakpoint *bp);
     int (*remove_sw_breakpoint)(CPUState *cpu, struct kvm_sw_breakpoint *bp);
+    int (*insert_hw_breakpoint)(CPUState *cpu, vaddr addr, vaddr len,
+                                GdbBreakpointType type);
+    int (*remove_hw_breakpoint)(CPUState *cpu, vaddr addr, vaddr len,
+                                GdbBreakpointType type);
+    void (*remove_all_hw_breakpoints)(CPUState *cpu);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 52b7a63a0b3..cfc0144d9a5 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -394,12 +394,6 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
 
 int kvm_sw_breakpoints_active(CPUState *cpu);
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type);
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type);
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void);
-
 bool kvm_arch_stop_on_emulation_error(CPUState *cpu);
 
 int kvm_vm_check_extension(KVMState *s, unsigned int extension);
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 27eea1f65ff..e2ae601100c 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -46,6 +46,11 @@ int x86_kvm_process_async_events(CPUState *cs);
 void x86_kvm_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg);
 int x86_kvm_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp);
 int x86_kvm_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp);
+int x86_kvm_insert_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                 GdbBreakpointType type);
+int x86_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                 GdbBreakpointType type);
+void x86_kvm_remove_all_hw_breakpoints(CPUState *cs);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 24ded4b1804..3bd61264a7e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3917,7 +3917,12 @@ int kvm_insert_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
 
         QTAILQ_INSERT_HEAD(&cpu->kvm_state->kvm_sw_breakpoints, bp, entry);
     } else {
-        err = kvm_arch_insert_gdbstub_hw_breakpoint(addr, len, type);
+        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+
+        if (!ops || !ops->insert_hw_breakpoint) {
+            return -ENOSYS;
+        }
+        err = ops->insert_hw_breakpoint(cpu, addr, len, type);
         if (err) {
             return err;
         }
@@ -3937,9 +3942,9 @@ int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
 {
     struct kvm_sw_breakpoint *bp;
     int err;
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
 
     if (type == GDB_BREAKPOINT_SW) {
-        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
 
         bp = kvm_find_sw_breakpoint(cpu, addr);
         if (!bp) {
@@ -3963,7 +3968,10 @@ int kvm_remove_gdbstub_breakpoint(CPUState *cpu, GdbBreakpointType type,
         QTAILQ_REMOVE(&cpu->kvm_state->kvm_sw_breakpoints, bp, entry);
         g_free(bp);
     } else {
-        err = kvm_arch_remove_gdbstub_hw_breakpoint(addr, len, type);
+        if (!ops || !ops->remove_hw_breakpoint) {
+            return -ENOSYS;
+        }
+        err = ops->remove_hw_breakpoint(cpu, addr, len, type);
         if (err) {
             return err;
         }
@@ -4005,7 +4013,9 @@ void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu)
         QTAILQ_REMOVE(&s->kvm_sw_breakpoints, bp, entry);
         g_free(bp);
     }
-    kvm_arch_remove_all_gdbstub_hw_breakpoints();
+    if (ops && ops->remove_all_hw_breakpoints) {
+        ops->remove_all_hw_breakpoints(cpu);
+    }
 
     CPU_FOREACH(cpu) {
         kvm_update_guest_debug(cpu, 0);
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index a4f063f2efb..5c0ccfc11cd 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1821,8 +1821,8 @@ void kvm_arch_accel_class_init(ObjectClass *oc)
         "Eager Page Split chunk size for hugepages. (default: 0, disabled)");
 }
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
+static int arm_kvm_insert_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                         GdbBreakpointType type)
 {
     switch (type) {
     case GDB_BREAKPOINT_HW:
@@ -1837,8 +1837,8 @@ int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     }
 }
 
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
+static int arm_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                         GdbBreakpointType type)
 {
     switch (type) {
     case GDB_BREAKPOINT_HW:
@@ -1852,7 +1852,7 @@ int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     }
 }
 
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
+static void arm_kvm_remove_all_hw_breakpoints(CPUState *cs)
 {
     if (cur_hw_wps > 0) {
         g_array_remove_range(hw_watchpoints, 0, cur_hw_wps);
@@ -2658,6 +2658,9 @@ static const KVMCPUOps arm_kvm_cpu_ops = {
     .update_guest_debug = arm_kvm_update_guest_debug,
     .insert_sw_breakpoint = arm_kvm_insert_sw_breakpoint,
     .remove_sw_breakpoint = arm_kvm_remove_sw_breakpoint,
+    .insert_hw_breakpoint = arm_kvm_insert_hw_breakpoint,
+    .remove_hw_breakpoint = arm_kvm_remove_hw_breakpoint,
+    .remove_all_hw_breakpoints = arm_kvm_remove_all_hw_breakpoints,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 0cd0884be30..baaee0c7e71 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -248,6 +248,9 @@ static const KVMCPUOps x86_kvm_cpu_ops = {
     .update_guest_debug = x86_kvm_update_guest_debug,
     .insert_sw_breakpoint = x86_kvm_insert_sw_breakpoint,
     .remove_sw_breakpoint = x86_kvm_remove_sw_breakpoint,
+    .insert_hw_breakpoint = x86_kvm_insert_hw_breakpoint,
+    .remove_hw_breakpoint = x86_kvm_remove_hw_breakpoint,
+    .remove_all_hw_breakpoints = x86_kvm_remove_all_hw_breakpoints,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 4ee7f53c2a8..78c06a07bd6 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6176,8 +6176,8 @@ static int find_hw_breakpoint(target_ulong addr, int len, GdbBreakpointType type
     return -1;
 }
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
+int x86_kvm_insert_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                 GdbBreakpointType type)
 {
     switch (type) {
     case GDB_BREAKPOINT_HW:
@@ -6217,8 +6217,8 @@ int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     return 0;
 }
 
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
+int x86_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                 GdbBreakpointType type)
 {
     int n;
 
@@ -6232,7 +6232,7 @@ int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     return 0;
 }
 
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
+void x86_kvm_remove_all_hw_breakpoints(CPUState *cs)
 {
     nb_hw_breakpoint = 0;
 }
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index 0899aef552e..b15f60bd2c3 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1551,22 +1551,6 @@ static int loongarch_kvm_remove_sw_breakpoint(CPUState *cs,
     return 0;
 }
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
-{
-    return -ENOSYS;
-}
-
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
-{
-    return -ENOSYS;
-}
-
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
-{
-}
-
 static bool kvm_loongarch_handle_debug(CPUState *cs, struct kvm_run *run)
 {
     LoongArchCPU *cpu = LOONGARCH_CPU(cs);
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 4b2e42ef163..548bf3e00ad 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -1438,8 +1438,8 @@ static int find_hw_watchpoint(target_ulong addr, int *flag)
     return -1;
 }
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
+static int ppc_kvm_insert_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                         GdbBreakpointType type)
 {
     const unsigned breakpoint_index = nb_hw_breakpoint + nb_hw_watchpoint;
     if (breakpoint_index >= ARRAY_SIZE(hw_debug_points)) {
@@ -1483,8 +1483,8 @@ int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     return 0;
 }
 
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
+static int ppc_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
+                                         GdbBreakpointType type)
 {
     int n;
 
@@ -1512,7 +1512,7 @@ int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     return 0;
 }
 
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
+static void ppc_kvm_remove_all_hw_breakpoints(CPUState *cs)
 {
     nb_hw_breakpoint = nb_hw_watchpoint = 0;
 }
@@ -3075,6 +3075,9 @@ static const KVMCPUOps ppc_kvm_cpu_ops = {
     .update_guest_debug = ppc_kvm_update_guest_debug,
     .insert_sw_breakpoint = ppc_kvm_insert_sw_breakpoint,
     .remove_sw_breakpoint = ppc_kvm_remove_sw_breakpoint,
+    .insert_hw_breakpoint = ppc_kvm_insert_hw_breakpoint,
+    .remove_hw_breakpoint = ppc_kvm_remove_hw_breakpoint,
+    .remove_all_hw_breakpoints = ppc_kvm_remove_all_hw_breakpoints,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index 8a82160a7bf..aeb049c0c71 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -2279,25 +2279,6 @@ static int riscv_kvm_remove_sw_breakpoint(CPUState *cs,
     return 0;
 }
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
-{
-    /* TODO; To be implemented later. */
-    return -EINVAL;
-}
-
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
-                                          GdbBreakpointType type)
-{
-    /* TODO; To be implemented later. */
-    return -EINVAL;
-}
-
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
-{
-    /* TODO; To be implemented later. */
-}
-
 static void riscv_kvm_update_guest_debug(CPUState *cs,
                                          struct kvm_guest_debug *dbg)
 {
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index 12695376442..ccdc85900ba 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -902,7 +902,7 @@ static int insert_hw_breakpoint(vaddr addr, int len, int type)
     return 0;
 }
 
-int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
+static int s390x_kvm_insert_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
                                           GdbBreakpointType type)
 {
     switch (type) {
@@ -921,7 +921,7 @@ int kvm_arch_insert_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     return insert_hw_breakpoint(addr, len, type);
 }
 
-int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
+static int s390x_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
                                           GdbBreakpointType type)
 {
     int size;
@@ -951,7 +951,7 @@ int kvm_arch_remove_gdbstub_hw_breakpoint(vaddr addr, vaddr len,
     return 0;
 }
 
-void kvm_arch_remove_all_gdbstub_hw_breakpoints(void)
+static void s390x_kvm_remove_all_hw_breakpoints(CPUState *cs)
 {
     nb_hw_breakpoints = 0;
     g_free(hw_breakpoints);
@@ -2653,6 +2653,9 @@ static const KVMCPUOps s390x_kvm_cpu_ops = {
     .update_guest_debug = s390x_kvm_update_guest_debug,
     .insert_sw_breakpoint = s390x_kvm_insert_sw_breakpoint,
     .remove_sw_breakpoint = s390x_kvm_remove_sw_breakpoint,
+    .insert_hw_breakpoint = s390x_kvm_insert_hw_breakpoint,
+    .remove_hw_breakpoint = s390x_kvm_remove_hw_breakpoint,
+    .remove_all_hw_breakpoints = s390x_kvm_remove_all_hw_breakpoints,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 19/23] accel/kvm: remove TARGET_KVM_HAVE_GUEST_DEBUG
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (17 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 18/23] accel/kvm: port kvm_arch_[insert|remove]_hw_breakpoints " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 20/23] accel/kvm: port kvm_arch_stop_on_emulation_error to KVMCPUOps Alex Bennée
                   ` (4 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

With guest debug and breakpoint handling now migrated to struct
KVMCPUOps, accel/kvm dispatches dynamically via ops. If an
architecture does not support guest debug or breakpoints, the
callbacks are simply NULL and common code handles this gracefully.

As a result we can drop TARGET_KVM_HAVE_GUEST_DEBUG. Remove it from
target configs and eliminate the #ifdef guards.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 configs/targets/aarch64-softmmu.mak     |  1 -
 configs/targets/i386-softmmu.mak        |  1 -
 configs/targets/loongarch64-softmmu.mak |  1 -
 configs/targets/ppc-softmmu.mak         |  1 -
 configs/targets/ppc64-softmmu.mak       |  1 -
 configs/targets/riscv64-softmmu.mak     |  1 -
 configs/targets/s390x-softmmu.mak       |  1 -
 configs/targets/x86_64-softmmu.mak      |  1 -
 include/system/kvm.h                    |  7 -------
 include/system/kvm_int.h                |  2 --
 accel/kvm/kvm-accel-ops.c               |  4 ----
 accel/kvm/kvm-all.c                     | 15 +++++----------
 12 files changed, 5 insertions(+), 31 deletions(-)

diff --git a/configs/targets/aarch64-softmmu.mak b/configs/targets/aarch64-softmmu.mak
index d34aead41c4..6f60ca6505c 100644
--- a/configs/targets/aarch64-softmmu.mak
+++ b/configs/targets/aarch64-softmmu.mak
@@ -1,6 +1,5 @@
 TARGET_ARCH=aarch64
 TARGET_BASE_ARCH=arm
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_XML_FILES= aarch64-core.xml aarch64-fpu.xml arm-core.xml arm-vfp.xml arm-vfp3.xml arm-vfp-sysregs.xml arm-neon.xml arm-m-profile.xml arm-m-profile-mve.xml aarch64-pauth.xml aarch64-sme2.xml
 # needed by boot.c
 TARGET_NEED_FDT=y
diff --git a/configs/targets/i386-softmmu.mak b/configs/targets/i386-softmmu.mak
index 38a8f85201f..2eef68dc55e 100644
--- a/configs/targets/i386-softmmu.mak
+++ b/configs/targets/i386-softmmu.mak
@@ -1,5 +1,4 @@
 TARGET_ARCH=i386
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_KVM_HAVE_RESET_PARKED_VCPU=y
 TARGET_XML_FILES= i386-32bit.xml
 TARGET_LONG_BITS=32
diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak
index a425b3dbaae..3b3a9021980 100644
--- a/configs/targets/loongarch64-softmmu.mak
+++ b/configs/targets/loongarch64-softmmu.mak
@@ -1,6 +1,5 @@
 TARGET_ARCH=loongarch64
 TARGET_BASE_ARCH=loongarch
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_XML_FILES= loongarch-base32.xml loongarch-base64.xml loongarch-fpu.xml loongarch-lsx.xml loongarch-lasx.xml
 # all boards require libfdt
 TARGET_NEED_FDT=y
diff --git a/configs/targets/ppc-softmmu.mak b/configs/targets/ppc-softmmu.mak
index 867898bd47c..c47887f8992 100644
--- a/configs/targets/ppc-softmmu.mak
+++ b/configs/targets/ppc-softmmu.mak
@@ -1,5 +1,4 @@
 TARGET_ARCH=ppc
 TARGET_BIG_ENDIAN=y
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_XML_FILES= power-core.xml power-fpu.xml power-altivec.xml power-spe.xml
 TARGET_LONG_BITS=32
diff --git a/configs/targets/ppc64-softmmu.mak b/configs/targets/ppc64-softmmu.mak
index 10d7a2681e7..8c6dc84b821 100644
--- a/configs/targets/ppc64-softmmu.mak
+++ b/configs/targets/ppc64-softmmu.mak
@@ -1,7 +1,6 @@
 TARGET_ARCH=ppc64
 TARGET_BASE_ARCH=ppc
 TARGET_BIG_ENDIAN=y
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_XML_FILES= power64-core.xml power-fpu.xml power-altivec.xml power-spe.xml power-vsx.xml
 # all boards require libfdt
 TARGET_NEED_FDT=y
diff --git a/configs/targets/riscv64-softmmu.mak b/configs/targets/riscv64-softmmu.mak
index a10dc03c04c..18b674230ab 100644
--- a/configs/targets/riscv64-softmmu.mak
+++ b/configs/targets/riscv64-softmmu.mak
@@ -1,6 +1,5 @@
 TARGET_ARCH=riscv64
 TARGET_BASE_ARCH=riscv
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_XML_FILES= riscv-64bit-cpu.xml riscv-32bit-fpu.xml riscv-64bit-fpu.xml riscv-64bit-virtual.xml riscv-32bit-cpu.xml riscv-32bit-virtual.xml
 # needed by boot.c
 TARGET_NEED_FDT=y
diff --git a/configs/targets/s390x-softmmu.mak b/configs/targets/s390x-softmmu.mak
index 478988e6d4a..6a629c6479e 100644
--- a/configs/targets/s390x-softmmu.mak
+++ b/configs/targets/s390x-softmmu.mak
@@ -1,6 +1,5 @@
 TARGET_ARCH=s390x
 TARGET_BIG_ENDIAN=y
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_XML_FILES= s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml s390-virt.xml s390-virt-kvm.xml s390-gs.xml
 TARGET_LONG_BITS=64
 TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
diff --git a/configs/targets/x86_64-softmmu.mak b/configs/targets/x86_64-softmmu.mak
index c7f8746b4f5..491173df466 100644
--- a/configs/targets/x86_64-softmmu.mak
+++ b/configs/targets/x86_64-softmmu.mak
@@ -1,6 +1,5 @@
 TARGET_ARCH=x86_64
 TARGET_BASE_ARCH=i386
-TARGET_KVM_HAVE_GUEST_DEBUG=y
 TARGET_KVM_HAVE_RESET_PARKED_VCPU=y
 TARGET_XML_FILES= i386-64bit.xml i386-64bit-apx.xml
 TARGET_LONG_BITS=64
diff --git a/include/system/kvm.h b/include/system/kvm.h
index cfc0144d9a5..1a52e7e5261 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -232,14 +232,7 @@ void kvm_irqchip_change_notify(void);
  * calling down to the KVMCPUOps::update_guest_debug callback after the generic
  * fields have been set.
  */
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
 int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap);
-#else
-static inline int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
-{
-    return -EINVAL;
-}
-#endif
 
 /* internal API */
 
diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h
index 0876aac938d..9d1d3fd3deb 100644
--- a/include/system/kvm_int.h
+++ b/include/system/kvm_int.h
@@ -113,9 +113,7 @@ struct KVMState
     struct kvm_coalesced_mmio_ring *coalesced_mmio_ring;
     bool coalesced_flush_in_progress;
     int vcpu_events;
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
     QTAILQ_HEAD(, kvm_sw_breakpoint) kvm_sw_breakpoints;
-#endif
     int max_nested_state_len;
     int kvm_shadow_mem;
     bool kernel_irqchip_allowed;
diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c
index 445d7d7f545..ab10de6ac30 100644
--- a/accel/kvm/kvm-accel-ops.c
+++ b/accel/kvm/kvm-accel-ops.c
@@ -86,12 +86,10 @@ static bool kvm_cpus_are_resettable(void)
     return !kvm_enabled() || !kvm_state->guest_state_protected;
 }
 
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
 static void kvm_update_guest_debug_ops(CPUState *cpu)
 {
     kvm_update_guest_debug(cpu, 0);
 }
-#endif
 
 static void kvm_accel_ops_class_init(ObjectClass *oc, const void *data)
 {
@@ -106,12 +104,10 @@ static void kvm_accel_ops_class_init(ObjectClass *oc, const void *data)
     ops->synchronize_pre_loadvm = kvm_cpu_synchronize_pre_loadvm;
     ops->handle_interrupt = generic_handle_interrupt;
 
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
     ops->update_guest_debug = kvm_update_guest_debug_ops;
     ops->insert_gdbstub_breakpoint = kvm_insert_gdbstub_breakpoint;
     ops->remove_gdbstub_breakpoint = kvm_remove_gdbstub_breakpoint;
     ops->remove_all_gdbstub_breakpoints = kvm_remove_all_gdbstub_breakpoints;
-#endif
 }
 
 static const TypeInfo kvm_accel_ops_type = {
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 3bd61264a7e..5b96fac513e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -2964,9 +2964,7 @@ static int kvm_init(AccelState *as, MachineState *ms)
     s->sigmask_len = 8;
     accel_blocker_init();
 
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
     QTAILQ_INIT(&s->kvm_sw_breakpoints);
-#endif
     QLIST_INIT(&s->kvm_parked_vcpus);
     s->fd = qemu_open_old(s->device ?: "/dev/kvm", O_RDWR);
     if (s->fd == -1) {
@@ -3077,7 +3075,6 @@ static int kvm_init(AccelState *as, MachineState *ms)
     kvm_vm_attributes_allowed =
         (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES) > 0);
 
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
     if (kvm_check_extension(s, KVM_CAP_SET_GUEST_DEBUG) > 0) {
         as->gdbstub.sstep_flags = SSTEP_ENABLE;
 
@@ -3088,7 +3085,6 @@ static int kvm_init(AccelState *as, MachineState *ms)
             as->gdbstub.sstep_flags |= SSTEP_NOIRQ;
         }
     }
-#endif
 
     kvm_state = s;
 
@@ -3832,7 +3828,6 @@ bool kvm_arm_supports_user_irq(void)
     return kvm_check_extension(kvm_state, KVM_CAP_ARM_USER_IRQ);
 }
 
-#ifdef TARGET_KVM_HAVE_GUEST_DEBUG
 struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu, vaddr pc)
 {
     struct kvm_sw_breakpoint *bp;
@@ -3869,6 +3864,10 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
     const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
     struct kvm_set_guest_debug_data data;
 
+    if (!ops || !ops->update_guest_debug) {
+        return -EINVAL;
+    }
+
     data.dbg.control = reinject_trap;
 
     if (cpu_single_stepping(cpu)) {
@@ -3878,9 +3877,7 @@ int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_trap)
             data.dbg.control |= KVM_GUESTDBG_BLOCKIRQ;
         }
     }
-    if (ops && ops->update_guest_debug) {
-        ops->update_guest_debug(cpu, &data.dbg);
-    }
+    ops->update_guest_debug(cpu, &data.dbg);
 
     run_on_cpu(cpu, kvm_invoke_set_guest_debug,
                RUN_ON_CPU_HOST_PTR(&data));
@@ -4022,8 +4019,6 @@ void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu)
     }
 }
 
-#endif /* !TARGET_KVM_HAVE_GUEST_DEBUG */
-
 static int kvm_set_signal_mask(CPUState *cpu, const sigset_t *sigset)
 {
     KVMState *s = kvm_state;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 20/23] accel/kvm: port kvm_arch_stop_on_emulation_error to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (18 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 19/23] accel/kvm: remove TARGET_KVM_HAVE_GUEST_DEBUG Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 21/23] accel/kvm: port kvm_arch_on_sigbus_vcpu " Alex Bennée
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Really only x86 is doing much complicated, everyone else defaults to
stop.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 7 +++++++
 include/system/kvm.h        | 2 --
 target/i386/kvm/kvm_i386.h  | 1 +
 accel/kvm/kvm-all.c         | 8 +++++++-
 target/arm/kvm.c            | 5 -----
 target/i386/kvm/kvm-cpu.c   | 1 +
 target/i386/kvm/kvm.c       | 2 +-
 target/loongarch/kvm/kvm.c  | 5 -----
 target/ppc/kvm.c            | 5 -----
 target/riscv/kvm/kvm-cpu.c  | 5 -----
 target/s390x/kvm/kvm.c      | 5 -----
 11 files changed, 17 insertions(+), 29 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index 23a83eee6ed..c2ae74f2b87 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -95,6 +95,12 @@ struct kvm_run;
  *                        Returns 0 on success, or a negative errno on failure.
  * @remove_all_hw_breakpoints: Optional callback to remove all architecture-
  *                             specific hardware breakpoints and watchpoints.
+ * @stop_on_emulation_error: Optional callback executed when KVM encounters an
+ *                           internal emulation failure (such as
+ *                           KVM_INTERNAL_ERROR_EMULATION) to decide whether
+ *                           execution should stop.
+ *                           Returns true to stop the VM, or false to dump state
+ *                           and continue. If NULL, defaults to true.
  */
 typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
@@ -115,6 +121,7 @@ typedef struct KVMCPUOps {
     int (*remove_hw_breakpoint)(CPUState *cpu, vaddr addr, vaddr len,
                                 GdbBreakpointType type);
     void (*remove_all_hw_breakpoints)(CPUState *cpu);
+    bool (*stop_on_emulation_error)(CPUState *cpu);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 1a52e7e5261..719ae1c71fb 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -387,8 +387,6 @@ struct kvm_sw_breakpoint *kvm_find_sw_breakpoint(CPUState *cpu,
 
 int kvm_sw_breakpoints_active(CPUState *cpu);
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cpu);
-
 int kvm_vm_check_extension(KVMState *s, unsigned int extension);
 
 #define kvm_vm_enable_cap(s, capability, cap_flags, ...)             \
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index e2ae601100c..9d4be604443 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -51,6 +51,7 @@ int x86_kvm_insert_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
 int x86_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
                                  GdbBreakpointType type);
 void x86_kvm_remove_all_hw_breakpoints(CPUState *cs);
+bool x86_kvm_stop_on_emulation_error(CPUState *cs);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 5b96fac513e..62ebb3458c8 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3183,8 +3183,14 @@ static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
                 i, (uint64_t)run->internal.data[i]);
     }
     if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
+        const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+        bool stop = true;
+
         fprintf(stderr, "emulation failure\n");
-        if (!kvm_arch_stop_on_emulation_error(cpu)) {
+        if (ops && ops->stop_on_emulation_error) {
+            stop = ops->stop_on_emulation_error(cpu);
+        }
+        if (!stop) {
             cpu_dump_state(cpu, stderr, CPU_DUMP_CODE);
             return EXCP_INTERRUPT;
         }
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index 5c0ccfc11cd..ed99699098c 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1609,11 +1609,6 @@ static int arm_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
     return ret;
 }
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cs)
-{
-    return true;
-}
-
 /**
  * kvm_arm_hw_debug_active:
  * @cpu: ARMCPU
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index baaee0c7e71..c9340183eaf 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -251,6 +251,7 @@ static const KVMCPUOps x86_kvm_cpu_ops = {
     .insert_hw_breakpoint = x86_kvm_insert_hw_breakpoint,
     .remove_hw_breakpoint = x86_kvm_remove_hw_breakpoint,
     .remove_all_hw_breakpoints = x86_kvm_remove_all_hw_breakpoints,
+    .stop_on_emulation_error = x86_kvm_stop_on_emulation_error,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 78c06a07bd6..e419af944cb 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -6661,7 +6661,7 @@ int x86_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
     return ret;
 }
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cs)
+bool x86_kvm_stop_on_emulation_error(CPUState *cs)
 {
     X86CPU *cpu = X86_CPU(cs);
     CPUX86State *env = &cpu->env;
diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c
index b15f60bd2c3..fd0f3a82a6b 100644
--- a/target/loongarch/kvm/kvm.c
+++ b/target/loongarch/kvm/kvm.c
@@ -1513,11 +1513,6 @@ static int loongarch_kvm_process_async_events(CPUState *cs)
     return cs->halted;
 }
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cs)
-{
-    return true;
-}
-
 static void loongarch_kvm_update_guest_debug(CPUState *cpu,
                                              struct kvm_guest_debug *dbg)
 {
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 548bf3e00ad..f5f2f82a4d8 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2840,11 +2840,6 @@ int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
     return 0;
 }
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
-{
-    return true;
-}
-
 void kvm_arch_init_irq_routing(KVMState *s)
 {
 }
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index aeb049c0c71..6a88fe761c0 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -1621,11 +1621,6 @@ int kvm_arch_irqchip_create(KVMState *s)
     return kvm_check_extension(s, KVM_CAP_DEVICE_CTRL);
 }
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cs)
-{
-    return true;
-}
-
 static void kvm_riscv_handle_sbi_dbcn(CPUState *cs, struct kvm_run *run)
 {
     const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c
index ccdc85900ba..e0373d05515 100644
--- a/target/s390x/kvm/kvm.c
+++ b/target/s390x/kvm/kvm.c
@@ -1935,11 +1935,6 @@ static int s390x_kvm_handle_exit(CPUState *cs, struct kvm_run *run)
     return ret;
 }
 
-bool kvm_arch_stop_on_emulation_error(CPUState *cpu)
-{
-    return true;
-}
-
 void kvm_s390_enable_css_support(S390CPU *cpu)
 {
     int r;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 21/23] accel/kvm: port kvm_arch_on_sigbus_vcpu to KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (19 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 20/23] accel/kvm: port kvm_arch_stop_on_emulation_error to KVMCPUOps Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 22/23] accel/kvm: cache KVMCPUOps Alex Bennée
                   ` (2 subsequent siblings)
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

This leaves hanging the question of if we should clean-up
KVM_HAVE_MCE_INJECTION? It is poisoned to avoid entering generic code.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 docs/specs/acpi_hest_ghes.rst |  3 ++-
 include/accel/kvm/cpu-ops.h   |  6 ++++++
 include/system/kvm.h          |  2 --
 target/i386/kvm/kvm_i386.h    |  1 +
 accel/kvm/kvm-all.c           | 19 ++++++++++++++++---
 target/arm/kvm.c              |  3 ++-
 target/i386/kvm/kvm-cpu.c     |  1 +
 target/i386/kvm/kvm.c         |  2 +-
 8 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/docs/specs/acpi_hest_ghes.rst b/docs/specs/acpi_hest_ghes.rst
index aaf7b1ad11a..dfb319dc3b4 100644
--- a/docs/specs/acpi_hest_ghes.rst
+++ b/docs/specs/acpi_hest_ghes.rst
@@ -114,5 +114,6 @@ Design Details
      kernel, on receiving notification, guest APEI driver could read the CPER error
      and take appropriate action.
 
-(11) kvm_arch_on_sigbus_vcpu() reports RAS errors via a SEA notifications,
+
+(11) The KVMCPUops::on_sigbus_vcpu callback reports RAS errors via a SEA notifications,
      when a SIGBUS event is triggered.
diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index c2ae74f2b87..d43bc845ad5 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -101,6 +101,11 @@ struct kvm_run;
  *                           execution should stop.
  *                           Returns true to stop the VM, or false to dump state
  *                           and continue. If NULL, defaults to true.
+ * @on_sigbus_vcpu: Optional callback executed when a SIGBUS signal is received
+ *                  to inject an architecture-specific hardware memory error
+ *                  (e.g. MCE on x86 or SEA on ARM) into the guest.
+ *                  May be NULL if the target does not support hardware error
+ *                  injection.
  */
 typedef struct KVMCPUOps {
     int (*pre_create_vcpu)(CPUState *cpu, Error **errp);
@@ -122,6 +127,7 @@ typedef struct KVMCPUOps {
                                 GdbBreakpointType type);
     void (*remove_all_hw_breakpoints)(CPUState *cpu);
     bool (*stop_on_emulation_error)(CPUState *cpu);
+    void (*on_sigbus_vcpu)(CPUState *cpu, int code, void *addr);
 } KVMCPUOps;
 
 #define TYPE_KVM_ACCEL_CPU "kvm-accel-cpu"
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 719ae1c71fb..98ef937eff1 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -352,8 +352,6 @@ bool kvm_vcpu_id_is_valid(int vcpu_id);
 /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */
 unsigned long kvm_vcpu_id(CPUState *cpu);
 
-void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
-
 void kvm_arch_init_irq_routing(KVMState *s);
 
 int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route,
diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h
index 9d4be604443..88aa0699c28 100644
--- a/target/i386/kvm/kvm_i386.h
+++ b/target/i386/kvm/kvm_i386.h
@@ -52,6 +52,7 @@ int x86_kvm_remove_hw_breakpoint(CPUState *cs, vaddr addr, vaddr len,
                                  GdbBreakpointType type);
 void x86_kvm_remove_all_hw_breakpoints(CPUState *cs);
 bool x86_kvm_stop_on_emulation_error(CPUState *cs);
+void x86_kvm_on_sigbus_vcpu(CPUState *c, int code, void *addr);
 void kvm_arch_after_reset_vcpu(X86CPU *cpu);
 void kvm_arch_do_init_vcpu(X86CPU *cs);
 uint32_t kvm_arch_get_supported_cpuid(KVMState *env, uint32_t function,
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 62ebb3458c8..5189cdc6a01 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -3535,8 +3535,10 @@ int kvm_cpu_exec(CPUState *cpu)
 #ifdef KVM_HAVE_MCE_INJECTION
         if (unlikely(have_sigbus_pending)) {
             bql_lock();
-            kvm_arch_on_sigbus_vcpu(cpu, pending_sigbus_code,
+            if (ops->on_sigbus_vcpu) {
+                ops->on_sigbus_vcpu(cpu, pending_sigbus_code,
                                     pending_sigbus_addr);
+            }
             have_sigbus_pending = false;
             bql_unlock();
         }
@@ -4080,6 +4082,11 @@ void kvm_init_cpu_signals(CPUState *cpu)
 int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
 {
 #ifdef KVM_HAVE_MCE_INJECTION
+    const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
+
+    if (!ops || !ops->on_sigbus_vcpu) {
+        return 1;
+    }
     if (have_sigbus_pending) {
         return 1;
     }
@@ -4097,13 +4104,19 @@ int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
 int kvm_on_sigbus(int code, void *addr)
 {
 #ifdef KVM_HAVE_MCE_INJECTION
+    const KVMCPUOps *ops;
+
     /* Action required MCE kills the process if SIGBUS is blocked.  Because
      * that's what happens in the I/O thread, where we handle MCE via signalfd,
      * we can only get action optional here.
      */
     assert(code != BUS_MCEERR_AR);
-    kvm_arch_on_sigbus_vcpu(first_cpu, code, addr);
-    return 0;
+    ops = kvm_get_cpu_ops(first_cpu);
+    if (ops && ops->on_sigbus_vcpu) {
+        ops->on_sigbus_vcpu(first_cpu, code, addr);
+        return 0;
+    }
+    return 1;
 #else
     return 1;
 #endif
diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index ed99699098c..563b331a7cf 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -2486,7 +2486,7 @@ static int arm_kvm_get_registers(CPUState *cs, Error **errp)
     return ret;
 }
 
-void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
+static void arm_kvm_on_sigbus_vcpu(CPUState *c, int code, void *addr)
 {
     ram_addr_t ram_addr;
     hwaddr paddr;
@@ -2656,6 +2656,7 @@ static const KVMCPUOps arm_kvm_cpu_ops = {
     .insert_hw_breakpoint = arm_kvm_insert_hw_breakpoint,
     .remove_hw_breakpoint = arm_kvm_remove_hw_breakpoint,
     .remove_all_hw_breakpoints = arm_kvm_remove_all_hw_breakpoints,
+    .on_sigbus_vcpu = arm_kvm_on_sigbus_vcpu,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index c9340183eaf..e876ec6b794 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -252,6 +252,7 @@ static const KVMCPUOps x86_kvm_cpu_ops = {
     .remove_hw_breakpoint = x86_kvm_remove_hw_breakpoint,
     .remove_all_hw_breakpoints = x86_kvm_remove_all_hw_breakpoints,
     .stop_on_emulation_error = x86_kvm_stop_on_emulation_error,
+    .on_sigbus_vcpu = x86_kvm_on_sigbus_vcpu,
 };
 
 static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data)
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index e419af944cb..26d30629272 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -767,7 +767,7 @@ static void hardware_memory_error(void *host_addr)
     exit(1);
 }
 
-void kvm_arch_on_sigbus_vcpu(CPUState *c, int code, void *addr)
+void x86_kvm_on_sigbus_vcpu(CPUState *c, int code, void *addr)
 {
     X86CPU *cpu = X86_CPU(c);
     CPUX86State *env = &cpu->env;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 22/23] accel/kvm: cache KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (20 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 21/23] accel/kvm: port kvm_arch_on_sigbus_vcpu " Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 10:43 ` [PATCH 23/23] accel/kvm: remove redundant ops checks for kvm_get_cpu_ops Alex Bennée
  2026-10-20 11:21 ` [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

Doing a QOM cast each time we need KVMCPUOps is overkill, especially
considering it is a single static assignment when we configure the
accelerator. Cache the value on kvm_init_vcpu and use it.

We also assert that anytime the system asks for KVMCPUOps it should be
at a point we can honour the request.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/accel/kvm/cpu-ops.h | 13 +++++++++----
 include/hw/core/cpu.h       |  3 +++
 accel/kvm/kvm-all.c         |  4 ++++
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/include/accel/kvm/cpu-ops.h b/include/accel/kvm/cpu-ops.h
index d43bc845ad5..075bac1d494 100644
--- a/include/accel/kvm/cpu-ops.h
+++ b/include/accel/kvm/cpu-ops.h
@@ -156,11 +156,16 @@ DECLARE_CLASS_CHECKERS(KVMAccelCPUClass, KVM_ACCEL_CPU, TYPE_KVM_ACCEL_CPU)
  */
 static inline const KVMCPUOps *kvm_get_cpu_ops(const CPUState *cpu)
 {
-    if (cpu->cc->accel_cpu) {
-        KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(cpu->cc->accel_cpu);
-        return kacc->cpu_ops;
+    if (cpu) {
+        if (cpu->kvm_cpu_ops) {
+            return cpu->kvm_cpu_ops;
+        }
+        if (cpu->cc->accel_cpu) {
+            KVMAccelCPUClass *kacc = KVM_ACCEL_CPU_CLASS(cpu->cc->accel_cpu);
+            return kacc->cpu_ops;
+        }
     }
-    return NULL;
+    g_assert_not_reached();
 }
 
 #endif /* ACCEL_KVM_CPU_OPS_H */
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 456154df6f6..1e164036286 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -473,6 +473,8 @@ struct qemu_work_item;
  *    ring is enabled.
  * @kvm_fetch_index: Keeps the index that we last fetched from the per-vCPU
  *    dirty ring structure.
+ * @kvm_cpu_ops: Cached pointer to the KVMCPUOps table to avoid QOM lookups
+ *    in the run loop.
  *
  * @neg_align: The CPUState is the common part of a concrete ArchCPU
  * which is allocated when an individual CPU instance is created. As
@@ -554,6 +556,7 @@ struct CPUState {
     uint32_t kvm_fetch_index;
     uint64_t dirty_pages;
     int kvm_vcpu_stats_fd;
+    const struct KVMCPUOps *kvm_cpu_ops;
 
     /* Use by accel-block: CPU is executing an ioctl() */
     QemuLockCnt in_ioctl_lock;
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 5189cdc6a01..041113ed9b5 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -746,6 +746,9 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
     KVMState *s = kvm_state;
     int ret;
 
+    assert(ops);
+    cpu->kvm_cpu_ops = ops;
+
     trace_kvm_init_vcpu(cpu->cpu_index, kvm_vcpu_id(cpu));
 
     if (ops->pre_create_vcpu) {
@@ -4111,6 +4114,7 @@ int kvm_on_sigbus(int code, void *addr)
      * we can only get action optional here.
      */
     assert(code != BUS_MCEERR_AR);
+    assert(first_cpu);
     ops = kvm_get_cpu_ops(first_cpu);
     if (ops && ops->on_sigbus_vcpu) {
         ops->on_sigbus_vcpu(first_cpu, code, addr);
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH 23/23] accel/kvm: remove redundant ops checks for kvm_get_cpu_ops
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (21 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 22/23] accel/kvm: cache KVMCPUOps Alex Bennée
@ 2026-10-20 10:43 ` Alex Bennée
  2026-10-20 11:21 ` [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 10:43 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv,
	Alex Bennée

We assert that we should always be able to retrieve KVMCPUOps on an
initialised system so remove the redundant checks.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 accel/kvm/kvm-all.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 041113ed9b5..8b719d6eb44 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -455,11 +455,7 @@ static void kvm_create_vcpu_internal(CPUState *cpu, KVMState *s, int kvm_fd)
 unsigned long kvm_vcpu_id(CPUState *cpu)
 {
     const KVMCPUOps *ops = kvm_get_cpu_ops(cpu);
-
-    if (ops && ops->vcpu_id) {
-        return ops->vcpu_id(cpu);
-    }
-    return cpu->cpu_index;
+    return ops->vcpu_id ? ops->vcpu_id(cpu) : cpu->cpu_index;
 }
 
 static int kvm_rebind_vcpus(Error **errp)
@@ -3190,7 +3186,7 @@ static int kvm_handle_internal_error(CPUState *cpu, struct kvm_run *run)
         bool stop = true;
 
         fprintf(stderr, "emulation failure\n");
-        if (ops && ops->stop_on_emulation_error) {
+        if (ops->stop_on_emulation_error) {
             stop = ops->stop_on_emulation_error(cpu);
         }
         if (!stop) {
@@ -4004,7 +4000,7 @@ void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu)
     QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
         int ret = -ENOENT;
 
-        if (ops && ops->remove_sw_breakpoint) {
+        if (ops->remove_sw_breakpoint) {
             ret = ops->remove_sw_breakpoint(cpu, bp);
         }
         if (ret != 0) {
@@ -4021,7 +4017,7 @@ void kvm_remove_all_gdbstub_breakpoints(CPUState *cpu)
         QTAILQ_REMOVE(&s->kvm_sw_breakpoints, bp, entry);
         g_free(bp);
     }
-    if (ops && ops->remove_all_hw_breakpoints) {
+    if (ops->remove_all_hw_breakpoints) {
         ops->remove_all_hw_breakpoints(cpu);
     }
 
@@ -4116,7 +4112,7 @@ int kvm_on_sigbus(int code, void *addr)
     assert(code != BUS_MCEERR_AR);
     assert(first_cpu);
     ops = kvm_get_cpu_ops(first_cpu);
-    if (ops && ops->on_sigbus_vcpu) {
+    if (ops->on_sigbus_vcpu) {
         ops->on_sigbus_vcpu(first_cpu, code, addr);
         return 0;
     }
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH 00/23] kvm: introduce KVMCPUOps
  2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
                   ` (22 preceding siblings ...)
  2026-10-20 10:43 ` [PATCH 23/23] accel/kvm: remove redundant ops checks for kvm_get_cpu_ops Alex Bennée
@ 2026-10-20 11:21 ` Alex Bennée
  23 siblings, 0 replies; 25+ messages in thread
From: Alex Bennée @ 2026-10-20 11:21 UTC (permalink / raw)
  To: qemu-devel
  Cc: Bibo Mao, Christian Borntraeger, Ilya Leoshkevich,
	Alistair Francis, Richard Henderson, Daniel Henrique Barboza,
	Paolo Bonzini, Eric Farman, Song Gao, Harsh Prateek Bora,
	David Hildenbrand, Bernhard Beschow, Halil Pasic, Nicholas Piggin,
	Paul Durrant, Björn Walk, Jiaxun Yang,
	Philippe Mathieu-Daudé, Palmer Dabbelt, qemu-s390x,
	David Woodhouse, Liu Zhiwei, qemu-ppc, Marcelo Tosatti, kvm,
	qemu-arm, linux-edac, Glenn Miles, Chao Liu, Cornelia Huck,
	Gautam Menghani, Xianglai Li, Pierrick Bouvier, Chinmay Rath,
	Michael S. Tsirkin, Matthew Rosato, Amit Machhiwal, Zhao Liu,
	Weiwei Li, Peter Maydell, Mauro Carvalho Chehab, qemu-riscv

Alex Bennée <alex.bennee@linaro.org> writes:

> There is a world coming where we can have a KVM interface which
> supports multiple architectures. The old style approach of using
> linking to resolve per arch kvm_arch_foo handlers won't scale and is
> also slightly antithetical to the flexible not-quite object orientated
> way we do things in QEMU.

In case it's not obvious I intended the prefix to be RFC as it needs
discussion ;-)

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2026-10-20 11:21 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20 10:42 [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée
2026-10-20 10:42 ` [PATCH 01/23] accel: introduce KVMAccelClass and KVMCPUOps Alex Bennée
2026-10-20 10:42 ` [PATCH 02/23] target/i386: wire up empty KVMAccelCPUClass Alex Bennée
2026-10-20 10:42 ` [PATCH 03/23] target/ppc: " Alex Bennée
2026-10-20 10:42 ` [PATCH 04/23] target/riscv: " Alex Bennée
2026-10-20 10:42 ` [PATCH 05/23] target/arm: " Alex Bennée
2026-10-20 10:43 ` [PATCH 06/23] target/s390x: " Alex Bennée
2026-10-20 10:43 ` [PATCH 07/23] target/loongarch: " Alex Bennée
2026-10-20 10:43 ` [PATCH 08/23] accel/kvm: port kvm_arch_pre_run to KVMCPUOps Alex Bennée
2026-10-20 10:43 ` [PATCH 09/23] accel/kvm: port kvm_arch_post_run " Alex Bennée
2026-10-20 10:43 ` [PATCH 10/23] accel/kvm: port kvm_arch_handle_exit " Alex Bennée
2026-10-20 10:43 ` [PATCH 11/23] accel/kvm: port kvm_arch_process_async_events " Alex Bennée
2026-10-20 10:43 ` [PATCH 12/23] accel/kvm: port kvm_arch_[put|get]_registers " Alex Bennée
2026-10-20 10:43 ` [PATCH 13/23] accel/kvm: port kvm_arch_pre_create_vcpu " Alex Bennée
2026-10-20 10:43 ` [PATCH 14/23] accel/kvm: port kvm_arch_init_vcpu " Alex Bennée
2026-10-20 10:43 ` [PATCH 15/23] accel/kvm: port kvm_arch_destroy_vcpu " Alex Bennée
2026-10-20 10:43 ` [PATCH 16/23] accel/kvm: port kvm_arch_vpcu_id " Alex Bennée
2026-10-20 10:43 ` [PATCH 17/23] accel/kvm: port kvm_arch_update_guest_debug " Alex Bennée
2026-10-20 10:43 ` [PATCH 18/23] accel/kvm: port kvm_arch_[insert|remove]_hw_breakpoints " Alex Bennée
2026-10-20 10:43 ` [PATCH 19/23] accel/kvm: remove TARGET_KVM_HAVE_GUEST_DEBUG Alex Bennée
2026-10-20 10:43 ` [PATCH 20/23] accel/kvm: port kvm_arch_stop_on_emulation_error to KVMCPUOps Alex Bennée
2026-10-20 10:43 ` [PATCH 21/23] accel/kvm: port kvm_arch_on_sigbus_vcpu " Alex Bennée
2026-10-20 10:43 ` [PATCH 22/23] accel/kvm: cache KVMCPUOps Alex Bennée
2026-10-20 10:43 ` [PATCH 23/23] accel/kvm: remove redundant ops checks for kvm_get_cpu_ops Alex Bennée
2026-10-20 11:21 ` [PATCH 00/23] kvm: introduce KVMCPUOps Alex Bennée

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox