[6/6] KVM: x86: Set KVM LASS based on hardware capability

Message ID 20230420133724.11398-7-guang.zeng@intel.com
State New
Headers
Series LASS KVM virtualization support |

Commit Message

Zeng Guang April 20, 2023, 1:37 p.m. UTC
  Host kernel may clear LASS capability in boot_cpu_data.x86_capability
besides explicitly using clearcpuid parameter. That will cause guest
not being able to manage LASS independently. So set KVM LASS directly
based on hardware capability to eliminate the dependency.

Add new helper functions to facilitate getting result of CPUID sub-leaf.

Signed-off-by: Zeng Guang <guang.zeng@intel.com>
---
 arch/x86/include/asm/cpuid.h | 36 ++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/cpuid.c         |  4 ++++
 2 files changed, 40 insertions(+)
  

Comments

Binbin Wu April 25, 2023, 2:57 a.m. UTC | #1
On 4/20/2023 9:37 PM, Zeng Guang wrote:
> Host kernel may clear LASS capability in boot_cpu_data.x86_capability
Is there some option to do it?

> besides explicitly using clearcpuid parameter. That will cause guest
> not being able to manage LASS independently. So set KVM LASS directly
> based on hardware capability to eliminate the dependency.
>
> Add new helper functions to facilitate getting result of CPUID sub-leaf.
>
> Signed-off-by: Zeng Guang <guang.zeng@intel.com>
> ---
>   arch/x86/include/asm/cpuid.h | 36 ++++++++++++++++++++++++++++++++++++
>   arch/x86/kvm/cpuid.c         |  4 ++++
>   2 files changed, 40 insertions(+)
>
> diff --git a/arch/x86/include/asm/cpuid.h b/arch/x86/include/asm/cpuid.h
> index 9bee3e7bf973..a25dd00b7c0a 100644
> --- a/arch/x86/include/asm/cpuid.h
> +++ b/arch/x86/include/asm/cpuid.h
> @@ -127,6 +127,42 @@ static inline unsigned int cpuid_edx(unsigned int op)
>   	return edx;
>   }
>   
> +static inline unsigned int cpuid_count_eax(unsigned int op, int count)
> +{
> +	unsigned int eax, ebx, ecx, edx;
> +
> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
> +
> +	return eax;
> +}
> +
> +static inline unsigned int cpuid_count_ebx(unsigned int op, int count)
> +{
> +	unsigned int eax, ebx, ecx, edx;
> +
> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
> +
> +	return ebx;
> +}
> +
> +static inline unsigned int cpuid_count_ecx(unsigned int op, int count)
> +{
> +	unsigned int eax, ebx, ecx, edx;
> +
> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
> +
> +	return ecx;
> +}
> +
> +static inline unsigned int cpuid_count_edx(unsigned int op, int count)
> +{
> +	unsigned int eax, ebx, ecx, edx;
> +
> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
> +
> +	return edx;
> +}
> +
>   static __always_inline bool cpuid_function_is_indexed(u32 function)
>   {
>   	switch (function) {
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 5facb8037140..e99b99ebe1fe 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -667,6 +667,10 @@ void kvm_set_cpu_caps(void)
>   		F(AMX_FP16) | F(AVX_IFMA)
>   	);
>   
> +	/* Set LASS based on hardware capability */
> +	if (cpuid_count_eax(7, 1) & F(LASS))
> +		kvm_cpu_cap_set(X86_FEATURE_LASS);
> +
>   	kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX,
>   		F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI)
>   	);
  
Zeng Guang April 25, 2023, 6:47 a.m. UTC | #2
On 4/25/2023 10:57 AM, Binbin Wu wrote:
>
> On 4/20/2023 9:37 PM, Zeng Guang wrote:
>> Host kernel may clear LASS capability in boot_cpu_data.x86_capability
> Is there some option to do it?

Kernel supporting LASS will turn off the LASS capability with specific 
option, e.g.
"vsyscall=emulate".

>> besides explicitly using clearcpuid parameter. That will cause guest
>> not being able to manage LASS independently. So set KVM LASS directly
>> based on hardware capability to eliminate the dependency.
>>
>> Add new helper functions to facilitate getting result of CPUID sub-leaf.
>>
>> Signed-off-by: Zeng Guang <guang.zeng@intel.com>
>> ---
>>    arch/x86/include/asm/cpuid.h | 36 ++++++++++++++++++++++++++++++++++++
>>    arch/x86/kvm/cpuid.c         |  4 ++++
>>    2 files changed, 40 insertions(+)
>>
>> diff --git a/arch/x86/include/asm/cpuid.h b/arch/x86/include/asm/cpuid.h
>> index 9bee3e7bf973..a25dd00b7c0a 100644
>> --- a/arch/x86/include/asm/cpuid.h
>> +++ b/arch/x86/include/asm/cpuid.h
>> @@ -127,6 +127,42 @@ static inline unsigned int cpuid_edx(unsigned int op)
>>    	return edx;
>>    }
>>    
>> +static inline unsigned int cpuid_count_eax(unsigned int op, int count)
>> +{
>> +	unsigned int eax, ebx, ecx, edx;
>> +
>> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
>> +
>> +	return eax;
>> +}
>> +
>> +static inline unsigned int cpuid_count_ebx(unsigned int op, int count)
>> +{
>> +	unsigned int eax, ebx, ecx, edx;
>> +
>> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
>> +
>> +	return ebx;
>> +}
>> +
>> +static inline unsigned int cpuid_count_ecx(unsigned int op, int count)
>> +{
>> +	unsigned int eax, ebx, ecx, edx;
>> +
>> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
>> +
>> +	return ecx;
>> +}
>> +
>> +static inline unsigned int cpuid_count_edx(unsigned int op, int count)
>> +{
>> +	unsigned int eax, ebx, ecx, edx;
>> +
>> +	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
>> +
>> +	return edx;
>> +}
>> +
>>    static __always_inline bool cpuid_function_is_indexed(u32 function)
>>    {
>>    	switch (function) {
>> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
>> index 5facb8037140..e99b99ebe1fe 100644
>> --- a/arch/x86/kvm/cpuid.c
>> +++ b/arch/x86/kvm/cpuid.c
>> @@ -667,6 +667,10 @@ void kvm_set_cpu_caps(void)
>>    		F(AMX_FP16) | F(AVX_IFMA)
>>    	);
>>    
>> +	/* Set LASS based on hardware capability */
>> +	if (cpuid_count_eax(7, 1) & F(LASS))
>> +		kvm_cpu_cap_set(X86_FEATURE_LASS);
>> +
>>    	kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX,
>>    		F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI)
>>    	);
  
Chao Gao April 25, 2023, 7:28 a.m. UTC | #3
On Thu, Apr 20, 2023 at 09:37:24PM +0800, Zeng Guang wrote:
>Host kernel may clear LASS capability in boot_cpu_data.x86_capability
>besides explicitly using clearcpuid parameter. That will cause guest
>not being able to manage LASS independently. So set KVM LASS directly
>based on hardware capability to eliminate the dependency.

...

>+	/* Set LASS based on hardware capability */
>+	if (cpuid_count_eax(7, 1) & F(LASS))
>+		kvm_cpu_cap_set(X86_FEATURE_LASS);
>+

What if LASS is cleared in boot_cpu_data because not all CPUs support LASS?

In arch/x86/kernel/cpu/common.c, identify_cpu() clears features which are
not supported by all CPUs:

	/*
	 * On SMP, boot_cpu_data holds the common feature set between
	 * all CPUs; so make sure that we indicate which features are
	 * common between the CPUs.  The first time this routine gets
	 * executed, c == &boot_cpu_data.
	 */
	if (c != &boot_cpu_data) {
		/* AND the already accumulated flags with these */
		for (i = 0; i < NCAPINTS; i++)
			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];

LA57 seems to have the same issue. We may need to add some checks for LA57
in KVM's cpu hotplug callback.

> 	kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX,
> 		F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI)
> 	);
>-- 
>2.27.0
>
  

Patch

diff --git a/arch/x86/include/asm/cpuid.h b/arch/x86/include/asm/cpuid.h
index 9bee3e7bf973..a25dd00b7c0a 100644
--- a/arch/x86/include/asm/cpuid.h
+++ b/arch/x86/include/asm/cpuid.h
@@ -127,6 +127,42 @@  static inline unsigned int cpuid_edx(unsigned int op)
 	return edx;
 }
 
+static inline unsigned int cpuid_count_eax(unsigned int op, int count)
+{
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
+
+	return eax;
+}
+
+static inline unsigned int cpuid_count_ebx(unsigned int op, int count)
+{
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
+
+	return ebx;
+}
+
+static inline unsigned int cpuid_count_ecx(unsigned int op, int count)
+{
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
+
+	return ecx;
+}
+
+static inline unsigned int cpuid_count_edx(unsigned int op, int count)
+{
+	unsigned int eax, ebx, ecx, edx;
+
+	cpuid_count(op, count, &eax, &ebx, &ecx, &edx);
+
+	return edx;
+}
+
 static __always_inline bool cpuid_function_is_indexed(u32 function)
 {
 	switch (function) {
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 5facb8037140..e99b99ebe1fe 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -667,6 +667,10 @@  void kvm_set_cpu_caps(void)
 		F(AMX_FP16) | F(AVX_IFMA)
 	);
 
+	/* Set LASS based on hardware capability */
+	if (cpuid_count_eax(7, 1) & F(LASS))
+		kvm_cpu_cap_set(X86_FEATURE_LASS);
+
 	kvm_cpu_cap_init_kvm_defined(CPUID_7_1_EDX,
 		F(AVX_VNNI_INT8) | F(AVX_NE_CONVERT) | F(PREFETCHITI)
 	);