[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <376d0c37d0cf4d578fe13be6f2b3599a694040af.camel@redhat.com>
Date: Thu, 04 Jul 2024 21:32:19 -0400
From: Maxim Levitsky <mlevitsk@...hat.com>
To: Sean Christopherson <seanjc@...gle.com>, Paolo Bonzini
<pbonzini@...hat.com>, Vitaly Kuznetsov <vkuznets@...hat.com>
Cc: kvm@...r.kernel.org, linux-kernel@...r.kernel.org, Hou Wenlong
<houwenlong.hwl@...group.com>, Kechen Lu <kechenl@...dia.com>, Oliver Upton
<oliver.upton@...ux.dev>, Binbin Wu <binbin.wu@...ux.intel.com>, Yang
Weijiang <weijiang.yang@...el.com>, Robert Hoo <robert.hoo.linux@...il.com>
Subject: Re: [PATCH v2 27/49] KVM: x86: Swap incoming guest CPUID into vCPU
before massaging in KVM_SET_CPUID2
On Fri, 2024-05-17 at 10:39 -0700, Sean Christopherson wrote:
> When handling KVM_SET_CPUID{,2}, swap the old and new CPUID arrays and
> lengths before processing the new CPUID, and simply undo the swap if
> setting the new CPUID fails for whatever reason.
>
> To keep the diff reasonable, continue passing the entry array and length
> to most helpers, and defer the more complete cleanup to future commits.
>
> For any sane VMM, setting "bad" CPUID state is not a hot path (or even
> something that is surviable), and setting guest CPUID before it's known
> good will allow removing all of KVM's infrastructure for processing CPUID
> entries directly (as opposed to operating on vcpu->arch.cpuid_entries).
>
> Signed-off-by: Sean Christopherson <seanjc@...gle.com>
> ---
> arch/x86/kvm/cpuid.c | 49 +++++++++++++++++++++++++++-----------------
> 1 file changed, 30 insertions(+), 19 deletions(-)
>
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 33e3e77de1b7..4ad01867cb8d 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -175,10 +175,10 @@ static inline struct kvm_cpuid_entry2 *cpuid_entry2_find(
> return NULL;
> }
>
> -static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
> - struct kvm_cpuid_entry2 *entries,
> - int nent)
> +static int kvm_check_cpuid(struct kvm_vcpu *vcpu)
> {
> + struct kvm_cpuid_entry2 *entries = vcpu->arch.cpuid_entries;
> + int nent = vcpu->arch.cpuid_nent;
> struct kvm_cpuid_entry2 *best;
> u64 xfeatures;
>
> @@ -369,9 +369,11 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
> }
> EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);
>
> -static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
> +static bool kvm_cpuid_has_hyperv(struct kvm_vcpu *vcpu)
> {
> #ifdef CONFIG_KVM_HYPERV
> + struct kvm_cpuid_entry2 *entries = vcpu->arch.cpuid_entries;
> + int nent = vcpu->arch.cpuid_nent;
> struct kvm_cpuid_entry2 *entry;
>
> entry = cpuid_entry2_find(entries, nent, HYPERV_CPUID_INTERFACE,
> @@ -436,8 +438,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
> __cr4_reserved_bits(guest_cpuid_has, vcpu);
> #undef __kvm_cpu_cap_has
>
> - kvm_hv_set_cpuid(vcpu, kvm_cpuid_has_hyperv(vcpu->arch.cpuid_entries,
> - vcpu->arch.cpuid_nent));
> + kvm_hv_set_cpuid(vcpu, kvm_cpuid_has_hyperv(vcpu));
>
> /* Invoke the vendor callback only after the above state is updated. */
> static_call(kvm_x86_vcpu_after_set_cpuid)(vcpu);
> @@ -478,6 +479,15 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
> {
> int r;
>
> + /*
> + * Swap the existing (old) entries with the incoming (new) entries in
> + * order to massage the new entries, e.g. to account for dynamic bits
> + * that KVM controls, without clobbering the current guest CPUID, which
> + * KVM needs to preserve in order to unwind on failure.
> + */
> + swap(vcpu->arch.cpuid_entries, e2);
> + swap(vcpu->arch.cpuid_nent, nent);
> +
> /*
> * KVM does not correctly handle changing guest CPUID after KVM_RUN, as
> * MAXPHYADDR, GBPAGES support, AMD reserved bit behavior, etc.. aren't
> @@ -497,31 +507,25 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
> * only because any change in CPUID is disallowed, i.e. using
> * stale data is ok because KVM will reject the change.
> */
> - __kvm_update_cpuid_runtime(vcpu, e2, nent);
> + kvm_update_cpuid_runtime(vcpu);
>
> r = kvm_cpuid_check_equal(vcpu, e2, nent);
> if (r)
> - return r;
> -
> - kvfree(e2);
> - return 0;
> + goto err;
> + goto success;
> }
>
> #ifdef CONFIG_KVM_HYPERV
> - if (kvm_cpuid_has_hyperv(e2, nent)) {
> + if (kvm_cpuid_has_hyperv(vcpu)) {
> r = kvm_hv_vcpu_init(vcpu);
> if (r)
> - return r;
> + goto err;
> }
> #endif
>
> - r = kvm_check_cpuid(vcpu, e2, nent);
> + r = kvm_check_cpuid(vcpu);
> if (r)
> - return r;
> -
> - kvfree(vcpu->arch.cpuid_entries);
> - vcpu->arch.cpuid_entries = e2;
> - vcpu->arch.cpuid_nent = nent;
> + goto err;
>
> vcpu->arch.kvm_cpuid = kvm_get_hypervisor_cpuid(vcpu, KVM_SIGNATURE);
> #ifdef CONFIG_KVM_XEN
> @@ -529,7 +533,14 @@ static int kvm_set_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid_entry2 *e2,
> #endif
> kvm_vcpu_after_set_cpuid(vcpu);
>
> +success:
> + kvfree(e2);
> return 0;
> +
> +err:
> + swap(vcpu->arch.cpuid_entries, e2);
> + swap(vcpu->arch.cpuid_nent, nent);
> + return r;
> }
>
> /* when an old userspace process fills a new kernel module */
Hi,
This IMHO is a good idea. You might consider moving this patch to the beginning of the patch series though,
it will make more sense with the rest of the patches there.
Reviewed-by: Maxim Levitsky <mlevitsk@...hat.com>
Best regards,
Maxim Levitsky
Powered by blists - more mailing lists