[PATCH v4 0/3] ppc/kvm: Handle CPU compatibility mode correctly for nested guests

Amit Machhiwal posted 3 patches 3 weeks, 4 days ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260701052341.62289-1-amachhiw@linux.ibm.com
Maintainers: Nicholas Piggin <npiggin@gmail.com>, Harsh Prateek Bora <harshpb@linux.ibm.com>, "Michael S. Tsirkin" <mst@redhat.com>, Cornelia Huck <cohuck@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Chinmay Rath <rathc@linux.ibm.com>, Glenn Miles <milesg@linux.ibm.com>
hw/ppc/spapr_hcall.c            | 14 ++++++
linux-headers/asm-powerpc/kvm.h | 20 ++++++++
linux-headers/linux/kvm.h       |  4 ++
target/ppc/kvm.c                | 87 +++++++++++++++++++++++++++++++++
target/ppc/kvm_ppc.h            |  7 +++
5 files changed, 132 insertions(+)
[PATCH v4 0/3] ppc/kvm: Handle CPU compatibility mode correctly for nested guests
Posted by Amit Machhiwal 3 weeks, 4 days ago
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 issues for nested virtualization. When booting a nested KVM
guest, QEMU may derive the CPU model from the raw hardware PVR and attempt
to configure the guest accordingly. However, the host is constrained by the
compatibility level negotiated with the hypervisor, and requests exceeding
that level are rejected by KVM, leading to guest boot failures such as:

  KVM-NESTEDv2: couldn't set guest wide elements

This series addresses the issue by preventing fallback to raw mode when the
host itself is booted in a compatibility mode, and by querying the effective
CPU compatibility modes supported by the host via KVM. The kernel interface
uses copy_struct_from/to_user() for forward and backward ABI compatibility.
With these changes, QEMU ensures that nested guests are configured with CPU
models consistent with the host compatibility mode, allowing them to boot
correctly.

Patch summary:
  [1/3] [DO_NOT_MERGE] linux-headers: Add uapi header changes
  [2/3] target/ppc/kvm: Add support for querying host compatibility mode
  [3/3] target/ppc/kvm: Use host compatibility mode for nested guests

Changes in v4 (based on review from Vaibhav):
- Patch 1: Updated to match kernel v5: ioctl kept as _IO (not _IOWR) so
  the ioctl number remains stable if the struct grows; the size field is
  read first by the kernel via get_user() before copy_struct_from_user().
  [Vaibhav, Amit]

- Patch 2: Replaced fprintf(stderr, ...) with error_report() for error
  reporting in kvmppc_get_compat_caps(). Replaced __builtin_ctzll() with
  portable ctz64(). Simplified kvm_ppc_host_compat_pvr() to switch directly
  on the capability bit value instead of a derived index, removing the
  KVM_PPC_COMPAT_CAP_P*_IDX defines from kvm_ppc.h. Dropped the post-ioctl
  size mismatch check which is no longer meaningful with the
  copy_struct_from/to_user() model. Added a function comment to
  kvm_ppc_host_compat_pvr(). [Vaibhav, Amit]
  Guard the kvm_ppc_host_compat_pvr() call in cas_check_pvr() with
  kvm_enabled() to prevent a segfault when QEMU is built with CONFIG_KVM=y
  but run as a TCG guest (kvm_state is NULL in that case).

- Patch 3: Added a #ifndef CONFIG_KVM compile-time assertion inside the
  TARGET_PPC64 guard as a sanity check. No functional changes.

Changes in v3 (based on review from Vaibhav):
- Patch 1: Moved compatibility mode check from do_client_architecture_support()
  to cas_check_pvr(). Instead of error handling when KVM rejects compat mode,
  now prevents raw mode fallback when host is booted in compatibility mode.
  This ensures guests cannot exceed the host's compatibility level.

- Patch 2: Added size field to kvm_ppc_compat_caps structure for ABI
  versioning. Changed flags field from __u32 to __u64. Added capability bit
  definitions (KVM_PPC_COMPAT_CAP_POWER9/10/11) and KVM_PPC_COMPAT_BITMASK.

- Patch 3: Added size field initialization and validation in
  kvmppc_get_compat_caps() to ensure ABI compatibility between QEMU and
  kernel. Changed from H_GUEST_CAP_* constants to KVM_PPC_COMPAT_CAP_*
  constants. Added capability masking with KVM_PPC_COMPAT_BITMASK.

- Dropped Tested-by from Anushree due to code changes in v3.

Changes in v2:
- Patch 3: Guard compatibility mode code with #if defined(TARGET_PPC64)
  to fix compilation for ppc32 targets. The POWER9/10/11 PVR constants
  are only defined for 64-bit builds, and compatibility modes are only
  relevant for 64-bit systems.

Testing (with kernel v5 patches):

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)

CI test results: https://gitlab.com/amachhiw/qemu/-/pipelines/2641423050

Note: Patch 1 is marked DO_NOT_MERGE as it contains linux-headers updates
that will be synced separately once the corresponding kernel patches are
merged.

The corresponding Linux kernel patches (v5) are being posted concurrently.

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 kernel patch versions:
v5: https://lore.kernel.org/all/20260701051409.51820-1-amachhiw@linux.ibm.com/
v4: https://lore.kernel.org/all/20260616123314.82721-1-amachhiw@linux.ibm.com/
v3: https://lore.kernel.org/all/20260522152744.55251-1-amachhiw@linux.ibm.com/
v2: https://lore.kernel.org/all/20260513100755.83195-1-amachhiw@linux.ibm.com/
v1: https://lore.kernel.org/all/20260430054906.94401-1-amachhiw@linux.ibm.com/

Amit Machhiwal (3):
  linux-headers: Add uapi header changes
  target/ppc/kvm: Add support for querying host compatibility mode
  target/ppc/kvm: Use host compatibility mode for nested guests

 hw/ppc/spapr_hcall.c            | 14 ++++++
 linux-headers/asm-powerpc/kvm.h | 20 ++++++++
 linux-headers/linux/kvm.h       |  4 ++
 target/ppc/kvm.c                | 87 +++++++++++++++++++++++++++++++++
 target/ppc/kvm_ppc.h            |  7 +++
 5 files changed, 132 insertions(+)


base-commit: 30e8a06b64aa58a3990ba39cb5d09531e7d265e0
-- 
2.50.1 (Apple Git-155)