Re: [PATCH v2 40/49] KVM: x86: Initialize guest cpu_caps based on KVM support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2024-07-08 at 17:10 -0700, Sean Christopherson wrote:
> On Thu, Jul 04, 2024, Maxim Levitsky wrote:
> > On Fri, 2024-05-17 at 10:39 -0700, Sean Christopherson wrote:
> > > @@ -421,6 +423,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
> > >  	 */
> > >  	for (i = 0; i < NR_KVM_CPU_CAPS; i++) {
> > >  		const struct cpuid_reg cpuid = reverse_cpuid[i];
> > > +		struct kvm_cpuid_entry2 emulated;
> > >  
> > >  		if (!cpuid.function)
> > >  			continue;
> > > @@ -429,7 +432,16 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
> > >  		if (!entry)
> > >  			continue;
> > >  
> > > -		vcpu->arch.cpu_caps[i] = cpuid_get_reg_unsafe(entry, cpuid.reg);
> > > +		cpuid_func_emulated(&emulated, cpuid.function);
> > > +
> > > +		/*
> > > +		 * A vCPU has a feature if it's supported by KVM and is enabled
> > > +		 * in guest CPUID.  Note, this includes features that are
> > > +		 * supported by KVM but aren't advertised to userspace!
> > > +		 */
> > > +		vcpu->arch.cpu_caps[i] = kvm_cpu_caps[i] | kvm_vmm_cpu_caps[i] |
> > > +					 cpuid_get_reg_unsafe(&emulated, cpuid.reg);
> > > +		vcpu->arch.cpu_caps[i] &= cpuid_get_reg_unsafe(entry, cpuid.reg);
> > 
> > Hi,
> > 
> > I have an idea. What if we get rid of kvm_vmm_cpu_caps, and instead advertise the
> > MWAIT in KVM_GET_EMULATED_CPUID?
> > 
> > MWAIT is sort of emulated as NOP after all, plus features in KVM_GET_EMULATED_CPUID are
> > sort of 'emulated inefficiently' and you can say that NOP is an inefficient emulation
> > of MWAIT sort of.
> 
> Heh, sort of indeed.  I really don't want to advertise MWAIT to userspace in any
> capacity beyond KVM_CAP_X86_DISABLE_EXITS, because advertising MWAIT to VMs when
> MONITOR/MWAIT exiting is enabled is actively harmful, to both host and guest.

Assuming that the only purpose of the KVM_GET_EMULATED_CPUID is to allow the guest
to use a feature if it really insists, there should be no harm, but yes, I understand
your concert here.

> 
> KVM also doesn't emulate them on #UD, unlike MOVBE, which would make the API even
> more confusing than it already is.
This is even bigger justification for not doing this.


> 
> > It just feels to me that kvm_vmm_cpu_caps, is somewhat an overkill, and its name is
> > somewhat confusing.
> 
> Yeah, I don't love it either, but trying to handle MWAIT as a one-off was even
> uglier.  One option would be to piggyback cpuid_func_emulated(), but add a param
> to have it fill MWAIT only for KVM's internal purposes.  That'd essentially be
> the same as a one-off in kvm_vcpu_after_set_cpuid(), but less ugly.
> 
> I'd say it comes down to whether or not we expect to have more features that KVM
> "supports", but doesn't advertise to userspace.  If we do, then I think adding
> VMM_F() is the way to go.  If we expect MWAIT to be the only feature that gets
> this treatment, then I'm ok if we bastardize cpuid_func_emulated().
> 
> And I think/hope that MWAIT will be a one-off.  Emulating it as a nop was a
> mistake and has since been quirked, and I like to think we (eventually) learn
> from our mistakes.
> 
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 0e64a6332052..dbc3f6ce9203 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -448,7 +448,7 @@ void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
>                 if (!entry)
>                         continue;
>  
> -               cpuid_func_emulated(&emulated, cpuid.function);
> +               cpuid_func_emulated(&emulated, cpuid.function, false);
>  
>                 /*
>                  * A vCPU has a feature if it's supported by KVM and is enabled
> @@ -1034,7 +1034,8 @@ static struct kvm_cpuid_entry2 *do_host_cpuid(struct kvm_cpuid_array *array,
>         return entry;
>  }
>  
> -static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func)
> +static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func,
> +                              bool only_advertised)

I'll say, lets call this boolean, 'include_partially_emulated', 
(basically features that kvm emulates but only partially,
and thus doesn't advertise, aka mwait)

and then it doesn't look that bad, assuming that comes with a comment.




>  {
>         memset(entry, 0, sizeof(*entry));
>  
> @@ -1048,6 +1049,9 @@ static int cpuid_func_emulated(struct kvm_cpuid_entry2 *entry, u32 func)
>                 return 1;
>         case 1:
>                 entry->ecx = F(MOVBE);
> +               /* comment goes here. */
> +               if (!only_advertised)

And here 

	if(include_partially_emulated) ...


It sort of even self-documents nature of mwait emulation.

> +                       entry->ecx |= F(MWAIT);
>                 return 1;
>         case 7:
>                 entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
> @@ -1065,7 +1069,7 @@ static int __do_cpuid_func_emulated(struct kvm_cpuid_array *array, u32 func)
>         if (array->nent >= array->maxnent)
>                 return -E2BIG;
>  
> -       array->nent += cpuid_func_emulated(&array->entries[array->nent], func);
> +       array->nent += cpuid_func_emulated(&array->entries[array->nent], func, true);
>         return 0;
>  }
> 

Best regards,
	Maxim Levitsky






[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux