Re: [PATCH v11 5/9] KVM: X86: Refresh CPUID once guest XSS MSR changes

From: Sean Christopherson
Date: Thu Apr 23 2020 - 13:34:54 EST


On Thu, Mar 26, 2020 at 04:18:42PM +0800, Yang Weijiang wrote:
> CPUID(0xd, 1) reports the current required storage size of
> XCR0 | XSS, when guest updates the XSS, it's necessary to update
> the CPUID leaf, otherwise guest will fetch old state size, and
> results to some WARN traces during guest running.
>
> Co-developed-by: Zhang Yi Z <yi.z.zhang@xxxxxxxxxxxxxxx>
> Signed-off-by: Zhang Yi Z <yi.z.zhang@xxxxxxxxxxxxxxx>
> Signed-off-by: Yang Weijiang <weijiang.yang@xxxxxxxxx>
> ---
> arch/x86/include/asm/kvm_host.h | 1 +
> arch/x86/kvm/cpuid.c | 21 ++++++++++++++++++---
> arch/x86/kvm/x86.c | 9 +++++++--
> 3 files changed, 26 insertions(+), 5 deletions(-)
>
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index 24c90ea5ddbd..2c944ad99692 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -650,6 +650,7 @@ struct kvm_vcpu_arch {
>
> u64 xcr0;
> u64 guest_supported_xcr0;
> + u64 guest_supported_xss;
> u32 guest_xstate_size;
>
> struct kvm_pio_request pio;
> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
> index 78d461be2102..25e9a11291b3 100644
> --- a/arch/x86/kvm/cpuid.c
> +++ b/arch/x86/kvm/cpuid.c
> @@ -95,9 +95,24 @@ int kvm_update_cpuid(struct kvm_vcpu *vcpu)
> }
>
> best = kvm_find_cpuid_entry(vcpu, 0xD, 1);
> - if (best && (cpuid_entry_has(best, X86_FEATURE_XSAVES) ||
> - cpuid_entry_has(best, X86_FEATURE_XSAVEC)))
> - best->ebx = xstate_required_size(vcpu->arch.xcr0, true);
> + if (best) {
> + if (best->eax & (F(XSAVES) | F(XSAVEC))) {

Please use cpuid_entry_has() to preserve the automagic register lookup and
compile-time assertions that are provided. E.g. I don't know off the top
of my whether %eax is the correct register, and I don't want to know :-).

> + u64 xstate = vcpu->arch.xcr0 | vcpu->arch.ia32_xss;
> +
> + best->ebx = xstate_required_size(xstate, true);
> + }
> +
> + if (best->eax & F(XSAVES)) {

Same thing here.

> + vcpu->arch.guest_supported_xss =
> + (best->ecx | ((u64)best->edx << 32)) & supported_xss;

The indentation is funky, I'm guessing you're trying to squeak in less than
80 chars. Maybe this?

if (!cpuid_entry_has(best, X86_FEATURE_XSAVES)) {
best->ecx = 0;
best->edx = 0;
}

vcpu->arch.guest_supported_xss =
(((u64)best->edx << 32) | best->ecx) & supported_xss;

Nit: my preference is to have the high half first, x86 is little endian
(the xcr0 code is "wrong" :-D). For me, this also makes it more obvious
that the effective size is a u64.

> + } else {
> + best->ecx = 0;
> + best->edx = 0;
> + vcpu->arch.guest_supported_xss = 0;
> + }
> + } else {
> + vcpu->arch.guest_supported_xss = 0;
> + }
>
> /*
> * The existing code assumes virtual address is 48-bit or 57-bit in the
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 90acdbbb8a5a..51ecb496d47d 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -2836,9 +2836,12 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than
> * XSAVES/XRSTORS to save/restore PT MSRs.
> */
> - if (data & ~supported_xss)
> + if (data & ~vcpu->arch.guest_supported_xss)
> return 1;
> - vcpu->arch.ia32_xss = data;
> + if (vcpu->arch.ia32_xss != data) {
> + vcpu->arch.ia32_xss = data;
> + kvm_update_cpuid(vcpu);
> + }
> break;
> case MSR_SMI_COUNT:
> if (!msr_info->host_initiated)
> @@ -9635,6 +9638,8 @@ int kvm_arch_hardware_setup(void)
>
> if (!kvm_cpu_cap_has(X86_FEATURE_XSAVES))
> supported_xss = 0;
> + else
> + supported_xss = host_xss & KVM_SUPPORTED_XSS;

Silly nit: I'd prefer to invert the check, e.g.

if (kvm_cpu_cap_has(X86_FEATURE_XSAVES))
supported_xss = host_xss & KVM_SUPPORTED_XSS;
else
supported_xss = 0;

>
> cr4_reserved_bits = kvm_host_cr4_reserved_bits(&boot_cpu_data);
>
> --
> 2.17.2
>