From: Amit Machhiwal <amachhiw@linux.ibm.com>
To: qemu-ppc@nongnu.org, Harsh Prateek Bora <harshpb@linux.ibm.com>
Cc: Amit Machhiwal <amachhiw@linux.ibm.com>,
Vaibhav Jain <vaibhav@linux.ibm.com>,
Nicholas Piggin <npiggin@gmail.com>,
Chinmay Rath <rathc@linux.ibm.com>,
Glenn Miles <milesg@linux.ibm.com>,
Paolo Bonzini <pbonzini@redhat.com>,
kvm@vger.kernel.org, qemu-devel@nongnu.org,
Gautam Menghani <gautam@linux.ibm.com>
Subject: [PATCH v5 2/3] target/ppc/kvm: Add support for querying host compatibility mode
Date: Tue, 4 Aug 2026 23:59:13 +0530 [thread overview]
Message-ID: <20260804182914.83091-3-amachhiw@linux.ibm.com> (raw)
In-Reply-To: <20260804182914.83091-1-amachhiw@linux.ibm.com>
Add infrastructure to query the host CPU compatibility mode via the
KVM_PPC_GET_COMPAT_CAPS ioctl. This allows QEMU to determine if the
host is running in a compatibility mode (e.g., a Power11 processor
operating in Power10 compatibility mode).
The kvmppc_get_compat_caps() function issues the ioctl and returns the
compat_capabilities bitmap. The kvm_ppc_host_compat_pvr() function derives
the effective PVR from the bitmap using ctz64() to find the lowest set
bit (highest supported compat level in IBM MSB-0 numbering).
The struct kvm_ppc_compat_caps places 'size' first and userspace sets it
to sizeof(struct kvm_ppc_compat_caps) before calling the ioctl. The kernel
uses copy_struct_from/to_user() to handle forward and backward ABI
compatibility: an older userspace with a smaller struct gets trailing fields
zero-padded. When newer userspace passes a larger struct to an older kernel
(usize > ksize), the kernel unconditionally returns -E2BIG and writes its
own ksize back into host_compat.size. QEMU detects this, validates the
returned size against KVM_PPC_COMPAT_CAPS_SIZE_VER0, and retries with that
size.
Additionally, cas_check_pvr() in hw/ppc/spapr_hcall.c is updated to
prevent fallback to raw mode when the host is running in compatibility
mode. This ensures that nested guests cannot exceed the host's
compatibility level. The call is guarded with kvm_enabled() since
kvm_ppc_host_compat_pvr() invokes kvm_vm_ioctl() which dereferences
kvm_state; without the guard, a TCG guest on a CONFIG_KVM=y binary
would segfault.
If the capability is not supported or the query fails, the functions
return 0, allowing fallback to existing behavior.
Tested-by: Gautam Menghani <gautam@linux.ibm.com>
Reviewed-by: Gautam Menghani <gautam@linux.ibm.com>
Signed-off-by: Amit Machhiwal <amachhiw@linux.ibm.com>
---
No changes in this version.
hw/ppc/spapr_hcall.c | 14 +++++++++
target/ppc/kvm.c | 75 ++++++++++++++++++++++++++++++++++++++++++++
target/ppc/kvm_ppc.h | 7 +++++
3 files changed, 96 insertions(+)
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 23bcd788daf6..708902934cff 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -1136,6 +1136,7 @@ static uint32_t cas_check_pvr(PowerPCCPU *cpu, uint32_t max_compat,
{
bool explicit_match = false; /* Matched the CPU's real PVR */
uint32_t best_compat = 0;
+ uint32_t compat_host_pvr = 0;
int i;
/*
@@ -1163,6 +1164,19 @@ static uint32_t cas_check_pvr(PowerPCCPU *cpu, uint32_t max_compat,
}
}
+ if (explicit_match && kvm_enabled()) {
+ compat_host_pvr = kvm_ppc_host_compat_pvr();
+ /*
+ * If the host is booted in a compatibility mode, do not try booting in
+ * the raw mode as it may allow KVM guests to boot with a higher CPU
+ * version compared to what host was booted with; which should not be
+ * allowed.
+ */
+ if (compat_host_pvr) {
+ explicit_match = false;
+ }
+ }
+
*raw_mode_supported = explicit_match;
/* Parsing finished */
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 116b39a00f4e..d4c5601a00c4 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2602,6 +2602,81 @@ bool kvmppc_supports_ail_3(void)
return cap_ail_mode_3;
}
+#if defined(TARGET_PPC64)
+static target_ulong kvmppc_get_compat_caps(void)
+{
+ struct kvm_ppc_compat_caps host_compat;
+ int ret;
+
+ if (!kvm_check_extension(kvm_state, KVM_CAP_PPC_COMPAT_CAPS)) {
+ return 0;
+ }
+
+ /*
+ * Set size to sizeof(struct kvm_ppc_compat_caps) so the kernel applies
+ * copy_struct_from/to_user() versioning. size must be >= VER0.
+ */
+ memset(&host_compat, 0, sizeof(host_compat));
+ host_compat.size = sizeof(host_compat);
+
+ ret = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_COMPAT_CAPS, &host_compat);
+ if (ret == -E2BIG && host_compat.size >= KVM_PPC_COMPAT_CAPS_SIZE_VER0) {
+ /*
+ * Kernel is older and knows only a smaller struct version. It
+ * wrote back its ksize into host_compat.size. Retry with that
+ * size so the kernel accepts the call.
+ *
+ * When a VER1 struct is introduced, add a check here:
+ * if (host_compat.size >= KVM_PPC_COMPAT_CAPS_SIZE_VER1) { ... }
+ */
+ uint64_t ksize = host_compat.size;
+ memset(&host_compat, 0, sizeof(host_compat));
+ host_compat.size = ksize;
+ ret = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_COMPAT_CAPS, &host_compat);
+ }
+
+ if (ret < 0) {
+ error_report("KVM: failed to get host CPU compat capabilities: %s",
+ strerror(-ret));
+ return 0;
+ }
+
+ return host_compat.compat_capabilities & KVM_PPC_COMPAT_BITMASK;
+}
+
+/*
+ * Return the effective host PVR based on the CPU compatibility mode
+ * reported by KVM. Returns 0 if no compat mode is active or the
+ * capability is not supported, in which case the caller falls back
+ * to the raw hardware PVR.
+ */
+uint32_t kvm_ppc_host_compat_pvr(void)
+{
+ uint32_t compat_host_pvr = 0;
+ uint64_t cap_idx = 0;
+ target_ulong host_caps = kvmppc_get_compat_caps();
+
+ if (host_caps) {
+ cap_idx = 1ULL << ctz64(host_caps);
+ switch (cap_idx) {
+ case KVM_PPC_COMPAT_CAP_POWER9:
+ compat_host_pvr = CPU_POWERPC_POWER9_DD22;
+ break;
+ case KVM_PPC_COMPAT_CAP_POWER10:
+ compat_host_pvr = CPU_POWERPC_POWER10_DD20;
+ break;
+ case KVM_PPC_COMPAT_CAP_POWER11:
+ compat_host_pvr = CPU_POWERPC_POWER11_DD20;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return compat_host_pvr;
+}
+#endif /* TARGET_PPC64 */
+
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
{
uint32_t host_pvr = mfpvr();
diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h
index 742881231e16..195dbaac5e17 100644
--- a/target/ppc/kvm_ppc.h
+++ b/target/ppc/kvm_ppc.h
@@ -81,6 +81,8 @@ bool kvmppc_supports_ail_3(void);
int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
+
+uint32_t kvm_ppc_host_compat_pvr(void);
void kvmppc_check_papr_resize_hpt(Error **errp);
int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift);
int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift);
@@ -440,6 +442,11 @@ static inline PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
return NULL;
}
+static inline uint32_t kvm_ppc_host_compat_pvr(void)
+{
+ return 0;
+}
+
static inline void kvmppc_check_papr_resize_hpt(Error **errp)
{
}
--
2.50.1 (Apple Git-155)
next prev parent reply other threads:[~2026-08-04 18:29 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 18:29 [PATCH v5 0/3] ppc/kvm: Handle CPU compatibility mode correctly for nested guests Amit Machhiwal
2026-08-04 18:29 ` [PATCH v5 1/3] [DO_NOT_MERGE] linux-headers: Add uapi header changes Amit Machhiwal
2026-08-04 18:29 ` Amit Machhiwal [this message]
2026-08-04 18:29 ` [PATCH v5 3/3] target/ppc/kvm: Use host compatibility mode for nested guests Amit Machhiwal
2026-08-04 19:55 ` BALATON Zoltan
2026-08-05 14:33 ` Amit Machhiwal
2026-08-05 8:25 ` [PATCH v5 0/3] ppc/kvm: Handle CPU compatibility mode correctly " Anushree Mathur
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=20260804182914.83091-3-amachhiw@linux.ibm.com \
--to=amachhiw@linux.ibm.com \
--cc=gautam@linux.ibm.com \
--cc=harshpb@linux.ibm.com \
--cc=kvm@vger.kernel.org \
--cc=milesg@linux.ibm.com \
--cc=npiggin@gmail.com \
--cc=pbonzini@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu-ppc@nongnu.org \
--cc=rathc@linux.ibm.com \
--cc=vaibhav@linux.ibm.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