From: "Jörg Rödel" <joro@8bytes.org>
To: Paolo Bonzini <pbonzini@redhat.com>,
Richard Henderson <richard.henderson@linaro.org>
Cc: philmd@linaro.org, marcel.apfelbaum@gmail.com,
zhao1.liu@intel.com, berrange@redhat.com, mst@redhat.com,
cohuck@redhat.com, mtosatti@redhat.com,
Tom Lendacky <thomas.lendacky@amd.com>,
qemu-devel@nongnu.org, kvm@vger.kernel.org,
coconut-svsm@lists.linux.dev, joerg.roedel@amd.com
Subject: [RFC PATCH 03/10] accel/kvm: Extend CPUState to handle Planes
Date: Mon, 8 Jun 2026 17:21:02 +0200 [thread overview]
Message-ID: <20260608152109.356783-4-joro@8bytes.org> (raw)
In-Reply-To: <20260608152109.356783-1-joro@8bytes.org>
From: Joerg Roedel <joerg.roedel@amd.com>
Extend the KVM specific part of the CPUState data structure to handle
the FDs for multiple planes.
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
accel/kvm/kvm-all.c | 121 +++++++++++++++++++++++++++++++--------
accel/kvm/trace-events | 1 +
include/hw/core/cpu.h | 17 +++++-
include/system/kvm.h | 4 ++
include/system/kvm_int.h | 8 +++
5 files changed, 126 insertions(+), 25 deletions(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 1a2f8e0f417c..7429e2be8ba9 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -133,6 +133,7 @@ static NotifierWithReturnList register_vcpufd_changed_notifiers =
static int map_kvm_run(KVMState *s, CPUState *cpu, Error **errp);
static int map_kvm_dirty_gfns(KVMState *s, CPUState *cpu, Error **errp);
static int vcpu_unmap_regions(KVMState *s, CPUState *cpu);
+static void kvm_alloc_vcpu_plane(CPUState *cpu, unsigned plane_id, int kvm_fd);
struct KVMResampleFd {
int gsi;
@@ -429,10 +430,16 @@ err:
static void kvm_create_vcpu_internal(CPUState *cpu, KVMState *s, int kvm_fd)
{
- cpu->kvm_fd = kvm_fd;
+ if (cpu->kvm_plane_state[0] == NULL) {
+ kvm_alloc_vcpu_plane(cpu, 0, kvm_fd);
+ } else {
+ cpu_kvm_plane(cpu, 0)->kvm_fd = kvm_fd;
+ }
+
+ cpu->kvm_plane = 0;
cpu->kvm_state = s;
if (!s->guest_state_protected) {
- cpu->vcpu_dirty = true;
+ cpu_kvm_plane(cpu, 0)->vcpu_dirty = true;
}
cpu->dirty_pages = 0;
cpu->throttle_us_per_full = 0;
@@ -450,8 +457,8 @@ static int kvm_rebind_vcpus(Error **errp)
CPU_FOREACH(cpu) {
vcpu_id = kvm_arch_vcpu_id(cpu);
- if (cpu->kvm_fd) {
- close(cpu->kvm_fd);
+ if (cpu_kvm_plane(cpu, 0)->kvm_fd) {
+ close(cpu_kvm_plane(cpu, 0)->kvm_fd);
}
ret = kvm_arch_destroy_vcpu(cpu);
@@ -501,8 +508,9 @@ static int kvm_rebind_vcpus(Error **errp)
vcpu_id);
}
- close(cpu->kvm_vcpu_stats_fd);
- cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
+ close(cpu_kvm_plane(cpu, 0)->kvm_vcpu_stats_fd);
+ cpu_kvm_plane(cpu, 0)->kvm_vcpu_stats_fd =
+ kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
kvm_init_cpu_signals(cpu);
}
trace_kvm_rebind_vcpus();
@@ -519,7 +527,7 @@ static void kvm_park_vcpu(CPUState *cpu)
vcpu = g_malloc0(sizeof(*vcpu));
vcpu->vcpu_id = kvm_arch_vcpu_id(cpu);
- vcpu->kvm_fd = cpu->kvm_fd;
+ vcpu->kvm_fd = cpu_kvm_plane(cpu, 0)->kvm_fd;
QLIST_INSERT_HEAD(&kvm_state->kvm_parked_vcpus, vcpu, node);
}
@@ -551,6 +559,34 @@ static void kvm_reset_parked_vcpus(KVMState *s)
}
}
+static void kvm_alloc_vcpu_plane(CPUState *cpu, unsigned plane_id, int kvm_fd)
+{
+ struct KVMPlane *p = NULL;
+
+ if (cpu->kvm_plane_state[plane_id] != NULL) {
+ return;
+ }
+
+ p = g_malloc0(sizeof(struct KVMPlane));
+ p->kvm_fd = kvm_fd;
+
+ cpu->kvm_plane_state[plane_id] = p;
+}
+
+void kvm_create_vcpu_plane(CPUState *cpu, unsigned plane_id, int kvm_fd)
+{
+ int vcpu_fd = cpu_kvm_plane(cpu, 0)->kvm_fd;
+ int plane_fd = kvm_vm_plane_ioctl(cpu->kvm_state, plane_id, KVM_CREATE_VCPU, vcpu_fd);
+
+ if (plane_fd < 0) {
+ fprintf(stderr, "Failed to create plane vcpu\n");
+ abort();
+ }
+
+ kvm_alloc_vcpu_plane(cpu, plane_id, plane_fd);
+}
+
+
/**
* kvm_create_vcpu - Gets a parked KVM vCPU or creates a KVM vCPU
* @cpu: QOM CPUState object for which KVM vCPU has to be fetched/created.
@@ -676,7 +712,7 @@ static int map_kvm_run(KVMState *s, CPUState *cpu, Error **errp)
}
cpu->kvm_run = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
- cpu->kvm_fd, 0);
+ cpu_kvm_plane(cpu, 0)->kvm_fd, 0);
if (cpu->kvm_run == MAP_FAILED) {
ret = -errno;
error_setg_errno(errp, ret,
@@ -700,7 +736,7 @@ static int map_kvm_dirty_gfns(KVMState *s, CPUState *cpu, Error **errp)
/* Use MAP_SHARED to share pages with the kernel */
cpu->kvm_dirty_gfns = mmap(NULL, s->kvm_dirty_ring_bytes,
PROT_READ | PROT_WRITE, MAP_SHARED,
- cpu->kvm_fd,
+ cpu_kvm_plane(cpu, 0)->kvm_fd,
PAGE_SIZE * KVM_DIRTY_LOG_PAGE_OFFSET);
if (cpu->kvm_dirty_gfns == MAP_FAILED) {
ret = -errno;
@@ -747,7 +783,7 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp)
"kvm_init_vcpu: kvm_arch_init_vcpu failed (%lu)",
kvm_arch_vcpu_id(cpu));
}
- cpu->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
+ cpu_kvm_plane(cpu, 0)->kvm_vcpu_stats_fd = kvm_vcpu_ioctl(cpu, KVM_GET_STATS_FD, NULL);
err:
return ret;
@@ -762,11 +798,17 @@ void kvm_close(void)
}
CPU_FOREACH(cpu) {
+ unsigned plane_id = KVM_MAX_PLANES;
cpu_remove_sync(cpu);
- close(cpu->kvm_fd);
- cpu->kvm_fd = -1;
- close(cpu->kvm_vcpu_stats_fd);
- cpu->kvm_vcpu_stats_fd = -1;
+ do {
+ struct KVMPlane *plane;
+ plane_id--;
+ plane = cpu_kvm_plane(cpu, plane_id);
+ close(plane->kvm_fd);
+ plane->kvm_fd = -1;
+ close(plane->kvm_vcpu_stats_fd);
+ plane->kvm_vcpu_stats_fd = -1;
+ } while (plane_id != 0);
}
if (kvm_state && kvm_state->fd != -1) {
@@ -3238,7 +3280,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) {
+ KVMPlane *plane = cpu_active_kvm_plane(cpu);
+
+ if (!plane->vcpu_dirty && !kvm_state->guest_state_protected) {
Error *err = NULL;
int ret = kvm_arch_get_registers(cpu, &err);
if (ret) {
@@ -3252,13 +3296,15 @@ static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg)
vm_stop(RUN_STATE_INTERNAL_ERROR);
}
- cpu->vcpu_dirty = true;
+ plane->vcpu_dirty = true;
}
}
void kvm_cpu_synchronize_state(CPUState *cpu)
{
- if (!cpu->vcpu_dirty && !kvm_state->guest_state_protected) {
+ KVMPlane *plane = cpu_active_kvm_plane(cpu);
+
+ if (!plane->vcpu_dirty && !kvm_state->guest_state_protected) {
run_on_cpu(cpu, do_kvm_cpu_synchronize_state, RUN_ON_CPU_NULL);
}
}
@@ -3278,7 +3324,7 @@ static bool kvm_cpu_synchronize_put(CPUState *cpu, KvmPutState state,
return false;
}
- cpu->vcpu_dirty = false;
+ cpu_active_kvm_plane(cpu)->vcpu_dirty = false;
return true;
}
@@ -3320,7 +3366,7 @@ void kvm_cpu_synchronize_post_init(CPUState *cpu)
static void do_kvm_cpu_synchronize_pre_loadvm(CPUState *cpu, run_on_cpu_data arg)
{
- cpu->vcpu_dirty = true;
+ cpu_active_kvm_plane(cpu)->vcpu_dirty = true;
}
void kvm_cpu_synchronize_pre_loadvm(CPUState *cpu)
@@ -3478,6 +3524,7 @@ out_unref:
int kvm_cpu_exec(CPUState *cpu)
{
+ KVMPlane *plane = cpu_active_kvm_plane(cpu);
struct kvm_run *run = cpu->kvm_run;
int ret, run_ret;
@@ -3493,7 +3540,7 @@ int kvm_cpu_exec(CPUState *cpu)
do {
MemTxAttrs attrs;
- if (cpu->vcpu_dirty) {
+ if (plane->vcpu_dirty) {
if (!kvm_cpu_synchronize_put(cpu, KVM_PUT_RUNTIME_STATE,
"at runtime")) {
ret = -1;
@@ -3725,8 +3772,36 @@ int kvm_vm_plane_ioctl(KVMState *s, unsigned plane_id, unsigned long type, ...)
return __vm_plane_ioctl(s, plane_id, type, arg);
}
+static inline int __vcpu_plane_ioctl(KVMPlane *plane, unsigned long type, void *arg)
+{
+ return ioctl(plane->kvm_fd, type, arg);
+}
+
+int kvm_vcpu_plane_ioctl(CPUState *cpu, unsigned plane_id, unsigned long type, ...)
+{
+ KVMPlane *plane = cpu_kvm_plane(cpu, plane_id);
+ int ret;
+ void *arg;
+ va_list ap;
+
+ va_start(ap, type);
+ arg = va_arg(ap, void *);
+ va_end(ap);
+
+ trace_kvm_vcpu_plane_ioctl(cpu->cpu_index, plane_id, type, arg);
+ accel_cpu_ioctl_begin(cpu);
+ ret = __vcpu_plane_ioctl(plane, type, arg);
+ accel_cpu_ioctl_end(cpu);
+ if (ret == -1) {
+ ret = -errno;
+ }
+ return ret;
+}
+
int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...)
{
+ /* Most VCPU IOCTLs (including KVM_RUN) must happen on the Plane-0 FD */
+ KVMPlane *plane = cpu_kvm_plane(cpu, 0);
int ret;
void *arg;
va_list ap;
@@ -3737,7 +3812,7 @@ int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...)
trace_kvm_vcpu_ioctl(cpu->cpu_index, type, arg);
accel_cpu_ioctl_begin(cpu);
- ret = ioctl(cpu->kvm_fd, type, arg);
+ ret = __vcpu_plane_ioctl(plane, type, arg);
accel_cpu_ioctl_end(cpu);
if (ret == -1) {
ret = -errno;
@@ -4731,7 +4806,7 @@ static void query_stats_schema(StatsSchemaList **result, StatsTarget target,
static void query_stats_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args)
{
- int stats_fd = cpu->kvm_vcpu_stats_fd;
+ int stats_fd = cpu_active_kvm_plane(cpu)->kvm_vcpu_stats_fd;
Error *local_err = NULL;
if (stats_fd == -1) {
@@ -4746,7 +4821,7 @@ static void query_stats_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args)
static void query_stats_schema_vcpu(CPUState *cpu, StatsArgs *kvm_stats_args)
{
- int stats_fd = cpu->kvm_vcpu_stats_fd;
+ int stats_fd = cpu_active_kvm_plane(cpu)->kvm_vcpu_stats_fd;
Error *local_err = NULL;
if (stats_fd == -1) {
diff --git a/accel/kvm/trace-events b/accel/kvm/trace-events
index 2f3bd9ba7052..1ca7be8a4b3b 100644
--- a/accel/kvm/trace-events
+++ b/accel/kvm/trace-events
@@ -5,6 +5,7 @@ kvm_ioctl(unsigned long type, void *arg) "type 0x%lx, arg %p"
kvm_vm_ioctl(unsigned long type, void *arg) "type 0x%lx, arg %p"
kvm_vm_plane_ioctl(unsigned long type, unsigned id, void *arg) "type 0x%lx, plane_id %d arg %p"
kvm_vcpu_ioctl(int cpu_index, unsigned long type, void *arg) "cpu_index %d, type 0x%lx, arg %p"
+kvm_vcpu_plane_ioctl(int cpu_index, unsigned plane_id, unsigned long type, void *arg) "cpu_index %d, plane_id %u type 0x%lx, arg %p"
kvm_run_exit(int cpu_index, uint32_t reason) "cpu_index %d, reason %d"
kvm_device_ioctl(int fd, unsigned long type, void *arg) "dev fd %d, type 0x%lx, arg %p"
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 04e1f970caf2..4025db67e13b 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -36,6 +36,7 @@
#include "qemu/lockcnt.h"
#include "qemu/thread.h"
#include "qom/object.h"
+#include "linux/kvm.h"
typedef int (*WriteCoreDumpFunction)(const void *buf, size_t size,
void *opaque);
@@ -545,13 +546,15 @@ struct CPUState {
uintptr_t mem_io_pc;
/* Only used in KVM */
- int kvm_fd;
struct KVMState *kvm_state;
struct kvm_run *kvm_run;
struct kvm_dirty_gfn *kvm_dirty_gfns;
uint32_t kvm_fetch_index;
uint64_t dirty_pages;
- int kvm_vcpu_stats_fd;
+
+ /* KVM plane state */
+ unsigned kvm_plane; /* Current active plane */
+ struct KVMPlane *kvm_plane_state[KVM_MAX_PLANES]; /* Per-Plane state */
/* Use by accel-block: CPU is executing an ioctl() */
QemuLockCnt in_ioctl_lock;
@@ -596,6 +599,16 @@ struct CPUState {
CPUNegativeOffsetState neg;
};
+static inline struct KVMPlane *cpu_kvm_plane(CPUState *s, unsigned plane_id)
+{
+ return s->kvm_plane_state[plane_id];
+}
+
+static inline struct KVMPlane *cpu_active_kvm_plane(CPUState *s)
+{
+ return s->kvm_plane_state[s->kvm_plane];
+}
+
/* Validate placement of CPUNegativeOffsetState. */
QEMU_BUILD_BUG_ON(offsetof(CPUState, neg) !=
sizeof(CPUState) - sizeof(CPUNegativeOffsetState));
diff --git a/include/system/kvm.h b/include/system/kvm.h
index 885ed35b061a..16597333cfa5 100644
--- a/include/system/kvm.h
+++ b/include/system/kvm.h
@@ -172,10 +172,12 @@ typedef struct KVMCapabilityInfo {
#define KVM_CAP_INFO(CAP) { "KVM_CAP_" stringify(CAP), KVM_CAP_##CAP }
#define KVM_CAP_LAST_INFO { NULL, 0 }
+struct KVMPlane;
struct KVMState;
#define TYPE_KVM_ACCEL ACCEL_CLASS_NAME("kvm")
typedef struct KVMState KVMState;
+typedef struct KVMPlane KVMPlane;
DECLARE_INSTANCE_CHECKER(KVMState, KVM_STATE,
TYPE_KVM_ACCEL)
@@ -219,6 +221,7 @@ int kvm_vm_ioctl(KVMState *s, unsigned long type, ...);
int kvm_vm_plane_ioctl(KVMState *s, unsigned plane_id, unsigned long type, ...);
int kvm_get_or_create_plane_fd(KVMState *s, unsigned id);
+void kvm_create_vcpu_plane(CPUState *cpu, unsigned plane, int kvm_fd);
void kvm_flush_coalesced_mmio_buffer(void);
@@ -251,6 +254,7 @@ static inline int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_t
int kvm_ioctl(KVMState *s, unsigned long type, ...);
+int kvm_vcpu_plane_ioctl(CPUState *cpu, unsigned plane_id, unsigned long type, ...);
int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...);
/**
diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h
index bfac331949f9..70b381f1ba05 100644
--- a/include/system/kvm_int.h
+++ b/include/system/kvm_int.h
@@ -101,6 +101,14 @@ struct KVMDirtyRingReaper {
volatile uint64_t reaper_iteration; /* iteration number of reaper thr */
volatile enum KVMDirtyRingReaperState reaper_state; /* reap thr state */
};
+
+/* VCPU per-plane state */
+struct KVMPlane {
+ int kvm_fd;
+ int kvm_vcpu_stats_fd;
+ bool vcpu_dirty;
+};
+
struct KVMState
{
AccelState parent_obj;
--
2.53.0
next prev parent reply other threads:[~2026-06-08 15:21 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-08 15:20 [RFC PATCH 00/10] QEMU Support for KVM Planes Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 01/10] Update Linux Header for KVM Planes Support Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 02/10] accel/kvm: Extend KVMState to carry fds for planes Jörg Rödel
2026-06-08 15:21 ` Jörg Rödel [this message]
2026-06-08 15:21 ` [RFC PATCH 04/10] accel: Add nr_planes() op Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 05/10] accel/kvm: Support nr_planes call-back Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 06/10] accel/kvm: Handle KVM_PLANE_EVENT_CREATE_CPU event Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 07/10] hw/core/machine: Add device-plane property Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 08/10] qdev: Add plane property Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 09/10] MSI: Inject into correct plane Jörg Rödel
2026-06-08 15:21 ` [RFC PATCH 10/10] KVM: Set GSI routes for default plane Jörg Rödel
2026-06-08 15:40 ` [RFC PATCH 00/10] QEMU Support for KVM Planes Daniel P. Berrangé
2026-06-08 15:45 ` Jörg Rödel
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260608152109.356783-4-joro@8bytes.org \
--to=joro@8bytes.org \
--cc=berrange@redhat.com \
--cc=coconut-svsm@lists.linux.dev \
--cc=cohuck@redhat.com \
--cc=joerg.roedel@amd.com \
--cc=kvm@vger.kernel.org \
--cc=marcel.apfelbaum@gmail.com \
--cc=mst@redhat.com \
--cc=mtosatti@redhat.com \
--cc=pbonzini@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=thomas.lendacky@amd.com \
--cc=zhao1.liu@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox