* [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests
@ 2026-08-04 18:07 Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl Amit Machhiwal
` (5 more replies)
0 siblings, 6 replies; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-04 18:07 UTC (permalink / raw)
To: linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Amit Machhiwal, Anushree Mathur, Paolo Bonzini,
Nicholas Piggin, Michael Ellerman, Christophe Leroy (CS GROUP),
Jonathan Corbet, Shuah Khan, Ritesh Harjani, kvm, linux-kernel,
linux-doc
On POWER systems, newer processor generations can operate in compatibility
modes corresponding to earlier generations (e.g., a Power11 system running
in Power10 compatibility mode). In such cases, the effective CPU level
exposed to guests differs from the physical processor generation.
This creates a problem for nested virtualization. When booting a nested KVM
guest (L2) inside a host KVM guest (L1) running in a compatibility mode,
userspace (e.g., QEMU) may derive the CPU model from the raw hardware PVR
and attempt to configure the nested guest accordingly. However, the L1
partition is constrained by the compatibility level negotiated with the
hypervisor (L0), and requests exceeding that level are rejected, leading to
guest boot failures such as:
KVM-NESTEDv2: couldn't set guest wide elements
This series provides a mechanism for userspace to query the effective CPU
compatibility modes supported by the host, so it can select an appropriate
CPU model for nested guests.
To achieve this, the series introduces a new KVM capability and ioctl
(KVM_CAP_PPC_COMPAT_CAPS / KVM_PPC_GET_COMPAT_CAPS) that expose the
compatibility modes supported by the host.
Why a new UAPI?
===============
While cpu-version is available in /proc/device-tree/cpus/<cpu#>/cpu-version
on both L1 booted on PowerNV and PowerVM LPARs, the UAPI approach is
preferable for several reasons:
1. pHYP (L0) capabilities: On PowerVM, we need to rely on capabilities
negotiated with pHYP in KVM, not just device tree properties. The
cpu-version property depicts the current compat mode but doesn't point
to what all compat modes are supported for the nested guest.
2. procfs dependency: Not all systems run with procfs enabled (CONFIG_PROC_FS
is optional). Minimal configurations like buildroot might disable it, but
KVM ioctl works regardless since it accesses kernel data structures
directly.
3. Kernel validation: The kernel validates and normalizes the compatibility
information, ensuring userspace gets validated, consistent data.
4. Abstraction & stability: /proc/device-tree is an implementation detail.
The UAPI provides a stable interface that won't break if the underlying
mechanism changes.
5. Semantic clarity: KVM_PPC_GET_COMPAT_CAPS clearly expresses what
compatibility modes can be used for KVM guests, vs. parsing device tree
which requires understanding the semantic meaning of cpu-version.
The implementation supports both:
- KVM on PowerVM (nested API v2), where compatibility information is
served from the cached nested_capabilities value, originally obtained
via the H_GUEST_GET_CAPABILITIES hypercall at module init.
- KVM on PowerNV (nested API v1), where compatibility is derived from the
device tree ("cpu-version") representing the effective processor
compatibility level.
This allows userspace (e.g., QEMU) to select a CPU model consistent with
the host compatibility mode, avoiding mismatches and enabling successful
nested guest boot.
Note: This series is built on top of patch [1] which must be applied first.
Patch [1] ensures arch_compat is validated against the host compatibility
mode before this series adds the capability query mechanism.
Commit e4de1b9cb3b5 ("powerpc/dt_cpu_ftrs: Set CPU_FTR_P11_PVR for Power11
and later processors") which was also a prerequisite has been merged upstream.
Changes in v6:
- Changed KVM_PPC_GET_COMPAT_CAPS ioctl number from 0xe4 to 0xb8 to
avoid placing it in the KVM_CREATE_DEVICE fd ioctl range (0xe0-0xe3);
relocated definition to sit alongside other PPC vm ioctls (patch 1)
- [Gautam]
- kvmppc_map_compat_capabilities(): changed parameter type from
'const __be32' to 'u32' to fix Sparse type annotation warning (patch 3)
- [Sashiko]
- kvmppc_get_compat_caps(): replaced of_get_property() + be32_to_cpup()
with of_property_read_u32() for implicit length validation and cleaner
endianness handling (patch 3) - [Sashiko]
- Documentation: corrected :Parameters: from (out) to (in/out) since
userspace must set size and flags before calling (patch 4) - [Sashiko]
Patch summary:
[1/4] Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
[2/4] Implement capability retrieval for KVM on PowerVM (API v2)
[3/4] Add KVM on PowerNV support (API v1)
[4/4] Document the new ioctl
Testing (with QEMU v4 patches and on top of patch [1]):
KVM APIv1 Testing
=================
On P10 PowerNV machine (L0)
---------------------------
- P10 L1 KVM guest -> works
- P10 nested L2 KVM guest -> works
- P9 compat nested L2 KVM guest -> works
- P9 compat L1 KVM guest -> works
- P9 nested L2 KVM guest -> works
On Powernv11 TCG Guest (L0)
---------------------------
- P11 PowerNV TCG L0 guest -> works
- P11 L1 KVM guest -> works
- P11 L2 KVM guest -> works
- P10 compat L1 KVM guest -> works
- P10 L2 KVM guest -> works
- P9 compat L1 KVM guest -> works
- P9 L2 KVM guest -> works
KVM APIv2 Testing
=================
On P11 PowerVM LPAR (L1)
------------------------
- P11 L2 KVM guest -> works
- P10 compat L2 KVM guest -> works
- P9 compat L2 KVM guest fails to boot as expected
- Without QEMU patches but Linux patches
- P11 L2 KVM guest -> works
- P10 compat L2 KVM guest -> works
- P9 compat L2 KVM guest fails to boot as expected
- Without Linux patches but QEMU patches
- P11 L2 KVM guest -> works
- P10 compat L2 KVM guest -> works
On P11 LPAR in P10 compat (L1)
------------------------------
- P10 (host compat) L2 KVM guest -> works
- Without QEMU patch but Linux patches
- P10 guest fails to boot as expected (error: kvm run failed Invalid argument)
- Without Linux patch but QEMU patches
- P10 guest fails to boot as expected (KVM: unknown exit, hardware reason ffffffffffffffea)
On P10 PowerVM LPAR (L1)
------------------------
- P10 L2 KVM guest -> works
- P9 compat L2 KVM guest fails to boot as expected
TCG pSeries Guest
=================
- P11 (default) pSeries guest boots fine
ABI Extensibility Testing (struct size 32, extra member)
=========================================================
- Newer struct on QEMU, older kernel -> works (kernel returns -E2BIG,
QEMU retries with correct size)
- New struct on Linux kernel, older QEMU -> works (kernel zero-pads
trailing fields, QEMU gets correct data)
With this series, nested guests boot successfully in configurations where
they previously failed due to compatibility mismatches.
Related QEMU series:
====================
A corresponding QEMU v5 series will be sent soon.
Previous QEMU versions:
v4: https://lore.kernel.org/all/20260701052341.62289-1-amachhiw@linux.ibm.com/
v3: https://lore.kernel.org/all/20260616113915.25589-1-amachhiw@linux.ibm.com/
v2: https://lore.kernel.org/all/20260502140021.69712-1-amachhiw@linux.ibm.com/
v1: https://lore.kernel.org/all/20260430061333.37905-1-amachhiw@linux.ibm.com/
Previous versions:
==================
v5: https://lore.kernel.org/linuxppc-dev/20260701051409.51820-1-amachhiw@linux.ibm.com/
v4: https://lore.kernel.org/linuxppc-dev/20260616123314.82721-1-amachhiw@linux.ibm.com/
v3: https://lore.kernel.org/linuxppc-dev/20260522152744.55251-1-amachhiw@linux.ibm.com/
v2: https://lore.kernel.org/linuxppc-dev/20260513100755.83195-1-amachhiw@linux.ibm.com/
v1: https://lore.kernel.org/linuxppc-dev/20260430054906.94431-1-amachhiw@linux.ibm.com/
References:
===========
[1] https://lore.kernel.org/all/20260714175432.86388-1-amachhiw@linux.ibm.com/
Amit Machhiwal (4):
KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM
on PowerVM
KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM
on PowerNV
KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
Documentation/virt/kvm/api.rst | 79 +++++++++++++++++++++++++++++
arch/powerpc/include/asm/kvm_ppc.h | 1 +
arch/powerpc/include/uapi/asm/kvm.h | 18 +++++++
arch/powerpc/kvm/book3s_hv.c | 56 ++++++++++++++++++++
arch/powerpc/kvm/powerpc.c | 71 ++++++++++++++++++++++++++
include/uapi/linux/kvm.h | 3 ++
6 files changed, 228 insertions(+)
base-commit: 848acc8ffe1b7cd5f1bf427b93069becfebc2c9d
prerequisite-patch-id: 7755786f0e4f415e47065ff1972765008727fe10
--
2.50.1 (Apple Git-155)
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
@ 2026-08-04 18:07 ` Amit Machhiwal
2026-08-04 18:19 ` sashiko-bot
2026-08-04 18:07 ` [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM Amit Machhiwal
` (4 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-04 18:07 UTC (permalink / raw)
To: linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Amit Machhiwal, Anushree Mathur, Paolo Bonzini,
Nicholas Piggin, Michael Ellerman, Christophe Leroy (CS GROUP),
Jonathan Corbet, Shuah Khan, Ritesh Harjani, kvm, linux-kernel,
linux-doc, Gautam Menghani
Introduce a new capability and ioctl to expose CPU compatibility modes
supported by the host processor for nested guests.
On IBM POWER systems, newer processor generations (N) can operate in
compatibility modes corresponding to earlier generations, like (N-1) and
(N-2). This is particularly relevant for nested virtualization, where
nested KVM guests may need to run with a specific processor compatibility
level.
Introduce KVM_CAP_PPC_COMPAT_CAPS capability and the corresponding
KVM_PPC_GET_COMPAT_CAPS vm ioctl. The ioctl returns a bitmap describing
the compatibility modes supported by the host in respective bit numbers,
allowing userspace (e.g., QEMU) to select an appropriate compatibility
level when configuring nested KVM guests.
The ioctl handling is added in kvm_arch_vm_ioctl() and retrieves host
CPU compatibility capabilities via a PowerPC-specific backend
implementation when available.
The struct kvm_ppc_compat_caps places the 'size' field first so it can
be read alone via get_user() before copy_struct_from_user() is called,
avoiding pointer arithmetic to locate the size field.
The ioctl is defined using _IO so the ioctl number remains stable even if
the struct grows in future versions. It uses copy_struct_from_user() and
copy_struct_to_user() to provide forward- and backward-compatible
extensibility: older userspace passing a smaller struct to a newer kernel
gets zero-padded trailing fields, while newer userspace passing a larger
struct to an older kernel (usize > ksize) gets sizeof(struct
kvm_ppc_compat_caps)written back to host_caps.size so it can retry with the
older kernel-supported size, after which the kernel returns -E2BIG.
KVM_PPC_COMPAT_CAPS_SIZE_VER0 is defined as a frozen integer constant
(24) marking the size of the initial struct version, used as the
minimum floor for size field validation, similar to other versioned
struct interfaces in the kernel.
The 'flags' field is reserved for future use. The kernel rejects any
call where flags is non-zero with -EINVAL, preventing garbage values
from being baked into ABI permanently.
The ioctl returns appropriate error codes: EINVAL for an invalid size
or non-zero reserved fields, E2BIG if new userspace provides a larger
struct than the kernel knows about (with ksize written back into
host_caps.size for the retry), EFAULT for failed copy operations, and
ENOTTY if the backend doesn't implement get_compat_caps.
Suggested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
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>
---
Changes in this version:
- Changed ioctl number from 0xe4 to 0xb8 to avoid the KVM_CREATE_DEVICE
fd ioctl range (0xe0-0xe3); relocated definition alongside other PPC
vm ioctls
arch/powerpc/include/asm/kvm_ppc.h | 1 +
arch/powerpc/include/uapi/asm/kvm.h | 8 ++++
arch/powerpc/kvm/powerpc.c | 71 +++++++++++++++++++++++++++++
include/uapi/linux/kvm.h | 3 ++
4 files changed, 83 insertions(+)
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 0953f2daa466..169ea6a7fbad 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -319,6 +319,7 @@ struct kvmppc_ops {
bool (*hash_v3_possible)(void);
int (*create_vm_debugfs)(struct kvm *kvm);
int (*create_vcpu_debugfs)(struct kvm_vcpu *vcpu, struct dentry *debugfs_dentry);
+ int (*get_compat_caps)(struct kvm_ppc_compat_caps *host_caps);
};
extern struct kvmppc_ops *kvmppc_hv_ops;
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 077c5437f521..19e53d5ae540 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -437,6 +437,14 @@ struct kvm_ppc_cpu_char {
__u64 behaviour_mask; /* valid bits in behaviour */
};
+/* For KVM_PPC_GET_COMPAT_CAPS */
+struct kvm_ppc_compat_caps {
+ __u64 size; /* Size of this structure */
+ __u64 flags; /* Reserved for future use */
+ __u64 compat_capabilities; /* Capabilities supported by the host */
+};
+#define KVM_PPC_COMPAT_CAPS_SIZE_VER0 24 /* sizeof first published struct */
+
/*
* Values for character and character_mask.
* These are identical to the values used by H_GET_CPU_CHARACTERISTICS.
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index b6b83fe3233f..732336092b03 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -703,6 +703,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
}
}
break;
+#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
+ case KVM_CAP_PPC_COMPAT_CAPS:
+ r = 0;
+ if (kvmhv_on_pseries())
+ r = 1;
+ break;
+#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
default:
r = 0;
break;
@@ -2469,6 +2476,70 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
r = kvm->arch.kvm_ops->svm_off(kvm);
break;
}
+ case KVM_PPC_GET_COMPAT_CAPS: {
+ struct kvm_ppc_compat_caps host_caps = {};
+ u64 usize;
+
+ /*
+ * Read the size field first to drive copy_struct_from_user.
+ * size must be the first field of the struct.
+ */
+ r = -EFAULT;
+ if (get_user(usize, (__u64 __user *)argp))
+ goto out;
+
+ /*
+ * Enforce a minimum: reject buffers smaller than the initial
+ * struct version (VER0). This allows old userspace compiled
+ * against the original struct to still work on a newer kernel
+ * that has grown the struct with appended fields.
+ */
+ r = -EINVAL;
+ if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0)
+ goto out;
+
+ /*
+ * New userspace with a larger struct called an older kernel.
+ * Write back ksize in host_caps.size so userspace knows which
+ * older struct to retry with, then fail with -E2BIG.
+ */
+ if (usize > sizeof(host_caps)) {
+ host_caps.size = sizeof(host_caps);
+ r = -EFAULT;
+ if (put_user(host_caps.size, (__u64 __user *)argp))
+ goto out;
+ r = -E2BIG;
+ goto out;
+ }
+
+ /*
+ * copy_struct_from_user() handles forward/backward compat:
+ * usize == ksize: verbatim copy
+ * usize < ksize: zero-pad trailing (old userspace, new kernel)
+ */
+ r = copy_struct_from_user(&host_caps, sizeof(host_caps),
+ argp, usize);
+ if (r)
+ goto out;
+
+ /* Reserved fields must be zero */
+ r = -EINVAL;
+ if (host_caps.flags)
+ goto out;
+
+ r = -ENOTTY;
+ if (!kvm->arch.kvm_ops->get_compat_caps)
+ goto out;
+
+ r = kvm->arch.kvm_ops->get_compat_caps(&host_caps);
+ if (r)
+ goto out;
+
+ host_caps.size = sizeof(host_caps);
+ r = copy_struct_to_user(argp, usize, &host_caps,
+ sizeof(host_caps), NULL);
+ break;
+ }
default: {
struct kvm *kvm = filp->private_data;
r = kvm->arch.kvm_ops->arch_vm_ioctl(filp, ioctl, arg);
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 419011097fa8..70e36e6a0ad4 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -997,6 +997,7 @@ struct kvm_enable_cap {
#define KVM_CAP_S390_KEYOP 247
#define KVM_CAP_S390_VSIE_ESAMODE 248
#define KVM_CAP_S390_HPAGE_2G 249
+#define KVM_CAP_PPC_COMPAT_CAPS 250
struct kvm_irq_routing_irqchip {
__u32 irqchip;
@@ -1341,6 +1342,8 @@ struct kvm_s390_keyop {
/* Available with KVM_CAP_COUNTER_OFFSET */
#define KVM_ARM_SET_COUNTER_OFFSET _IOW(KVMIO, 0xb5, struct kvm_arm_counter_offset)
#define KVM_ARM_GET_REG_WRITABLE_MASKS _IOR(KVMIO, 0xb6, struct reg_mask_range)
+/* Available with KVM_CAP_PPC_COMPAT_CAPS */
+#define KVM_PPC_GET_COMPAT_CAPS _IO(KVMIO, 0xb8)
/* ioctl for vm fd */
#define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl Amit Machhiwal
@ 2026-08-04 18:07 ` Amit Machhiwal
2026-08-04 18:21 ` sashiko-bot
2026-08-04 18:07 ` [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV Amit Machhiwal
` (3 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-04 18:07 UTC (permalink / raw)
To: linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Amit Machhiwal, Anushree Mathur, Paolo Bonzini,
Nicholas Piggin, Michael Ellerman, Christophe Leroy (CS GROUP),
Jonathan Corbet, Shuah Khan, Ritesh Harjani, kvm, linux-kernel,
linux-doc, Gautam Menghani
On POWER systems, the host CPU may run in a compatibility mode (e.g., a
Power11 processor operating in Power10 compatibility mode). In such
cases, the effective CPU level exposed to guests differs from the
physical processor generation.
When running nested KVM guests, QEMU derives the host CPU type using
mfpvr(), which reflects the physical processor version. This can result
in a mismatch between the CPU model selected by QEMU and the
compatibility mode enforced by the host, leading to guest boot failures.
For example, booting a nested guest on a Power11 LPAR configured in
Power10 compatibility mode fails with:
KVM-NESTEDv2: couldn't set guest wide elements
[..KVM reg dump..]
This occurs because QEMU selects a CPU model corresponding to the
physical processor (via mfpvr()), while the host operates in a lower
compatibility mode. As a result, KVM rejects the requested compatibility
level during guest initialization.
On pseries nestedv2 systems, add support for retrieving host CPU
compatibility capabilities for nested guests on PowerVM. The capability
bitmap reflects the processor modes negotiated between the Power
hypervisor (L0) and the host partition (L1) via the
H_GUEST_GET_CAPABILITIES hcall, but is retrieved from the cached
nested_capabilities value populated during module initialization,
avoiding repeated hypervisor calls. A WARN_ON_ONCE() flags the
unexpected case where nested_capabilities is zero on a nestedv2 system.
The implementation defines KVM-specific capability constants
(KVM_PPC_COMPAT_CAP_POWER9/10/11), masks unsupported bits, and exposes
the result through the KVM_PPC_GET_COMPAT_CAPS ioctl.
Hook the implementation into the Book3S HV kvmppc_ops so that it can be
invoked by the generic KVM ioctl handling code.
Suggested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
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>
---
arch/powerpc/include/uapi/asm/kvm.h | 10 ++++++++++
arch/powerpc/kvm/book3s_hv.c | 20 ++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/arch/powerpc/include/uapi/asm/kvm.h b/arch/powerpc/include/uapi/asm/kvm.h
index 19e53d5ae540..913a64b901a3 100644
--- a/arch/powerpc/include/uapi/asm/kvm.h
+++ b/arch/powerpc/include/uapi/asm/kvm.h
@@ -445,6 +445,16 @@ struct kvm_ppc_compat_caps {
};
#define KVM_PPC_COMPAT_CAPS_SIZE_VER0 24 /* sizeof first published struct */
+/*
+ * Capability bits for compat_capabilities field in kvm_ppc_compat_caps.
+ * These bits indicate which processor compatibility modes are supported.
+ */
+#define KVM_PPC_COMPAT_CAP_POWER9 (1ULL << 62)
+#define KVM_PPC_COMPAT_CAP_POWER10 (1ULL << 61)
+#define KVM_PPC_COMPAT_CAP_POWER11 (1ULL << 60)
+#define KVM_PPC_COMPAT_BITMASK (KVM_PPC_COMPAT_CAP_POWER9 | \
+ KVM_PPC_COMPAT_CAP_POWER10 | \
+ KVM_PPC_COMPAT_CAP_POWER11)
/*
* Values for character and character_mask.
* These are identical to the values used by H_GET_CPU_CHARACTERISTICS.
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index f9380ef65750..152cd08a5b38 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -6523,6 +6523,25 @@ static bool kvmppc_hash_v3_possible(void)
return true;
}
+
+static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
+{
+ unsigned long capabilities = 0;
+ long rc = -EINVAL;
+
+ if (kvmhv_on_pseries()) {
+ if (kvmhv_is_nestedv2()) {
+ WARN_ON_ONCE(!nested_capabilities);
+ capabilities = nested_capabilities;
+ rc = 0;
+ }
+ }
+
+ host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
+
+ return rc;
+}
+
static struct kvmppc_ops kvm_ops_hv = {
.get_sregs = kvm_arch_vcpu_ioctl_get_sregs_hv,
.set_sregs = kvm_arch_vcpu_ioctl_set_sregs_hv,
@@ -6565,6 +6584,7 @@ static struct kvmppc_ops kvm_ops_hv = {
.hash_v3_possible = kvmppc_hash_v3_possible,
.create_vcpu_debugfs = kvmppc_arch_create_vcpu_debugfs_hv,
.create_vm_debugfs = kvmppc_arch_create_vm_debugfs_hv,
+ .get_compat_caps = kvmppc_get_compat_caps,
};
static int kvm_init_subcore_bitmap(void)
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM Amit Machhiwal
@ 2026-08-04 18:07 ` Amit Machhiwal
2026-08-04 18:27 ` sashiko-bot
2026-08-04 18:07 ` [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl Amit Machhiwal
` (2 subsequent siblings)
5 siblings, 1 reply; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-04 18:07 UTC (permalink / raw)
To: linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Amit Machhiwal, Anushree Mathur, Paolo Bonzini,
Nicholas Piggin, Michael Ellerman, Christophe Leroy (CS GROUP),
Jonathan Corbet, Shuah Khan, Ritesh Harjani, kvm, linux-kernel,
linux-doc, Gautam Menghani
Currently, when booting a compatibility-mode KVM guest (L1) on a PowerNV
hypervisor (L0), the guest runs with the expected processor
compatibility level. However, when booting a nested KVM guest (L2)
inside the L1, QEMU derives the CPU model from the raw host PVR and
attempts to run the nested guest at that level, instead of honoring the
compatibility mode of the L1.
Extend host CPU compatibility capability reporting to support nested
virtualization on PowerNV systems (PAPR nested API v1).
For nested API v2 (PowerVM), compatibility capabilities are served from
the cached nested_capabilities value (populated at module init via
kvmhv_nested_init() using the H_GUEST_GET_CAPABILITIES hcall). This
information is not available on PowerNV systems.
For nested API v1, derive the compatibility capabilities from the L1
guest by reading the "cpu-version" property from the device tree, which
reflects the effective (logical) processor compatibility level. Map this
value to the corresponding compatibility capability bitmap using
KVM-specific constants.
The mapping is cumulative: a system running at a given compatibility
level is assumed to also support older generations down the supported
chain. Note that unlike KVM on PowerVM (nested API v2), KVM on PowerNV
currently does not strictly enforce older generation compatibility modes
for nested guests - the reported capabilities reflect what the host CPU
can present, not what the hypervisor independently validates.
Introduce a helper kvmppc_map_compat_capabilities() to translate CPU
version values into KVM_PPC_COMPAT_CAP bits using a fallthrough switch,
and integrate it into kvmppc_get_compat_caps(). The implementation
applies masking to ensure only supported processor modes are exposed.
This allows userspace to query host CPU compatibility modes on both
KVM on PowerVM and on PowerNV platforms via the KVM_PPC_GET_COMPAT_CAPS
ioctl.
Suggested-by: Vaibhav Jain <vaibhav@linux.ibm.com>
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>
---
Changes in this version:
- kvmppc_map_compat_capabilities(): changed parameter type from
'const __be32' to 'u32' to fix Sparse type annotation warning
- kvmppc_get_compat_caps(): replaced of_get_property() + be32_to_cpup()
with of_property_read_u32() for implicit length validation and cleaner
endianness handling; dropped 'const __be32 *prop' variable
arch/powerpc/kvm/book3s_hv.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 152cd08a5b38..4d0307f55e06 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -6523,20 +6523,56 @@ static bool kvmppc_hash_v3_possible(void)
return true;
}
+static int kvmppc_map_compat_capabilities(u32 cpu_version,
+ unsigned long *capabilities)
+{
+ switch (cpu_version) {
+ case PVR_ARCH_31_P11:
+ *capabilities |= KVM_PPC_COMPAT_CAP_POWER11;
+ fallthrough;
+ case PVR_ARCH_31:
+ *capabilities |= KVM_PPC_COMPAT_CAP_POWER10;
+ fallthrough;
+ case PVR_ARCH_300:
+ *capabilities |= KVM_PPC_COMPAT_CAP_POWER9;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
{
+ struct device_node *np;
unsigned long capabilities = 0;
long rc = -EINVAL;
+ u32 cpu_version = 0;
if (kvmhv_on_pseries()) {
if (kvmhv_is_nestedv2()) {
WARN_ON_ONCE(!nested_capabilities);
capabilities = nested_capabilities;
rc = 0;
+ } else {
+ for_each_node_by_type(np, "cpu") {
+ if (!of_property_read_u32(np, "cpu-version",
+ &cpu_version)) {
+ of_node_put(np);
+ break;
+ }
+ }
+ if (!cpu_version)
+ return -EINVAL;
+ rc = kvmppc_map_compat_capabilities(cpu_version,
+ &capabilities);
}
}
+ if (rc < 0)
+ return rc;
+
host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
return rc;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 18+ messages in thread
* [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
` (2 preceding siblings ...)
2026-08-04 18:07 ` [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV Amit Machhiwal
@ 2026-08-04 18:07 ` Amit Machhiwal
2026-08-04 18:27 ` sashiko-bot
2026-08-05 4:32 ` [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Anushree Mathur
2026-08-05 18:39 ` Ritesh Harjani
5 siblings, 1 reply; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-04 18:07 UTC (permalink / raw)
To: linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Amit Machhiwal, Anushree Mathur, Paolo Bonzini,
Nicholas Piggin, Michael Ellerman, Christophe Leroy (CS GROUP),
Jonathan Corbet, Shuah Khan, Ritesh Harjani, kvm, linux-kernel,
linux-doc, Gautam Menghani
Add documentation for the KVM_PPC_GET_COMPAT_CAPS ioctl to the KVM API
documentation.
The ioctl exposes host processor compatibility modes supported for
nested KVM guests on PowerPC systems. The documentation covers error
code descriptions including E2BIG for forward compatibility, the
extensible size-based versioning contract using
KVM_PPC_COMPAT_CAPS_SIZE_VER0, the rationale for rejecting non-zero
reserved fields to prevent ABI ambiguity, bit numbering clarification
for IBM MSB-0 convention, and KVM-specific capability bit constants.
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>
---
Changes in this version:
- Corrected :Parameters: from (out) to (in/out) since userspace must
set size and flags before calling
Documentation/virt/kvm/api.rst | 79 ++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index e3003a241d5b..22fedb0aa34b 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -6566,6 +6566,85 @@ KVM_S390_KEYOP_SSKE
Sets the storage key for the guest address ``guest_addr`` to the key
specified in ``key``, returning the previous value in ``key``.
+4.145 KVM_PPC_GET_COMPAT_CAPS
+-----------------------------
+:Capability: KVM_CAP_PPC_COMPAT_CAPS
+:Architectures: powerpc
+:Type: vm ioctl
+:Parameters: struct kvm_ppc_compat_caps (in/out)
+:Returns: 0 on success, negative value on failure
+
+Errors include:
+
+ ======== ============================================================
+ EFAULT if ``struct kvm_ppc_compat_caps`` cannot be read from or
+ written to userspace
+ EINVAL if the ``size`` field is smaller than
+ ``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field
+ is non-zero, or if the backend fails to retrieve or map
+ CPU compatibility capabilities
+ E2BIG if ``size`` is larger than the kernel's struct size
+ (new userspace on old kernel); the kernel writes back its
+ own struct size into the ``size`` field so userspace can
+ retry with the correct size
+ ENOTTY if the backend does not implement the ``get_compat_caps``
+ operation (e.g., on non-HV KVM implementations where the
+ required KVM operations are not available)
+ ======== ============================================================
+
+IBM POWER system server-based processors provide a compatibility mode feature
+where an Nth generation processor can operate in modes consistent with earlier
+generations such as (N-1) and (N-2).
+
+This ioctl provides userspace with information about the CPU compatibility modes
+supported by the current host processor for booting the nested KVM guests on
+KVM on PowerNV (nested API v1) and KVM on PowerVM (nested API v2) platforms.
+
+::
+
+ struct kvm_ppc_compat_caps {
+ __u64 size; /* Size of this structure */
+ __u64 flags; /* Reserved for future use, must be 0 */
+ __u64 compat_capabilities; /* Capabilities supported by the host */
+ };
+
+Before calling this ioctl, userspace must set the ``size`` field to
+``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.
+The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent
+uninitialized stack values from being silently accepted, keeping the
+field available for future use without ABI ambiguity.
+
+The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``
+to support extensible versioning: if userspace passes a struct smaller
+than the current kernel version (``size >= KVM_PPC_COMPAT_CAPS_SIZE_VER0``),
+the kernel zero-pads unknown trailing fields. If userspace passes a larger
+struct (``size > sizeof(struct kvm_ppc_compat_caps)``), the kernel writes
+back its own struct size into the ``size`` field and returns ``-E2BIG``,
+allowing userspace to discover the kernel's struct size and retry.
+``KVM_PPC_COMPAT_CAPS_SIZE_VER0`` (24) is a frozen constant marking the
+size of the initial struct version.
+
+The ``compat_capabilities`` bit field describes the processor compatibility
+modes supported by the host. The following bits indicate support for specific
+processor modes (using IBM's MSB-0 convention where bit 0 is the most
+significant bit):
+
+- ``KVM_PPC_COMPAT_CAP_POWER9`` (bit 1) -- KVM guests can run in Power9 processor mode
+- ``KVM_PPC_COMPAT_CAP_POWER10`` (bit 2) -- KVM guests can run in Power10 processor mode
+- ``KVM_PPC_COMPAT_CAP_POWER11`` (bit 3) -- KVM guests can run in Power11 processor mode
+
+.. note::
+
+ The bit numbering above uses IBM's MSB-0 convention (bit 0 is the most
+ significant bit). In the actual implementation, these are defined as:
+
+ - ``KVM_PPC_COMPAT_CAP_POWER9`` = ``(1ULL << 62)``
+ - ``KVM_PPC_COMPAT_CAP_POWER10`` = ``(1ULL << 61)``
+ - ``KVM_PPC_COMPAT_CAP_POWER11`` = ``(1ULL << 60)``
+
+ Userspace should use the defined constants from ``<linux/kvm.h>`` rather
+ than hardcoding bit positions.
+
.. _kvm_run:
5. The kvm_run structure
--
2.50.1 (Apple Git-155)
^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
2026-08-04 18:07 ` [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl Amit Machhiwal
@ 2026-08-04 18:19 ` sashiko-bot
2026-08-06 16:07 ` Amit Machhiwal
0 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-08-04 18:19 UTC (permalink / raw)
To: Amit Machhiwal; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] The ioctl artificially inflates the userspace struct's `size` field on success, creating a memory corruption trap if userspace reuses the struct.
- [High] The ioctl unconditionally rejects larger structs with -E2BIG, bypassing standard UAPI zero-checking and encouraging silent input truncation.
- [Medium] The KVM_PPC_GET_COMPAT_CAPS ioctl availability is decoupled from its KVM_CAP_PPC_COMPAT_CAPS capability, breaking capability negotiation and bisectability.
--
--- Patch [1]: [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl ---
commit bcf86bb5d3079ca2dbb4bf09693ba6e6a24b06c5
Author: Amit Machhiwal <amachhiw@linux.ibm.com>
KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
This commit introduces a new capability and ioctl to expose CPU compatibility
modes supported by the host processor for nested guests.
> diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
> index 00302399fc37b..8d6632c64ca5f 100644
> --- a/arch/powerpc/kvm/powerpc.c
> +++ b/arch/powerpc/kvm/powerpc.c
> @@ -697,6 +697,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> }
> }
> break;
> +#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
> + case KVM_CAP_PPC_COMPAT_CAPS:
> + r = 0;
> + if (kvmhv_on_pseries())
> + r = 1;
> + break;
[Severity: Medium]
Is this capability check fully aligned with the ioctl's availability?
This check returns 1 on a pseries host using PR KVM (since it misses the
hv_enabled check), but the ioctl might fail with -ENOTTY if the backend
is missing.
Later in the ioctl execution, it succeeds on a bare-metal host using HV KVM
(missing the kvmhv_on_pseries() check) even though this capability check
would return 0.
Could this decoupling between the capability and the ioctl availability break
capability negotiation for userspace?
> +#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
> default:
> r = 0;
> break;
[ ... ]
> @@ -2463,6 +2470,70 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
> r = kvm->arch.kvm_ops->svm_off(kvm);
> break;
> }
> + case KVM_PPC_GET_COMPAT_CAPS: {
> + struct kvm_ppc_compat_caps host_caps = {};
> + u64 usize;
> +
> + /*
> + * Read the size field first to drive copy_struct_from_user.
> + * size must be the first field of the struct.
> + */
> + r = -EFAULT;
> + if (get_user(usize, (__u64 __user *)argp))
> + goto out;
> +
> + /*
> + * Enforce a minimum: reject buffers smaller than the initial
> + * struct version (VER0). This allows old userspace compiled
> + * against the original struct to still work on a newer kernel
> + * that has grown the struct with appended fields.
> + */
> + r = -EINVAL;
> + if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0)
> + goto out;
> +
> + /*
> + * New userspace with a larger struct called an older kernel.
> + * Write back ksize in host_caps.size so userspace knows which
> + * older struct to retry with, then fail with -E2BIG.
> + */
> + if (usize > sizeof(host_caps)) {
> + host_caps.size = sizeof(host_caps);
> + r = -EFAULT;
> + if (put_user(host_caps.size, (__u64 __user *)argp))
> + goto out;
> + r = -E2BIG;
> + goto out;
> + }
[Severity: High]
Does explicitly rejecting larger structs here bypass the standard UAPI
zero-checking?
By catching usize > sizeof(host_caps) early and returning -E2BIG, the code
bypasses copy_struct_from_user()'s built-in validation which would safely
reject non-zero extended fields.
If userspace receives the smaller kernel size and retries by truncating its
buffer size, the kernel will only read the truncated portion, silently
ignoring any non-zero extended fields that userspace originally provided.
Should this rely on copy_struct_from_user() to safely check zeroed trailing
bytes instead?
> +
> + /*
> + * copy_struct_from_user() handles forward/backward compat:
> + * usize == ksize: verbatim copy
> + * usize < ksize: zero-pad trailing (old userspace, new kernel)
> + */
> + r = copy_struct_from_user(&host_caps, sizeof(host_caps),
> + argp, usize);
> + if (r)
> + goto out;
> +
> + /* Reserved fields must be zero */
> + r = -EINVAL;
> + if (host_caps.flags)
> + goto out;
> +
> + r = -ENOTTY;
> + if (!kvm->arch.kvm_ops->get_compat_caps)
> + goto out;
> +
> + r = kvm->arch.kvm_ops->get_compat_caps(&host_caps);
> + if (r)
> + goto out;
> +
> + host_caps.size = sizeof(host_caps);
> + r = copy_struct_to_user(argp, usize, &host_caps,
> + sizeof(host_caps), NULL);
[Severity: High]
Can this artificial size inflation cause an out-of-bounds read/write if
userspace reuses the struct?
If an older userspace passes a smaller struct to a newer kernel (where
usize < sizeof(host_caps)), the kernel sets host_caps.size to its own larger
size. It then copies the smaller usize bytes back, overwriting the userspace
size field with the kernel's larger size.
If userspace reuses this struct for a subsequent ioctl call, it will now pass
the larger size. The kernel would then read past the end of the originally
allocated userspace buffer, and if successful, write back past the end
as well.
> + break;
> + }
> default: {
> struct kvm *kvm = filp->private_data;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM
2026-08-04 18:07 ` [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM Amit Machhiwal
@ 2026-08-04 18:21 ` sashiko-bot
2026-08-06 16:09 ` Amit Machhiwal
0 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-08-04 18:21 UTC (permalink / raw)
To: Amit Machhiwal; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Mismatch between KVM_CAP_PPC_COMPAT_CAPS advertisement and ioctl implementation for unsupported environments.
--
--- Patch [2]: [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM ---
commit 8305652489744988576b7fa55e0424452c48a633
Author: Amit Machhiwal <amachhiw@linux.ibm.com>
KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM
This commit adds support for retrieving host CPU compatibility capabilities
for nested guests on PowerVM. The capability bitmap is retrieved from the
cached nested_capabilities value and exposed through the new
KVM_PPC_GET_COMPAT_CAPS ioctl.
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 61dbeea317f3b..8799124b80960 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
[ ... ]
> @@ -6510,6 +6510,25 @@ static bool kvmppc_hash_v3_possible(void)
> return true;
> }
>
> +
> +static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
> +{
> + unsigned long capabilities = 0;
> + long rc = -EINVAL;
> +
> + if (kvmhv_on_pseries()) {
> + if (kvmhv_is_nestedv2()) {
> + WARN_ON_ONCE(!nested_capabilities);
> + capabilities = nested_capabilities;
> + rc = 0;
> + }
> + }
> +
> + host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
> +
> + return rc;
> +}
[Severity: Medium]
Will this return -EINVAL for pseries hosts when nestedv1 is used?
If KVM_CAP_PPC_COMPAT_CAPS advertises support by returning 1 for all pseries
hosts (which appears to be the case in kvm_vm_ioctl_check_extension),
userspace might query KVM_PPC_GET_COMPAT_CAPS and hit this path when
kvmhv_is_nestedv2() is false.
For example, if userspace checks KVM_CAP_PPC_COMPAT_CAPS and gets a positive
result, but kvmhv_is_nestedv2() returns false here, we return -EINVAL.
Since -EINVAL typically indicates invalid structure size or bad flags, could
userspace fail to differentiate an unsupported backend from invalid inputs,
leading to initialization failures?
Should this gracefully return 0 capabilities (or -ENOTTY), or should the
capability check itself verify kvmhv_is_nestedv2() before advertising support?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=2
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV
2026-08-04 18:07 ` [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV Amit Machhiwal
@ 2026-08-04 18:27 ` sashiko-bot
2026-08-06 16:13 ` Amit Machhiwal
0 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-08-04 18:27 UTC (permalink / raw)
To: Amit Machhiwal; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] `kvmppc_get_compat_caps()` incorrectly returns `-EINVAL` when the 'cpu-version' property is absent, breaking the `KVM_CAP_PPC_COMPAT_CAPS` contract.
--
--- Patch [3]: [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV ---
commit b4de9c28bb9d6eeb95ed5310169709b332b6f664
Author: Amit Machhiwal <amachhiw@linux.ibm.com>
KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV
This commit extends host CPU compatibility capability reporting to support
nested virtualization on PowerNV systems. For nested API v1, it derives
compatibility capabilities from the L1 guest by reading the cpu-version
property from the device tree and maps it to the corresponding compatibility
capability bitmap.
> diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> index 8799124b80960..77558f6eed864 100644
> --- a/arch/powerpc/kvm/book3s_hv.c
> +++ b/arch/powerpc/kvm/book3s_hv.c
[ ... ]
> static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
> {
> + struct device_node *np;
> unsigned long capabilities = 0;
> long rc = -EINVAL;
> + u32 cpu_version = 0;
>
> if (kvmhv_on_pseries()) {
> if (kvmhv_is_nestedv2()) {
> WARN_ON_ONCE(!nested_capabilities);
> capabilities = nested_capabilities;
> rc = 0;
> + } else {
> + for_each_node_by_type(np, "cpu") {
> + if (!of_property_read_u32(np, "cpu-version",
> + &cpu_version)) {
> + of_node_put(np);
> + break;
> + }
> + }
> + if (!cpu_version)
> + return -EINVAL;
[Severity: High]
If an L1 guest is booted in native mode (e.g. without a 'compat=' setting in
QEMU), the cpu-version property is intentionally omitted from the device
tree.
Doesn't returning -EINVAL here cause KVM_PPC_GET_COMPAT_CAPS to fail,
thereby breaking nested virtualization initialization for native-mode L1
guests?
Could this fall back to deriving capabilities from the physical native PVR
instead of returning an error?
> + rc = kvmppc_map_compat_capabilities(cpu_version,
> + &capabilities);
> }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=3
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
2026-08-04 18:07 ` [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl Amit Machhiwal
@ 2026-08-04 18:27 ` sashiko-bot
2026-08-06 16:15 ` Amit Machhiwal
0 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-08-04 18:27 UTC (permalink / raw)
To: Amit Machhiwal; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unconditional rejection of larger structs breaks the forward compatibility mechanism of copy_struct_from_user().
- [High] Overwriting the userspace size field with the kernel's struct size creates dangerous ambiguities on success.
--
--- Patch [4]: [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl ---
commit 5d4e2edcf1688edc6d21e5f2463ef8b58bd3d0a7
Author: Amit Machhiwal <amachhiw@linux.ibm.com>
KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
Add documentation for the KVM_PPC_GET_COMPAT_CAPS ioctl to the KVM API
documentation. The documentation covers error code descriptions including
E2BIG for forward compatibility and the extensible size-based versioning
contract.
> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> index e3003a241d5b0..22fedb0aa34b4 100644
> --- a/Documentation/virt/kvm/api.rst
> +++ b/Documentation/virt/kvm/api.rst
> @@ -6566,6 +6566,85 @@ KVM_S390_KEYOP_SSKE
> Sets the storage key for the guest address ``guest_addr`` to the key
> specified in ``key``, returning the previous value in ``key``.
>
> +4.145 KVM_PPC_GET_COMPAT_CAPS
> +-----------------------------
> +:Capability: KVM_CAP_PPC_COMPAT_CAPS
> +:Architectures: powerpc
> +:Type: vm ioctl
> +:Parameters: struct kvm_ppc_compat_caps (in/out)
> +:Returns: 0 on success, negative value on failure
> +
> +Errors include:
> +
> + ======== ============================================================
> + EFAULT if ``struct kvm_ppc_compat_caps`` cannot be read from or
> + written to userspace
> + EINVAL if the ``size`` field is smaller than
> + ``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field
> + is non-zero, or if the backend fails to retrieve or map
> + CPU compatibility capabilities
> + E2BIG if ``size`` is larger than the kernel's struct size
> + (new userspace on old kernel); the kernel writes back its
> + own struct size into the ``size`` field so userspace can
> + retry with the correct size
[Severity: High]
Does explicitly rejecting a larger struct size with -E2BIG break the standard
forward compatibility mechanism of copy_struct_from_user()?
Extensible struct UAPIs are designed to allow newer userspace to run seamlessly
on older kernels as long as new fields are zeroed.
Looking at arch/powerpc/kvm/powerpc.c in kvm_arch_vm_ioctl(), the code
short-circuits the native trailing-zero check in copy_struct_from_user():
if (usize > sizeof(host_caps)) {
host_caps.size = sizeof(host_caps);
r = -EFAULT;
if (put_user(host_caps.size, (__u64 __user *)argp))
goto out;
r = -E2BIG;
goto out;
}
This forces userspace to implement fallback retry loops instead of relying on
the kernel's native UAPI extensibility.
[ ... ]
> +Before calling this ioctl, userspace must set the ``size`` field to
> +``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.
> +The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent
> +uninitialized stack values from being silently accepted, keeping the
> +field available for future use without ABI ambiguity.
> +
> +The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``
> +to support extensible versioning: if userspace passes a struct smaller
> +than the current kernel version (``size >= KVM_PPC_COMPAT_CAPS_SIZE_VER0``),
> +the kernel zero-pads unknown trailing fields. If userspace passes a larger
> +struct (``size > sizeof(struct kvm_ppc_compat_caps)``), the kernel writes
> +back its own struct size into the ``size`` field and returns ``-E2BIG``,
> +allowing userspace to discover the kernel's struct size and retry.
[Severity: High]
Can overwriting the userspace size field with the kernel's struct size create
dangerous ambiguities on success?
If userspace passes a smaller struct (e.g., 24 bytes) and the kernel uses a
larger struct (e.g., 32 bytes), the kernel updates host_caps.size to 32 and
copies 24 bytes back to userspace.
Looking at arch/powerpc/kvm/powerpc.c in kvm_arch_vm_ioctl():
host_caps.size = sizeof(host_caps);
r = copy_struct_to_user(argp, usize, &host_caps,
sizeof(host_caps), NULL);
Userspace would receive a success code (0) but its size field is now 32. This
falsely indicates to userspace that the kernel provided 32 bytes of valid data,
which can lead to out-of-bounds reads if userspace trusts the returned size
field to determine valid data bounds within its buffer.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=4
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
` (3 preceding siblings ...)
2026-08-04 18:07 ` [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl Amit Machhiwal
@ 2026-08-05 4:32 ` Anushree Mathur
2026-08-05 18:39 ` Ritesh Harjani
5 siblings, 0 replies; 18+ messages in thread
From: Anushree Mathur @ 2026-08-05 4:32 UTC (permalink / raw)
To: Amit Machhiwal, linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Paolo Bonzini, Nicholas Piggin, Michael Ellerman,
Christophe Leroy (CS GROUP), Jonathan Corbet, Shuah Khan,
Ritesh Harjani, kvm, linux-kernel, linux-doc, Anushree Mathur
On 04/08/26 11:37 PM, Amit Machhiwal wrote:
> On POWER systems, newer processor generations can operate in compatibility
> modes corresponding to earlier generations (e.g., a Power11 system running
> in Power10 compatibility mode). In such cases, the effective CPU level
> exposed to guests differs from the physical processor generation.
>
> This creates a problem for nested virtualization. When booting a nested KVM
> guest (L2) inside a host KVM guest (L1) running in a compatibility mode,
> userspace (e.g., QEMU) may derive the CPU model from the raw hardware PVR
> and attempt to configure the nested guest accordingly. However, the L1
> partition is constrained by the compatibility level negotiated with the
> hypervisor (L0), and requests exceeding that level are rejected, leading to
> guest boot failures such as:
>
> KVM-NESTEDv2: couldn't set guest wide elements
>
> This series provides a mechanism for userspace to query the effective CPU
> compatibility modes supported by the host, so it can select an appropriate
> CPU model for nested guests.
>
> To achieve this, the series introduces a new KVM capability and ioctl
> (KVM_CAP_PPC_COMPAT_CAPS / KVM_PPC_GET_COMPAT_CAPS) that expose the
> compatibility modes supported by the host.
>
> Why a new UAPI?
> ===============
> While cpu-version is available in /proc/device-tree/cpus/<cpu#>/cpu-version
> on both L1 booted on PowerNV and PowerVM LPARs, the UAPI approach is
> preferable for several reasons:
>
> 1. pHYP (L0) capabilities: On PowerVM, we need to rely on capabilities
> negotiated with pHYP in KVM, not just device tree properties. The
> cpu-version property depicts the current compat mode but doesn't point
> to what all compat modes are supported for the nested guest.
>
> 2. procfs dependency: Not all systems run with procfs enabled (CONFIG_PROC_FS
> is optional). Minimal configurations like buildroot might disable it, but
> KVM ioctl works regardless since it accesses kernel data structures
> directly.
>
> 3. Kernel validation: The kernel validates and normalizes the compatibility
> information, ensuring userspace gets validated, consistent data.
>
> 4. Abstraction & stability: /proc/device-tree is an implementation detail.
> The UAPI provides a stable interface that won't break if the underlying
> mechanism changes.
>
> 5. Semantic clarity: KVM_PPC_GET_COMPAT_CAPS clearly expresses what
> compatibility modes can be used for KVM guests, vs. parsing device tree
> which requires understanding the semantic meaning of cpu-version.
>
> The implementation supports both:
>
> - KVM on PowerVM (nested API v2), where compatibility information is
> served from the cached nested_capabilities value, originally obtained
> via the H_GUEST_GET_CAPABILITIES hypercall at module init.
> - KVM on PowerNV (nested API v1), where compatibility is derived from the
> device tree ("cpu-version") representing the effective processor
> compatibility level.
>
> This allows userspace (e.g., QEMU) to select a CPU model consistent with
> the host compatibility mode, avoiding mismatches and enabling successful
> nested guest boot.
>
> Note: This series is built on top of patch [1] which must be applied first.
> Patch [1] ensures arch_compat is validated against the host compatibility
> mode before this series adds the capability query mechanism.
> Commit e4de1b9cb3b5 ("powerpc/dt_cpu_ftrs: Set CPU_FTR_P11_PVR for Power11
> and later processors") which was also a prerequisite has been merged upstream.
>
> Changes in v6:
> - Changed KVM_PPC_GET_COMPAT_CAPS ioctl number from 0xe4 to 0xb8 to
> avoid placing it in the KVM_CREATE_DEVICE fd ioctl range (0xe0-0xe3);
> relocated definition to sit alongside other PPC vm ioctls (patch 1)
> - [Gautam]
> - kvmppc_map_compat_capabilities(): changed parameter type from
> 'const __be32' to 'u32' to fix Sparse type annotation warning (patch 3)
> - [Sashiko]
> - kvmppc_get_compat_caps(): replaced of_get_property() + be32_to_cpup()
> with of_property_read_u32() for implicit length validation and cleaner
> endianness handling (patch 3) - [Sashiko]
> - Documentation: corrected :Parameters: from (out) to (in/out) since
> userspace must set size and flags before calling (patch 4) - [Sashiko]
>
> Patch summary:
> [1/4] Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
> [2/4] Implement capability retrieval for KVM on PowerVM (API v2)
> [3/4] Add KVM on PowerNV support (API v1)
> [4/4] Document the new ioctl
>
> Testing (with QEMU v4 patches and on top of patch [1]):
>
> KVM APIv1 Testing
> =================
> On P10 PowerNV machine (L0)
> ---------------------------
> - P10 L1 KVM guest -> works
> - P10 nested L2 KVM guest -> works
> - P9 compat nested L2 KVM guest -> works
> - P9 compat L1 KVM guest -> works
> - P9 nested L2 KVM guest -> works
>
> On Powernv11 TCG Guest (L0)
> ---------------------------
> - P11 PowerNV TCG L0 guest -> works
> - P11 L1 KVM guest -> works
> - P11 L2 KVM guest -> works
> - P10 compat L1 KVM guest -> works
> - P10 L2 KVM guest -> works
> - P9 compat L1 KVM guest -> works
> - P9 L2 KVM guest -> works
>
> KVM APIv2 Testing
> =================
> On P11 PowerVM LPAR (L1)
> ------------------------
> - P11 L2 KVM guest -> works
> - P10 compat L2 KVM guest -> works
> - P9 compat L2 KVM guest fails to boot as expected
> - Without QEMU patches but Linux patches
> - P11 L2 KVM guest -> works
> - P10 compat L2 KVM guest -> works
> - P9 compat L2 KVM guest fails to boot as expected
> - Without Linux patches but QEMU patches
> - P11 L2 KVM guest -> works
> - P10 compat L2 KVM guest -> works
>
> On P11 LPAR in P10 compat (L1)
> ------------------------------
> - P10 (host compat) L2 KVM guest -> works
> - Without QEMU patch but Linux patches
> - P10 guest fails to boot as expected (error: kvm run failed Invalid argument)
> - Without Linux patch but QEMU patches
> - P10 guest fails to boot as expected (KVM: unknown exit, hardware reason ffffffffffffffea)
>
> On P10 PowerVM LPAR (L1)
> ------------------------
> - P10 L2 KVM guest -> works
> - P9 compat L2 KVM guest fails to boot as expected
>
> TCG pSeries Guest
> =================
> - P11 (default) pSeries guest boots fine
>
> ABI Extensibility Testing (struct size 32, extra member)
> =========================================================
> - Newer struct on QEMU, older kernel -> works (kernel returns -E2BIG,
> QEMU retries with correct size)
> - New struct on Linux kernel, older QEMU -> works (kernel zero-pads
> trailing fields, QEMU gets correct data)
>
> With this series, nested guests boot successfully in configurations where
> they previously failed due to compatibility mismatches.
>
> Related QEMU series:
> ====================
> A corresponding QEMU v5 series will be sent soon.
>
> Previous QEMU versions:
> v4: https://lore.kernel.org/all/20260701052341.62289-1-amachhiw@linux.ibm.com/
> v3: https://lore.kernel.org/all/20260616113915.25589-1-amachhiw@linux.ibm.com/
> v2: https://lore.kernel.org/all/20260502140021.69712-1-amachhiw@linux.ibm.com/
> v1: https://lore.kernel.org/all/20260430061333.37905-1-amachhiw@linux.ibm.com/
>
> Previous versions:
> ==================
> v5: https://lore.kernel.org/linuxppc-dev/20260701051409.51820-1-amachhiw@linux.ibm.com/
> v4: https://lore.kernel.org/linuxppc-dev/20260616123314.82721-1-amachhiw@linux.ibm.com/
> v3: https://lore.kernel.org/linuxppc-dev/20260522152744.55251-1-amachhiw@linux.ibm.com/
> v2: https://lore.kernel.org/linuxppc-dev/20260513100755.83195-1-amachhiw@linux.ibm.com/
> v1: https://lore.kernel.org/linuxppc-dev/20260430054906.94431-1-amachhiw@linux.ibm.com/
>
> References:
> ===========
> [1] https://lore.kernel.org/all/20260714175432.86388-1-amachhiw@linux.ibm.com/
>
> Amit Machhiwal (4):
> KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
> KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM
> on PowerVM
> KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM
> on PowerNV
> KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
>
> Documentation/virt/kvm/api.rst | 79 +++++++++++++++++++++++++++++
> arch/powerpc/include/asm/kvm_ppc.h | 1 +
> arch/powerpc/include/uapi/asm/kvm.h | 18 +++++++
> arch/powerpc/kvm/book3s_hv.c | 56 ++++++++++++++++++++
> arch/powerpc/kvm/powerpc.c | 71 ++++++++++++++++++++++++++
> include/uapi/linux/kvm.h | 3 ++
> 6 files changed, 228 insertions(+)
>
>
> base-commit: 848acc8ffe1b7cd5f1bf427b93069becfebc2c9d
> prerequisite-patch-id: 7755786f0e4f415e47065ff1972765008727fe10
Hi Amit,
I have tested this patch and it works as expected. Here is my analysis :
I booted a host with Power10 compat mode and tried following scenarios -
lscpu on host :
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Model name: POWER10 (architected), altivec supported
Before applying the patch :
When I am trying to bringup the guest on a compat mode host it was
bringing up a Power11 guest and was failing as
[ 1411.578944] [ T2928] KVM-NESTEDv2: couldn't set guest wide elements
[ 1411.578963] [ T2928] vcpu 000000000b9c4155 (0):
[ 1411.578968] [ T2928] pc = 000000007daf9790 msr =
8000000000103000 trap = ffffffea
[ 1411.578973] [ T2928] r 0 = 8000000000003000 r16 = 0000000000000000
[ 1411.578978] [ T2928] r 1 = 000000007e581e20 r17 = 0000000000000000
[ 1411.578982] [ T2928] r 2 = 000000007db26c00 r18 = 0000000000000000
[ 1411.578985] [ T2928] r 3 = 0000000000000000 r19 = 0000000000000000
[ 1411.578989] [ T2928] r 4 = 0000000002e30c80 r20 = 0000000000000000
[ 1411.578993] [ T2928] r 5 = 000000007df80000 r21 = 0000000000000000
[ 1411.578996] [ T2928] r 6 = 0000000000200000 r22 = 00000000018c5fd6
[ 1411.579000] [ T2928] r 7 = 000000007df80000 r23 = 000000007db21cc0
[ 1411.579003] [ T2928] r 8 = 000000007db6e5d8 r24 = 000000007db66000
[ 1411.579006] [ T2928] r 9 = 000000007e6655d8 r25 = 000000007e665508
[ 1411.579010] [ T2928] r10 = 000000007db6e5d0 r26 = 00000000018c5fd6
[ 1411.579013] [ T2928] r11 = 0000000000003000 r27 = 0000000000000003
[ 1411.579017] [ T2928] r12 = 8000000000000001 r28 = 000000007db6e5e0
[ 1411.579020] [ T2928] r13 = 0000000000000000 r29 = 000000007db224b0
[ 1411.579024] [ T2928] r14 = 0000000000000000 r30 = 000000007daf274c
[ 1411.579028] [ T2928] r15 = 0000000000000000 r31 = 000000007db76000
[ 1411.579033] [ T2928] ctr = 000000007daf1b44 lr = 000000007daf1b7c
[ 1411.579037] [ T2928] srr0 = 000000007daf9790 srr1 = 8000000000102000
[ 1411.579041] [ T2928] sprg0 = 0000000000000000 sprg1 = 000000000000ff10
[ 1411.579045] [ T2928] sprg2 = 0000000000000000 sprg3 = 0000000000000000
[ 1411.579049] [ T2928] cr = 20000402 xer = 0000000020040000 dsisr =
00000000
[ 1411.579054] [ T2928] dar = 0000000000000000
[ 1411.579057] [ T2928] fault dar = 0000000000000000 dsisr = 00000000
[ 1411.579061] [ T2928] SLB (0 entries):
[ 1411.579064] [ T2928] lpcr = 0040000000020400 sdr1 =
0000000000000000 last_inst = ffffffffffffffff
[ 1411.579069] [ T2928] trap=0xffffffea | pc=0x7daf9790 |
msr=0x8000000000103000
After applying this patch along with the qemu built with it's dependent
patch
(https://lore.kernel.org/all/20260804182914.83091-1-amachhiw@linux.ibm.com/):
I am able to bringup a guest and it got boot up with Power10 by default:
lscpu on guest -
ltcbonn53-vm2:~ # lscpu
Architecture: ppc64le
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Model name: POWER10 (architected), altivec supported
Model: 2.0 (pvr 0082 0200)
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
Please feel free to add my tested-by:
Tested-by: Anushree Mathur <anushree.mathur@linux.ibm.com>
Thank you,
Anushree Mathur
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
` (4 preceding siblings ...)
2026-08-05 4:32 ` [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Anushree Mathur
@ 2026-08-05 18:39 ` Ritesh Harjani
2026-08-06 5:33 ` Amit Machhiwal
5 siblings, 1 reply; 18+ messages in thread
From: Ritesh Harjani @ 2026-08-05 18:39 UTC (permalink / raw)
To: Amit Machhiwal, linuxppc-dev, Madhavan Srinivasan
Cc: Vaibhav Jain, Amit Machhiwal, Anushree Mathur, Paolo Bonzini,
Nicholas Piggin, Michael Ellerman, Christophe Leroy (CS GROUP),
Jonathan Corbet, Shuah Khan, kvm, linux-kernel, linux-doc
Hi Amit,
Amit Machhiwal <amachhiw@linux.ibm.com> writes:
> On POWER systems, newer processor generations can operate in compatibility
> modes corresponding to earlier generations (e.g., a Power11 system running
> in Power10 compatibility mode). In such cases, the effective CPU level
> exposed to guests differs from the physical processor generation.
>
> This creates a problem for nested virtualization. When booting a nested KVM
> guest (L2) inside a host KVM guest (L1) running in a compatibility mode,
> userspace (e.g., QEMU) may derive the CPU model from the raw hardware PVR
> and attempt to configure the nested guest accordingly. However, the L1
> partition is constrained by the compatibility level negotiated with the
> hypervisor (L0), and requests exceeding that level are rejected, leading to
> guest boot failures such as:
>
> KVM-NESTEDv2: couldn't set guest wide elements
>
> This series provides a mechanism for userspace to query the effective CPU
> compatibility modes supported by the host, so it can select an appropriate
> CPU model for nested guests.
>
> To achieve this, the series introduces a new KVM capability and ioctl
> (KVM_CAP_PPC_COMPAT_CAPS / KVM_PPC_GET_COMPAT_CAPS) that expose the
> compatibility modes supported by the host.
>
Sorry, but I am somehow not convinced on whether we need all of this
machinary just to get these 3 bits of information, which we are
returning today.
Since KVM_CHECK_EXTENSION can already return an int, so why can't we use
KVM_CAP_PPC_COMPAT_CAPS itself and return the bitmap of supported compat
modes to the user?
Say if the cap is not supported, we can return 0, otherwise we can
return the bitmap of supported compat modes. This will easily allow us
to use 31-bits which as I see would be hardly a problem in the near
future. In the future if it grows - we can always use KVM_CAP_PPC_COMPAT_CAPS2.
This should reduce the code complexity both in the kernel and
userspace and we don't even need a new ioctl then.
Thoughts?
-ritesh
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests
2026-08-05 18:39 ` Ritesh Harjani
@ 2026-08-06 5:33 ` Amit Machhiwal
2026-08-06 13:05 ` Ritesh Harjani
0 siblings, 1 reply; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-06 5:33 UTC (permalink / raw)
To: Ritesh Harjani
Cc: Amit Machhiwal, linuxppc-dev, Madhavan Srinivasan, Vaibhav Jain,
Anushree Mathur, Paolo Bonzini, Nicholas Piggin, Michael Ellerman,
Christophe Leroy (CS GROUP), Jonathan Corbet, Shuah Khan, kvm,
linux-kernel, linux-doc
Hi Ritesh,
Thanks for taking a look. Please find my response inline.
On 2026/08/06 12:09 AM, Ritesh Harjani wrote:
>
> Hi Amit,
>
> Amit Machhiwal <amachhiw@linux.ibm.com> writes:
>
> > On POWER systems, newer processor generations can operate in compatibility
> > modes corresponding to earlier generations (e.g., a Power11 system running
> > in Power10 compatibility mode). In such cases, the effective CPU level
> > exposed to guests differs from the physical processor generation.
> >
> > This creates a problem for nested virtualization. When booting a nested KVM
> > guest (L2) inside a host KVM guest (L1) running in a compatibility mode,
> > userspace (e.g., QEMU) may derive the CPU model from the raw hardware PVR
> > and attempt to configure the nested guest accordingly. However, the L1
> > partition is constrained by the compatibility level negotiated with the
> > hypervisor (L0), and requests exceeding that level are rejected, leading to
> > guest boot failures such as:
> >
> > KVM-NESTEDv2: couldn't set guest wide elements
> >
> > This series provides a mechanism for userspace to query the effective CPU
> > compatibility modes supported by the host, so it can select an appropriate
> > CPU model for nested guests.
> >
> > To achieve this, the series introduces a new KVM capability and ioctl
> > (KVM_CAP_PPC_COMPAT_CAPS / KVM_PPC_GET_COMPAT_CAPS) that expose the
> > compatibility modes supported by the host.
> >
>
> Sorry, but I am somehow not convinced on whether we need all of this
> machinary just to get these 3 bits of information, which we are
> returning today.
>
> Since KVM_CHECK_EXTENSION can already return an int, so why can't we use
> KVM_CAP_PPC_COMPAT_CAPS itself and return the bitmap of supported compat
> modes to the user?
> Say if the cap is not supported, we can return 0, otherwise we can
> return the bitmap of supported compat modes. This will easily allow us
> to use 31-bits which as I see would be hardly a problem in the near
> future. In the future if it grows - we can always use KVM_CAP_PPC_COMPAT_CAPS2.
>
> This should reduce the code complexity both in the kernel and
> userspace and we don't even need a new ioctl then.
Thanks for the suggestion. I considered this approach but would like to
go with a dedicated ioctl for the following reasons:
1. Intended semantics: The KVM API documentation states:
..kvm defines extension identifiers and a facility to query
whether a particular extension identifier is available. If it is, a
set of ioctls is available for application use.
[...]
KVM defines many constants of the form KVM_CAP_*, each corresponding
to a set of functionality provided by one or more ioctls. Availability
of these capabilities can be checked with KVM_CHECK_EXTENSION.
The intended role of KVM_CAP_* is to signal ioctl availability, not
to serve as a data retrieval mechanism itself.
You may take a look at KVM_CAP_PPC_GET_CPU_CHAR for instance.
2. Return type constraint: KVM_CHECK_EXTENSION returns a signed 32-bit int. The
capability bits are defined as (1ULL << 62), (1ULL << 61), and (1ULL << 60) —
64-bit values that cannot fit in a 32-bit return. Renumbering them to small
integers would be a UAPI change and would lose alignment with the
H_GUEST_CAP_* values from the hypervisor ABI.
3. Extensibility: The struct-based approach with the size field provides clean
forward and backward ABI versioning via copy_struct_from/to_user(), without
needing a KVM_CAP_PPC_COMPAT_CAPS2 in the future.
Thanks,
Amit
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests
2026-08-06 5:33 ` Amit Machhiwal
@ 2026-08-06 13:05 ` Ritesh Harjani
2026-08-06 14:58 ` Amit Machhiwal
0 siblings, 1 reply; 18+ messages in thread
From: Ritesh Harjani @ 2026-08-06 13:05 UTC (permalink / raw)
To: Amit Machhiwal
Cc: Amit Machhiwal, linuxppc-dev, Madhavan Srinivasan, Vaibhav Jain,
Anushree Mathur, Paolo Bonzini, Nicholas Piggin, Michael Ellerman,
Christophe Leroy (CS GROUP), Jonathan Corbet, Shuah Khan, kvm,
linux-kernel, linux-doc
Amit Machhiwal <amachhiw@linux.ibm.com> writes:
> Hi Ritesh,
>
> Thanks for taking a look. Please find my response inline.
>
> On 2026/08/06 12:09 AM, Ritesh Harjani wrote:
>>
>> Hi Amit,
>>
>> Amit Machhiwal <amachhiw@linux.ibm.com> writes:
>>
>> > On POWER systems, newer processor generations can operate in compatibility
>> > modes corresponding to earlier generations (e.g., a Power11 system running
>> > in Power10 compatibility mode). In such cases, the effective CPU level
>> > exposed to guests differs from the physical processor generation.
>> >
>> > This creates a problem for nested virtualization. When booting a nested KVM
>> > guest (L2) inside a host KVM guest (L1) running in a compatibility mode,
>> > userspace (e.g., QEMU) may derive the CPU model from the raw hardware PVR
>> > and attempt to configure the nested guest accordingly. However, the L1
>> > partition is constrained by the compatibility level negotiated with the
>> > hypervisor (L0), and requests exceeding that level are rejected, leading to
>> > guest boot failures such as:
>> >
>> > KVM-NESTEDv2: couldn't set guest wide elements
>> >
>> > This series provides a mechanism for userspace to query the effective CPU
>> > compatibility modes supported by the host, so it can select an appropriate
>> > CPU model for nested guests.
>> >
>> > To achieve this, the series introduces a new KVM capability and ioctl
>> > (KVM_CAP_PPC_COMPAT_CAPS / KVM_PPC_GET_COMPAT_CAPS) that expose the
>> > compatibility modes supported by the host.
>> >
>>
>> Sorry, but I am somehow not convinced on whether we need all of this
>> machinary just to get these 3 bits of information, which we are
>> returning today.
>>
>> Since KVM_CHECK_EXTENSION can already return an int, so why can't we use
>> KVM_CAP_PPC_COMPAT_CAPS itself and return the bitmap of supported compat
>> modes to the user?
>> Say if the cap is not supported, we can return 0, otherwise we can
>> return the bitmap of supported compat modes. This will easily allow us
>> to use 31-bits which as I see would be hardly a problem in the near
>> future. In the future if it grows - we can always use KVM_CAP_PPC_COMPAT_CAPS2.
>>
>> This should reduce the code complexity both in the kernel and
>> userspace and we don't even need a new ioctl then.
>
> Thanks for the suggestion. I considered this approach
Then we should have brought that up early on during the design
discussion. But for the sake of discussion let's call this as
approach-2.
> but would like to
> go with a dedicated ioctl for the following reasons:
>
> 1. Intended semantics: The KVM API documentation states:
>
> ..kvm defines extension identifiers and a facility to query
> whether a particular extension identifier is available. If it is, a
> set of ioctls is available for application use.
>
> [...]
>
> KVM defines many constants of the form KVM_CAP_*, each corresponding
> to a set of functionality provided by one or more ioctls. Availability
> of these capabilities can be checked with KVM_CHECK_EXTENSION.
>
> The intended role of KVM_CAP_* is to signal ioctl availability, not
> to serve as a data retrieval mechanism itself.
That's not entirely true. We do return data as part of check extension
for e.g. for getting the SMT modes check KVM_CAP_PPC_SMT_POSSIBLE.
>
> You may take a look at KVM_CAP_PPC_GET_CPU_CHAR for instance.
>
> 2. Return type constraint: KVM_CHECK_EXTENSION returns a signed 32-bit int. The
> capability bits are defined as (1ULL << 62), (1ULL << 61), and (1ULL << 60) —
> 64-bit values that cannot fit in a 32-bit return. Renumbering them to small
> integers would be a UAPI change and would lose alignment with the
There is no _change_ in the UAPI so far. This is the patch which is
defining that in the first place.
> H_GUEST_CAP_* values from the hypervisor ABI.
No please. Those are 2 different ABIs and there is no need to set a hard
dependency among the two.
>
> 3. Extensibility: The struct-based approach with the size field provides clean
> forward and backward ABI versioning via copy_struct_from/to_user(), without
> needing a KVM_CAP_PPC_COMPAT_CAPS2 in the future.
>
This only make sense if we really have a usecase already in mind which
you are planning to extend it for. Otherwise, IMO, this is a lot of
machinary and I think we should consider the simpler approach.
IMO - I think approach-2 is a much simpler for this usecase. I don't see
any valid reason on why we should not do that instead. We don't need an
extra ioctl and all the struct machinary along with that just for
returning a bitmask. The existing check extension ioctl can be
easily used for this purpose.
Would it be possible for you to give, approach-2 a try? Do you see any
geniunine roadblock or limitation with that?
-ritesh
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests
2026-08-06 13:05 ` Ritesh Harjani
@ 2026-08-06 14:58 ` Amit Machhiwal
0 siblings, 0 replies; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-06 14:58 UTC (permalink / raw)
To: Ritesh Harjani
Cc: Amit Machhiwal, linuxppc-dev, Madhavan Srinivasan, Vaibhav Jain,
Anushree Mathur, Paolo Bonzini, Nicholas Piggin, Michael Ellerman,
Christophe Leroy (CS GROUP), Jonathan Corbet, Shuah Khan, kvm,
linux-kernel, linux-doc
On 2026/08/06 06:35 PM, Ritesh Harjani wrote:
> Amit Machhiwal <amachhiw@linux.ibm.com> writes:
>
> > Hi Ritesh,
> >
> > Thanks for taking a look. Please find my response inline.
> >
> > On 2026/08/06 12:09 AM, Ritesh Harjani wrote:
> >>
> >> Hi Amit,
> >>
> >> Amit Machhiwal <amachhiw@linux.ibm.com> writes:
> >>
> >> > On POWER systems, newer processor generations can operate in compatibility
> >> > modes corresponding to earlier generations (e.g., a Power11 system running
> >> > in Power10 compatibility mode). In such cases, the effective CPU level
> >> > exposed to guests differs from the physical processor generation.
> >> >
> >> > This creates a problem for nested virtualization. When booting a nested KVM
> >> > guest (L2) inside a host KVM guest (L1) running in a compatibility mode,
> >> > userspace (e.g., QEMU) may derive the CPU model from the raw hardware PVR
> >> > and attempt to configure the nested guest accordingly. However, the L1
> >> > partition is constrained by the compatibility level negotiated with the
> >> > hypervisor (L0), and requests exceeding that level are rejected, leading to
> >> > guest boot failures such as:
> >> >
> >> > KVM-NESTEDv2: couldn't set guest wide elements
> >> >
> >> > This series provides a mechanism for userspace to query the effective CPU
> >> > compatibility modes supported by the host, so it can select an appropriate
> >> > CPU model for nested guests.
> >> >
> >> > To achieve this, the series introduces a new KVM capability and ioctl
> >> > (KVM_CAP_PPC_COMPAT_CAPS / KVM_PPC_GET_COMPAT_CAPS) that expose the
> >> > compatibility modes supported by the host.
> >> >
> >>
> >> Sorry, but I am somehow not convinced on whether we need all of this
> >> machinary just to get these 3 bits of information, which we are
> >> returning today.
> >>
> >> Since KVM_CHECK_EXTENSION can already return an int, so why can't we use
> >> KVM_CAP_PPC_COMPAT_CAPS itself and return the bitmap of supported compat
> >> modes to the user?
> >> Say if the cap is not supported, we can return 0, otherwise we can
> >> return the bitmap of supported compat modes. This will easily allow us
> >> to use 31-bits which as I see would be hardly a problem in the near
> >> future. In the future if it grows - we can always use KVM_CAP_PPC_COMPAT_CAPS2.
> >>
> >> This should reduce the code complexity both in the kernel and
> >> userspace and we don't even need a new ioctl then.
> >
> > Thanks for the suggestion. I considered this approach
>
> Then we should have brought that up early on during the design
> discussion. But for the sake of discussion let's call this as
> approach-2.
>
> > but would like to
> > go with a dedicated ioctl for the following reasons:
> >
>
> > 1. Intended semantics: The KVM API documentation states:
> >
> > ..kvm defines extension identifiers and a facility to query
> > whether a particular extension identifier is available. If it is, a
> > set of ioctls is available for application use.
> >
> > [...]
> >
> > KVM defines many constants of the form KVM_CAP_*, each corresponding
> > to a set of functionality provided by one or more ioctls. Availability
> > of these capabilities can be checked with KVM_CHECK_EXTENSION.
> >
> > The intended role of KVM_CAP_* is to signal ioctl availability, not
> > to serve as a data retrieval mechanism itself.
>
> That's not entirely true. We do return data as part of check extension
> for e.g. for getting the SMT modes check KVM_CAP_PPC_SMT_POSSIBLE.
>
> >
> > You may take a look at KVM_CAP_PPC_GET_CPU_CHAR for instance.
> >
> > 2. Return type constraint: KVM_CHECK_EXTENSION returns a signed 32-bit int. The
> > capability bits are defined as (1ULL << 62), (1ULL << 61), and (1ULL << 60) —
> > 64-bit values that cannot fit in a 32-bit return. Renumbering them to small
> > integers would be a UAPI change and would lose alignment with the
>
> There is no _change_ in the UAPI so far. This is the patch which is
> defining that in the first place.
>
> > H_GUEST_CAP_* values from the hypervisor ABI.
>
> No please. Those are 2 different ABIs and there is no need to set a hard
> dependency among the two.
>
> >
> > 3. Extensibility: The struct-based approach with the size field provides clean
> > forward and backward ABI versioning via copy_struct_from/to_user(), without
> > needing a KVM_CAP_PPC_COMPAT_CAPS2 in the future.
> >
>
> This only make sense if we really have a usecase already in mind which
> you are planning to extend it for. Otherwise, IMO, this is a lot of
> machinary and I think we should consider the simpler approach.
>
> IMO - I think approach-2 is a much simpler for this usecase. I don't see
> any valid reason on why we should not do that instead. We don't need an
> extra ioctl and all the struct machinary along with that just for
> returning a bitmask. The existing check extension ioctl can be
> easily used for this purpose.
>
> Would it be possible for you to give, approach-2 a try? Do you see any
> geniunine roadblock or limitation with that?
As discussed, one additional and deeper technical reason is that the
Power Hypervisor (PHYP) returns a 64-bit capabilities mask as part of
the H_GUEST_GET_CAPABILITIES hcall (defined in the PAPR specification).
Our KVM_PPC_COMPAT_CAP_* bits are deliberately aligned to this 64-bit
mask so that the cached nested_capabilities value can be used directly
without any translation.
The PAPR spec reserves bits beyond the current processor modes and
capability flags for future capabilities. As new processor generations
arrive, some of those reserved bits may become relevant for them — at
which point a 32-bit return from KVM_CHECK_EXTENSION would be
insufficient, forcing a KVM_CAP_PPC_COMPAT_CAPS2.
The struct-based ioctl avoids this problem cleanly.
Thanks,
Amit
>
> -ritesh
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
2026-08-04 18:19 ` sashiko-bot
@ 2026-08-06 16:07 ` Amit Machhiwal
0 siblings, 0 replies; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-06 16:07 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Amit Machhiwal, kvm
On 2026/08/04 06:19 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] The ioctl artificially inflates the userspace struct's `size` field on success, creating a memory corruption trap if userspace reuses the struct.
> - [High] The ioctl unconditionally rejects larger structs with -E2BIG, bypassing standard UAPI zero-checking and encouraging silent input truncation.
> - [Medium] The KVM_PPC_GET_COMPAT_CAPS ioctl availability is decoupled from its KVM_CAP_PPC_COMPAT_CAPS capability, breaking capability negotiation and bisectability.
> --
>
> --- Patch [1]: [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl ---
> commit bcf86bb5d3079ca2dbb4bf09693ba6e6a24b06c5
> Author: Amit Machhiwal <amachhiw@linux.ibm.com>
>
> KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl
>
> This commit introduces a new capability and ioctl to expose CPU compatibility
> modes supported by the host processor for nested guests.
>
> > diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
> > index 00302399fc37b..8d6632c64ca5f 100644
> > --- a/arch/powerpc/kvm/powerpc.c
> > +++ b/arch/powerpc/kvm/powerpc.c
> > @@ -697,6 +697,13 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
> > }
> > }
> > break;
> > +#if defined(CONFIG_KVM_BOOK3S_HV_POSSIBLE)
> > + case KVM_CAP_PPC_COMPAT_CAPS:
> > + r = 0;
> > + if (kvmhv_on_pseries())
> > + r = 1;
> > + break;
>
> [Severity: Medium]
> Is this capability check fully aligned with the ioctl's availability?
>
> This check returns 1 on a pseries host using PR KVM (since it misses the
> hv_enabled check), but the ioctl might fail with -ENOTTY if the backend
> is missing.
Looking closely, it looks like a good catch. PPC kernels can be built
both KVM-PR and as well KVM-HV config enabled. Though at one point in
time only one of kvm-pr and kvm-hv can be loaded, a PR KVM guest on a
pseries system can see cap=1 but then get -ENOTTY from the ioctl
(thought the documentation explicitly covers this case: "ENOTTY if the
backend does not implement the get_compat_caps operation (e.g., on
non-HV KVM implementations). But anyway, I'll fix in v7:
case KVM_CAP_PPC_COMPAT_CAPS:
r = 0;
if (hv_enabled && kvmhv_on_pseries())
r = 1;
break;
>
> Later in the ioctl execution, it succeeds on a bare-metal host using HV KVM
> (missing the kvmhv_on_pseries() check) even though this capability check
> would return 0.
On bare-metal, kvmhv_on_pseries() is false (CPU_FTR_HVMODE is set), so
the cap correctly returns 0 there regardless of hv_enabled. The ioctl is
only meaningful on pseries (PAPR guests) where KVM acts as L1 under a
hypervisor, which is why both conditions are required
>
> Could this decoupling between the capability and the ioctl availability break
> capability negotiation for userspace?
>
> > +#endif /* CONFIG_KVM_BOOK3S_HV_POSSIBLE */
> > default:
> > r = 0;
> > break;
>
> [ ... ]
>
> > @@ -2463,6 +2470,70 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
> > r = kvm->arch.kvm_ops->svm_off(kvm);
> > break;
> > }
> > + case KVM_PPC_GET_COMPAT_CAPS: {
> > + struct kvm_ppc_compat_caps host_caps = {};
> > + u64 usize;
> > +
> > + /*
> > + * Read the size field first to drive copy_struct_from_user.
> > + * size must be the first field of the struct.
> > + */
> > + r = -EFAULT;
> > + if (get_user(usize, (__u64 __user *)argp))
> > + goto out;
> > +
> > + /*
> > + * Enforce a minimum: reject buffers smaller than the initial
> > + * struct version (VER0). This allows old userspace compiled
> > + * against the original struct to still work on a newer kernel
> > + * that has grown the struct with appended fields.
> > + */
> > + r = -EINVAL;
> > + if (usize < KVM_PPC_COMPAT_CAPS_SIZE_VER0)
> > + goto out;
> > +
> > + /*
> > + * New userspace with a larger struct called an older kernel.
> > + * Write back ksize in host_caps.size so userspace knows which
> > + * older struct to retry with, then fail with -E2BIG.
> > + */
> > + if (usize > sizeof(host_caps)) {
> > + host_caps.size = sizeof(host_caps);
> > + r = -EFAULT;
> > + if (put_user(host_caps.size, (__u64 __user *)argp))
> > + goto out;
> > + r = -E2BIG;
> > + goto out;
> > + }
>
> [Severity: High]
> Does explicitly rejecting larger structs here bypass the standard UAPI
> zero-checking?
The pre-check `usize > sizeof(host_caps)` is required, not a bypass. The
-E2BIG path writes back ksize so userspace can discover the kernel's
size and retry explicitly. Userspace that retries with the smaller size
is making a deliberate choice to use the older interface; the kernel
cannot have seen the truncated extra fields, so there is nothing
silently ignored. copy_struct_from_user() itself would also return
-E2BIG for non-zero trailing bytes — but it cannot be called safely with
an arbitrary usize against a fixed-size kernel struct.
>
> By catching usize > sizeof(host_caps) early and returning -E2BIG, the code
> bypasses copy_struct_from_user()'s built-in validation which would safely
> reject non-zero extended fields.
>
> If userspace receives the smaller kernel size and retries by truncating its
> buffer size, the kernel will only read the truncated portion, silently
> ignoring any non-zero extended fields that userspace originally provided.
>
> Should this rely on copy_struct_from_user() to safely check zeroed trailing
> bytes instead?
>
> > +
> > + /*
> > + * copy_struct_from_user() handles forward/backward compat:
> > + * usize == ksize: verbatim copy
> > + * usize < ksize: zero-pad trailing (old userspace, new kernel)
> > + */
> > + r = copy_struct_from_user(&host_caps, sizeof(host_caps),
> > + argp, usize);
> > + if (r)
> > + goto out;
> > +
> > + /* Reserved fields must be zero */
> > + r = -EINVAL;
> > + if (host_caps.flags)
> > + goto out;
> > +
> > + r = -ENOTTY;
> > + if (!kvm->arch.kvm_ops->get_compat_caps)
> > + goto out;
> > +
> > + r = kvm->arch.kvm_ops->get_compat_caps(&host_caps);
> > + if (r)
> > + goto out;
> > +
> > + host_caps.size = sizeof(host_caps);
> > + r = copy_struct_to_user(argp, usize, &host_caps,
> > + sizeof(host_caps), NULL);
>
> [Severity: High]
> Can this artificial size inflation cause an out-of-bounds read/write if
> userspace reuses the struct?
>
> If an older userspace passes a smaller struct to a newer kernel (where
> usize < sizeof(host_caps)), the kernel sets host_caps.size to its own larger
> size. It then copies the smaller usize bytes back, overwriting the userspace
> size field with the kernel's larger size.
>
> If userspace reuses this struct for a subsequent ioctl call, it will now pass
> the larger size. The kernel would then read past the end of the originally
> allocated userspace buffer, and if successful, write back past the end
> as well.
Not a bug. `copy_struct_to_user(argp, usize, &host_caps,
sizeof(host_caps), NULL)` copies min(usize, ksize) bytes back to
userspace. Today usize == ksize == 24, so exactly 24 bytes are written.
In a future kernel where ksize grows, the function correctly copies only
usize bytes (old userspace case), meaning userspace sees its own size
field reflected back — not the kernel's larger size. The kernel sets
host_caps.size = sizeof(host_caps) in the kernel-side copy so that the
output `size` field documents the kernel's struct version when it is
within the copied range, which is the designed semantics for versioned
structs. No out-of-bounds access occurs.
>
> > + break;
> > + }
> > default: {
> > struct kvm *kvm = filp->private_data;
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=1
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM
2026-08-04 18:21 ` sashiko-bot
@ 2026-08-06 16:09 ` Amit Machhiwal
0 siblings, 0 replies; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-06 16:09 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Amit Machhiwal, kvm
On 2026/08/04 06:21 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [Medium] Mismatch between KVM_CAP_PPC_COMPAT_CAPS advertisement and ioctl implementation for unsupported environments.
> --
>
> --- Patch [2]: [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM ---
> commit 8305652489744988576b7fa55e0424452c48a633
> Author: Amit Machhiwal <amachhiw@linux.ibm.com>
>
> KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM
>
> This commit adds support for retrieving host CPU compatibility capabilities
> for nested guests on PowerVM. The capability bitmap is retrieved from the
> cached nested_capabilities value and exposed through the new
> KVM_PPC_GET_COMPAT_CAPS ioctl.
>
> > diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> > index 61dbeea317f3b..8799124b80960 100644
> > --- a/arch/powerpc/kvm/book3s_hv.c
> > +++ b/arch/powerpc/kvm/book3s_hv.c
>
> [ ... ]
>
> > @@ -6510,6 +6510,25 @@ static bool kvmppc_hash_v3_possible(void)
> > return true;
> > }
> >
> > +
> > +static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
> > +{
> > + unsigned long capabilities = 0;
> > + long rc = -EINVAL;
> > +
> > + if (kvmhv_on_pseries()) {
> > + if (kvmhv_is_nestedv2()) {
> > + WARN_ON_ONCE(!nested_capabilities);
> > + capabilities = nested_capabilities;
> > + rc = 0;
> > + }
> > + }
> > +
> > + host_caps->compat_capabilities = capabilities & KVM_PPC_COMPAT_BITMASK;
> > +
> > + return rc;
> > +}
>
> [Severity: Medium]
> Will this return -EINVAL for pseries hosts when nestedv1 is used?
This is analysing patch 2 in isolation. The series is applied in order:
patch 3 adds the nestedv1 (KVM on PowerNV) path to
kvmppc_get_compat_caps(), filling in the `else` branch for the case
where kvmhv_is_nestedv2() is false. After the full series is applied, a
pseries nestedv1 host takes the DT-based path added in patch 3, not the
-EINVAL path. There is no issue in the complete series.
>
> If KVM_CAP_PPC_COMPAT_CAPS advertises support by returning 1 for all pseries
> hosts (which appears to be the case in kvm_vm_ioctl_check_extension),
> userspace might query KVM_PPC_GET_COMPAT_CAPS and hit this path when
> kvmhv_is_nestedv2() is false.
>
> For example, if userspace checks KVM_CAP_PPC_COMPAT_CAPS and gets a positive
> result, but kvmhv_is_nestedv2() returns false here, we return -EINVAL.
>
> Since -EINVAL typically indicates invalid structure size or bad flags, could
> userspace fail to differentiate an unsupported backend from invalid inputs,
> leading to initialization failures?
>
> Should this gracefully return 0 capabilities (or -ENOTTY), or should the
> capability check itself verify kvmhv_is_nestedv2() before advertising support?
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=2
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV
2026-08-04 18:27 ` sashiko-bot
@ 2026-08-06 16:13 ` Amit Machhiwal
0 siblings, 0 replies; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-06 16:13 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Amit Machhiwal, kvm
On 2026/08/04 06:27 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] `kvmppc_get_compat_caps()` incorrectly returns `-EINVAL` when the 'cpu-version' property is absent, breaking the `KVM_CAP_PPC_COMPAT_CAPS` contract.
> --
>
> --- Patch [3]: [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV ---
> commit b4de9c28bb9d6eeb95ed5310169709b332b6f664
> Author: Amit Machhiwal <amachhiw@linux.ibm.com>
>
> KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV
>
> This commit extends host CPU compatibility capability reporting to support
> nested virtualization on PowerNV systems. For nested API v1, it derives
> compatibility capabilities from the L1 guest by reading the cpu-version
> property from the device tree and maps it to the corresponding compatibility
> capability bitmap.
>
> > diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
> > index 8799124b80960..77558f6eed864 100644
> > --- a/arch/powerpc/kvm/book3s_hv.c
> > +++ b/arch/powerpc/kvm/book3s_hv.c
>
> [ ... ]
>
> > static int kvmppc_get_compat_caps(struct kvm_ppc_compat_caps *host_caps)
> > {
> > + struct device_node *np;
> > unsigned long capabilities = 0;
> > long rc = -EINVAL;
> > + u32 cpu_version = 0;
> >
> > if (kvmhv_on_pseries()) {
> > if (kvmhv_is_nestedv2()) {
> > WARN_ON_ONCE(!nested_capabilities);
> > capabilities = nested_capabilities;
> > rc = 0;
> > + } else {
> > + for_each_node_by_type(np, "cpu") {
> > + if (!of_property_read_u32(np, "cpu-version",
> > + &cpu_version)) {
> > + of_node_put(np);
> > + break;
> > + }
> > + }
> > + if (!cpu_version)
> > + return -EINVAL;
>
> [Severity: High]
> If an L1 guest is booted in native mode (e.g. without a 'compat=' setting in
> QEMU), the cpu-version property is intentionally omitted from the device
> tree.
>
> Doesn't returning -EINVAL here cause KVM_PPC_GET_COMPAT_CAPS to fail,
> thereby breaking nested virtualization initialization for native-mode L1
> guests?
>
> Could this fall back to deriving capabilities from the physical native PVR
> instead of returning an error?
The premise is incorrect for the context where this code runs. This code
path is guarded by kvmhv_on_pseries(), which is true only when the
kernel is running as a PAPR guest (under PHYP or KVM on PowerNV acting
as L0). In that context, the `cpu-version` property in the guest DT is
always populated by the hypervisor (PHYP or QEMU) with a logical PVR
value including for native-mode guests. This is standard PAPR firmware
behavior and is documented in the PAPR specification.
For KVM on PowerNV (L0), the L1 guest's DT is built by QEMU which sets
cpu-version to the negotiated CPU version. For PHYP-managed LPARs, PHYP
always provides cpu-version regardless of whether the guest is in compat
mode or native mode.
The `if (!cpu_version) return -EINVAL` guard handles only the case where
of_property_read_u32() fails and leaves cpu_version at its 0
initialisation value — which would indicate an unexpected firmware or DT
construction error, not a normal native-mode guest scenario.
>
> > + rc = kvmppc_map_compat_capabilities(cpu_version,
> > + &capabilities);
> > }
> > }
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=3
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
2026-08-04 18:27 ` sashiko-bot
@ 2026-08-06 16:15 ` Amit Machhiwal
0 siblings, 0 replies; 18+ messages in thread
From: Amit Machhiwal @ 2026-08-06 16:15 UTC (permalink / raw)
To: sashiko-reviews; +Cc: Amit Machhiwal, kvm
On 2026/08/04 06:27 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] Unconditional rejection of larger structs breaks the forward compatibility mechanism of copy_struct_from_user().
> - [High] Overwriting the userspace size field with the kernel's struct size creates dangerous ambiguities on success.
> --
>
> --- Patch [4]: [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl ---
> commit 5d4e2edcf1688edc6d21e5f2463ef8b58bd3d0a7
> Author: Amit Machhiwal <amachhiw@linux.ibm.com>
>
> KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl
>
> Add documentation for the KVM_PPC_GET_COMPAT_CAPS ioctl to the KVM API
> documentation. The documentation covers error code descriptions including
> E2BIG for forward compatibility and the extensible size-based versioning
> contract.
>
> > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
> > index e3003a241d5b0..22fedb0aa34b4 100644
> > --- a/Documentation/virt/kvm/api.rst
> > +++ b/Documentation/virt/kvm/api.rst
> > @@ -6566,6 +6566,85 @@ KVM_S390_KEYOP_SSKE
> > Sets the storage key for the guest address ``guest_addr`` to the key
> > specified in ``key``, returning the previous value in ``key``.
> >
> > +4.145 KVM_PPC_GET_COMPAT_CAPS
> > +-----------------------------
> > +:Capability: KVM_CAP_PPC_COMPAT_CAPS
> > +:Architectures: powerpc
> > +:Type: vm ioctl
> > +:Parameters: struct kvm_ppc_compat_caps (in/out)
> > +:Returns: 0 on success, negative value on failure
> > +
> > +Errors include:
> > +
> > + ======== ============================================================
> > + EFAULT if ``struct kvm_ppc_compat_caps`` cannot be read from or
> > + written to userspace
> > + EINVAL if the ``size`` field is smaller than
> > + ``KVM_PPC_COMPAT_CAPS_SIZE_VER0``, if the ``flags`` field
> > + is non-zero, or if the backend fails to retrieve or map
> > + CPU compatibility capabilities
> > + E2BIG if ``size`` is larger than the kernel's struct size
> > + (new userspace on old kernel); the kernel writes back its
> > + own struct size into the ``size`` field so userspace can
> > + retry with the correct size
>
> [Severity: High]
> Does explicitly rejecting a larger struct size with -E2BIG break the standard
> forward compatibility mechanism of copy_struct_from_user()?
These are the same concerns raised on patch 1/4 — please see the
response there. In summary: the pre-check is necessary for
stack-allocated structs, and the size field update follows the
documented versioning contract for extensible structs.
>
> Extensible struct UAPIs are designed to allow newer userspace to run seamlessly
> on older kernels as long as new fields are zeroed.
>
> Looking at arch/powerpc/kvm/powerpc.c in kvm_arch_vm_ioctl(), the code
> short-circuits the native trailing-zero check in copy_struct_from_user():
>
> if (usize > sizeof(host_caps)) {
> host_caps.size = sizeof(host_caps);
> r = -EFAULT;
> if (put_user(host_caps.size, (__u64 __user *)argp))
> goto out;
> r = -E2BIG;
> goto out;
> }
>
> This forces userspace to implement fallback retry loops instead of relying on
> the kernel's native UAPI extensibility.
>
> [ ... ]
>
> > +Before calling this ioctl, userspace must set the ``size`` field to
> > +``sizeof(struct kvm_ppc_compat_caps)`` and zero the ``flags`` field.
> > +The kernel rejects non-zero ``flags`` with ``-EINVAL`` to prevent
> > +uninitialized stack values from being silently accepted, keeping the
> > +field available for future use without ABI ambiguity.
> > +
> > +The ioctl uses ``copy_struct_from_user()`` and ``copy_struct_to_user()``
> > +to support extensible versioning: if userspace passes a struct smaller
> > +than the current kernel version (``size >= KVM_PPC_COMPAT_CAPS_SIZE_VER0``),
> > +the kernel zero-pads unknown trailing fields. If userspace passes a larger
> > +struct (``size > sizeof(struct kvm_ppc_compat_caps)``), the kernel writes
> > +back its own struct size into the ``size`` field and returns ``-E2BIG``,
> > +allowing userspace to discover the kernel's struct size and retry.
>
> [Severity: High]
> Can overwriting the userspace size field with the kernel's struct size create
> dangerous ambiguities on success?
>
> If userspace passes a smaller struct (e.g., 24 bytes) and the kernel uses a
> larger struct (e.g., 32 bytes), the kernel updates host_caps.size to 32 and
> copies 24 bytes back to userspace.
>
> Looking at arch/powerpc/kvm/powerpc.c in kvm_arch_vm_ioctl():
>
> host_caps.size = sizeof(host_caps);
> r = copy_struct_to_user(argp, usize, &host_caps,
> sizeof(host_caps), NULL);
>
> Userspace would receive a success code (0) but its size field is now 32. This
> falsely indicates to userspace that the kernel provided 32 bytes of valid data,
> which can lead to out-of-bounds reads if userspace trusts the returned size
> field to determine valid data bounds within its buffer.
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260804180705.59160-1-amachhiw@linux.ibm.com?part=4
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2026-08-06 16:14 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-04 18:07 [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 1/4] KVM: PPC: Introduce KVM_CAP_PPC_COMPAT_CAPS and wire up ioctl Amit Machhiwal
2026-08-04 18:19 ` sashiko-bot
2026-08-06 16:07 ` Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 2/4] KVM: PPC: Book3S HV: Implement compat CPU capability retrieval for KVM on PowerVM Amit Machhiwal
2026-08-04 18:21 ` sashiko-bot
2026-08-06 16:09 ` Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 3/4] KVM: PPC: Book3S HV: Add support for compat CPU capabilities for KVM on PowerNV Amit Machhiwal
2026-08-04 18:27 ` sashiko-bot
2026-08-06 16:13 ` Amit Machhiwal
2026-08-04 18:07 ` [PATCH v6 4/4] KVM: PPC: Document KVM_PPC_GET_COMPAT_CAPS ioctl Amit Machhiwal
2026-08-04 18:27 ` sashiko-bot
2026-08-06 16:15 ` Amit Machhiwal
2026-08-05 4:32 ` [PATCH v6 0/4] KVM: PPC: Expose CPU compatibility modes for nested guests Anushree Mathur
2026-08-05 18:39 ` Ritesh Harjani
2026-08-06 5:33 ` Amit Machhiwal
2026-08-06 13:05 ` Ritesh Harjani
2026-08-06 14:58 ` Amit Machhiwal
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox