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 obtained from the hypervisor via 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. Introduce a helper to translate CPU version values into compatibility capability bits and integrate it into kvmppc_get_compat_cpu_caps(). This allows userspace to query host CPU compatibility modes on both PowerVM and PowerNV platforms via the KVM_PPC_GET_COMPAT_CAPS ioctl. Signed-off-by: Amit Machhiwal --- arch/powerpc/kvm/book3s_hv.c | 37 +++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 38de7040e2b7..18774c49af85 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -6522,15 +6522,50 @@ static bool kvmppc_hash_v3_possible(void) return true; } +static int kvmppc_map_compat_capabilities(const __be32 cpu_version, + unsigned long *capabilities) +{ + switch (cpu_version) { + case PVR_ARCH_31_P11: + *capabilities |= H_GUEST_CAP_POWER11; + break; + case PVR_ARCH_31: + *capabilities |= H_GUEST_CAP_POWER10; + break; + case PVR_ARCH_300: + *capabilities |= H_GUEST_CAP_POWER9; + break; + default: + return -EINVAL; + } + + return 0; +} static int kvmppc_get_compat_cpu_caps(struct kvm_ppc_compat_caps *host_caps) { + struct device_node *np; unsigned long capabilities = 0; + const __be32 *prop = NULL; long rc = -EINVAL; + u32 cpu_version; if (kvmhv_on_pseries()) { - if (kvmhv_is_nestedv2()) + if (kvmhv_is_nestedv2()) { rc = plpar_guest_get_capabilities(0, &capabilities); + } else { + for_each_node_by_type(np, "cpu") { + prop = of_get_property(np, "cpu-version", NULL); + if (prop) { + cpu_version = be32_to_cpup(prop); + break; + } + } + if (!prop) + return -EINVAL; + rc = kvmppc_map_compat_capabilities(cpu_version, + &capabilities); + } host_caps->compat_capabilities = capabilities; } -- 2.50.1 (Apple Git-155)