[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250401161106.790710-25-pbonzini@redhat.com>
Date: Tue, 1 Apr 2025 18:11:01 +0200
From: Paolo Bonzini <pbonzini@...hat.com>
To: linux-kernel@...r.kernel.org,
kvm@...r.kernel.org
Cc: roy.hopkins@...e.com,
seanjc@...gle.com,
thomas.lendacky@....com,
ashish.kalra@....com,
michael.roth@....com,
jroedel@...e.de,
nsaenz@...zon.com,
anelkz@...zon.de,
James.Bottomley@...senPartnership.com
Subject: [PATCH 24/29] KVM: x86: initialize CPUID for non-default planes
Copy the initial CPUID from plane 0. To avoid mismatches, block
KVM_SET_CPUID{,2} after KVM_CREATE_VCPU_PLANE similar to how it is
blocked after KVM_RUN; this is handled by a tiny bit of architecture
independent code.
Signed-off-by: Paolo Bonzini <pbonzini@...hat.com>
---
Documentation/virt/kvm/api.rst | 4 +++-
arch/x86/kvm/cpuid.c | 19 ++++++++++++++++++-
arch/x86/kvm/cpuid.h | 1 +
arch/x86/kvm/x86.c | 7 ++++++-
include/linux/kvm_host.h | 1 +
virt/kvm/kvm_main.c | 1 +
6 files changed, 30 insertions(+), 3 deletions(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 16d836b954dc..3739d16b7164 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -736,7 +736,9 @@ Caveat emptor:
configuration (if there is) is not corrupted. Userspace can get a copy
of the resulting CPUID configuration through KVM_GET_CPUID2 in case.
- Using KVM_SET_CPUID{,2} after KVM_RUN, i.e. changing the guest vCPU model
- after running the guest, may cause guest instability.
+ after running the guest, is forbidden; so is using the ioctls after
+ KVM_CREATE_VCPU_PLANE, because all planes must have the same CPU
+ capabilities.
- Using heterogeneous CPUID configurations, modulo APIC IDs, topology, etc...
may cause guest instability.
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 142decb3a736..44e6d4989bdd 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -545,7 +545,7 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
* KVM_SET_CPUID{,2} again. To support this legacy behavior, check
* whether the supplied CPUID data is equal to what's already set.
*/
- if (kvm_vcpu_has_run(vcpu)) {
+ if (kvm_vcpu_has_run(vcpu) || vcpu->has_planes) {
r = kvm_cpuid_check_equal(vcpu, e2, nent);
if (r)
goto err;
@@ -567,6 +567,23 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
return r;
}
+int kvm_dup_cpuid(struct kvm_vcpu *vcpu, struct kvm_vcpu *source)
+{
+ if (WARN_ON_ONCE(vcpu->arch.cpuid_entries || vcpu->arch.cpuid_nent))
+ return -EEXIST;
+
+ vcpu->arch.cpuid_entries = kmemdup(source->arch.cpuid_entries,
+ source->arch.cpuid_nent * sizeof(struct kvm_cpuid_entry2),
+ GFP_KERNEL_ACCOUNT);
+ if (!vcpu->arch.cpuid_entries)
+ return -ENOMEM;
+
+ memcpy(vcpu->arch.cpu_caps, source->arch.cpu_caps, sizeof(source->arch.cpu_caps));
+ vcpu->arch.cpuid_nent = source->arch.cpuid_nent;
+
+ return 0;
+}
+
/* when an old userspace process fills a new kernel module */
int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
struct kvm_cpuid *cpuid,
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 05cc1245f570..a5983c635a70 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -42,6 +42,7 @@ static inline struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcp
int kvm_dev_ioctl_get_cpuid(struct kvm_cpuid2 *cpuid,
struct kvm_cpuid_entry2 __user *entries,
unsigned int type);
+int kvm_dup_cpuid(struct kvm_vcpu *vcpu, struct kvm_vcpu *source);
int kvm_post_set_cpuid(struct kvm_vcpu *vcpu);
int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
struct kvm_cpuid *cpuid,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d2b43d9b6543..be4d7b97367b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -12412,6 +12412,11 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu, struct kvm_plane *plane)
if (plane->plane) {
page = NULL;
vcpu->arch.pio_data = vcpu->plane0->arch.pio_data;
+ r = kvm_dup_cpuid(vcpu, vcpu->plane0);
+ if (r < 0)
+ goto fail_free_lapic;
+
+ r = -ENOMEM;
} else {
page = alloc_page(GFP_KERNEL_ACCOUNT | __GFP_ZERO);
if (!page)
@@ -12459,7 +12464,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu, struct kvm_plane *plane)
kvm_xen_init_vcpu(vcpu);
vcpu_load(vcpu);
- kvm_vcpu_after_set_cpuid(vcpu);
+ WARN_ON_ONCE(kvm_post_set_cpuid(vcpu));
kvm_set_tsc_khz(vcpu, vcpu->kvm->arch.default_tsc_khz);
kvm_vcpu_reset(vcpu, false);
kvm_init_mmu(vcpu);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 5cade1c04646..0b764951f461 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -344,6 +344,7 @@ struct kvm_vcpu {
struct mutex mutex;
/* Only valid on plane 0 */
+ bool has_planes;
bool wants_to_run;
/* Shared for all planes */
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index db38894f6fa3..3a04fdf0865d 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4182,6 +4182,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm_plane *plane, struct kvm_vcpu *pl
if (plane->plane) {
page = NULL;
vcpu->run = plane0_vcpu->run;
+ plane0_vcpu->has_planes = true;
} else {
WARN_ON(plane0_vcpu != NULL);
plane0_vcpu = vcpu;
--
2.49.0
Powered by blists - more mailing lists