Message ID | 20230914063325.85503-13-weijiang.yang@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Enable CET Virtualization | expand |
>diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h >index 0fc5e6312e93..d77b030e996c 100644 >--- a/arch/x86/include/asm/kvm_host.h >+++ b/arch/x86/include/asm/kvm_host.h >@@ -803,6 +803,7 @@ struct kvm_vcpu_arch { > > u64 xcr0; > u64 guest_supported_xcr0; >+ u64 guest_supported_xss; This structure has the ia32_xss field. how about moving it here for symmetry? > > struct kvm_pio_request pio; > void *pio_data; >diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c >index 1f206caec559..4e7a820cba62 100644 >--- a/arch/x86/kvm/cpuid.c >+++ b/arch/x86/kvm/cpuid.c >@@ -275,7 +275,8 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e > best = cpuid_entry2_find(entries, nent, 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); >+ best->ebx = xstate_required_size(vcpu->arch.xcr0 | >+ vcpu->arch.ia32_xss, true); > > best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); > if (kvm_hlt_in_guest(vcpu->kvm) && best && >@@ -312,6 +313,17 @@ static u64 vcpu_get_supported_xcr0(struct kvm_vcpu *vcpu) > return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; > } > >+static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu) >+{ >+ struct kvm_cpuid_entry2 *best; >+ >+ best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); >+ if (!best) >+ return 0; >+ >+ return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; >+} >+ > static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) > { > struct kvm_cpuid_entry2 *entry; >@@ -358,6 +370,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) > } > > vcpu->arch.guest_supported_xcr0 = vcpu_get_supported_xcr0(vcpu); >+ vcpu->arch.guest_supported_xss = vcpu_get_supported_xss(vcpu); > > /* > * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if >diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c >index 1258d1d6dd52..9a616d84bd39 100644 >--- a/arch/x86/kvm/x86.c >+++ b/arch/x86/kvm/x86.c >@@ -3795,20 +3795,25 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) > vcpu->arch.ia32_tsc_adjust_msr += adj; > } > break; >- case MSR_IA32_XSS: >- if (!msr_info->host_initiated && >- !guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) >+ case MSR_IA32_XSS: { >+ bool host_msr_reset = msr_info->host_initiated && data == 0; >+ >+ if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES) && >+ (!host_msr_reset || !msr_info->host_initiated)) !msr_info->host_initiated can be dropped here.
On 10/8/2023 1:54 PM, Chao Gao wrote: >> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h >> index 0fc5e6312e93..d77b030e996c 100644 >> --- a/arch/x86/include/asm/kvm_host.h >> +++ b/arch/x86/include/asm/kvm_host.h >> @@ -803,6 +803,7 @@ struct kvm_vcpu_arch { >> >> u64 xcr0; >> u64 guest_supported_xcr0; >> + u64 guest_supported_xss; > This structure has the ia32_xss field. how about moving it here for symmetry? OK, will do it, thanks! >> struct kvm_pio_request pio; >> void *pio_data; >> diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c >> index 1f206caec559..4e7a820cba62 100644 >> --- a/arch/x86/kvm/cpuid.c >> +++ b/arch/x86/kvm/cpuid.c >> @@ -275,7 +275,8 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e >> best = cpuid_entry2_find(entries, nent, 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); >> + best->ebx = xstate_required_size(vcpu->arch.xcr0 | >> + vcpu->arch.ia32_xss, true); >> >> best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); >> if (kvm_hlt_in_guest(vcpu->kvm) && best && >> @@ -312,6 +313,17 @@ static u64 vcpu_get_supported_xcr0(struct kvm_vcpu *vcpu) >> return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; >> } >> >> +static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu) >> +{ >> + struct kvm_cpuid_entry2 *best; >> + >> + best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); >> + if (!best) >> + return 0; >> + >> + return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; >> +} >> + >> static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) >> { >> struct kvm_cpuid_entry2 *entry; >> @@ -358,6 +370,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) >> } >> >> vcpu->arch.guest_supported_xcr0 = vcpu_get_supported_xcr0(vcpu); >> + vcpu->arch.guest_supported_xss = vcpu_get_supported_xss(vcpu); >> >> /* >> * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if >> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c >> index 1258d1d6dd52..9a616d84bd39 100644 >> --- a/arch/x86/kvm/x86.c >> +++ b/arch/x86/kvm/x86.c >> @@ -3795,20 +3795,25 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) >> vcpu->arch.ia32_tsc_adjust_msr += adj; >> } >> break; >> - case MSR_IA32_XSS: >> - if (!msr_info->host_initiated && >> - !guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) >> + case MSR_IA32_XSS: { >> + bool host_msr_reset = msr_info->host_initiated && data == 0; >> + >> + if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES) && >> + (!host_msr_reset || !msr_info->host_initiated)) > !msr_info->host_initiated can be dropped here. Yes, it's not necessary, will remove it, thanks!
On Thu, 2023-09-14 at 02:33 -0400, Yang Weijiang wrote: > Update CPUID.(EAX=0DH,ECX=1).EBX to reflect current required xstate size > due to XSS MSR modification. > CPUID(EAX=0DH,ECX=1).EBX reports the required storage size of all enabled > xstate features in (XCR0 | IA32_XSS). The CPUID value can be used by guest > before allocate sufficient xsave buffer. > > Note, KVM does not yet support any XSS based features, i.e. supported_xss > is guaranteed to be zero at this time. > > Opportunistically modify XSS write access logic as: if !guest_cpuid_has(), > write initiated from host is allowed iff the write is reset operaiton, > i.e., data == 0, reject host_initiated non-reset write and any guest write. The commit message is not clear and somewhat misleading because it forces the reader to parse the whole patch before one could understand what '!guest_cpuid_has()' means. Also I don't think that the term 'reset operation' is a good choice, because it is too closely related to vCPU reset IMHO. Let's at least call it 'reset to a default value' or something like that. Also note that 0 is not always the default/reset value of an MSR. I suggest this instead: "If XSAVES is not enabled in the guest CPUID, forbid setting IA32_XSS msr to anything but 0, even if the write is host initiated." Also, isn't this change is at least in theory not backward compatible? While KVM didn't report IA32_XSS as one needing save/restore, the userspace could before this patch set the IA32_XSS to any value, now it can't. Maybe it's safer to allow to set any value, ignore the set value and issue a WARN_ON_ONCE or something? Finally, I think that this change is better to be done in a separate patch because it is unrelated and might not even be backward compatible. Best regards, Maxim Levitsky > > Suggested-by: Sean Christopherson <seanjc@google.com> > Co-developed-by: Zhang Yi Z <yi.z.zhang@linux.intel.com> > Signed-off-by: Zhang Yi Z <yi.z.zhang@linux.intel.com> > Signed-off-by: Yang Weijiang <weijiang.yang@intel.com> > --- > arch/x86/include/asm/kvm_host.h | 1 + > arch/x86/kvm/cpuid.c | 15 ++++++++++++++- > arch/x86/kvm/x86.c | 13 +++++++++---- > 3 files changed, 24 insertions(+), 5 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 0fc5e6312e93..d77b030e996c 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -803,6 +803,7 @@ struct kvm_vcpu_arch { > > u64 xcr0; > u64 guest_supported_xcr0; > + u64 guest_supported_xss; > > struct kvm_pio_request pio; > void *pio_data; > diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c > index 1f206caec559..4e7a820cba62 100644 > --- a/arch/x86/kvm/cpuid.c > +++ b/arch/x86/kvm/cpuid.c > @@ -275,7 +275,8 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e > best = cpuid_entry2_find(entries, nent, 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); > + best->ebx = xstate_required_size(vcpu->arch.xcr0 | > + vcpu->arch.ia32_xss, true); > > best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); > if (kvm_hlt_in_guest(vcpu->kvm) && best && > @@ -312,6 +313,17 @@ static u64 vcpu_get_supported_xcr0(struct kvm_vcpu *vcpu) > return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; > } > > +static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu) > +{ > + struct kvm_cpuid_entry2 *best; > + > + best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); > + if (!best) > + return 0; > + > + return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; > +} Same question as one for patch that added vcpu_get_supported_xcr0() Why to have per vCPU supported XSS if we assume that all CPUs have the same CPUID? I mean I am not against supporting hybrid CPU models, but KVM currently doesn't support this and this creates illusion that it does. > + > static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) > { > struct kvm_cpuid_entry2 *entry; > @@ -358,6 +370,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) > } > > vcpu->arch.guest_supported_xcr0 = vcpu_get_supported_xcr0(vcpu); > + vcpu->arch.guest_supported_xss = vcpu_get_supported_xss(vcpu); > > /* > * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 1258d1d6dd52..9a616d84bd39 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -3795,20 +3795,25 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) > vcpu->arch.ia32_tsc_adjust_msr += adj; > } > break; > - case MSR_IA32_XSS: > - if (!msr_info->host_initiated && > - !guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) > + case MSR_IA32_XSS: { > + bool host_msr_reset = msr_info->host_initiated && data == 0; > + > + if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES) && > + (!host_msr_reset || !msr_info->host_initiated)) > return 1; > /* > * KVM supports exposing PT to the guest, but does not support > * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than > * XSAVES/XRSTORS to save/restore PT MSRs. > */ Just in case.... TODO > - if (data & ~kvm_caps.supported_xss) > + if (data & ~vcpu->arch.guest_supported_xss) > return 1; > + if (vcpu->arch.ia32_xss == data) > + break; > vcpu->arch.ia32_xss = data; > kvm_update_cpuid_runtime(vcpu); > break; > + } > case MSR_SMI_COUNT: > if (!msr_info->host_initiated) > return 1;
On Tue, Oct 31, 2023, Maxim Levitsky wrote: > On Thu, 2023-09-14 at 02:33 -0400, Yang Weijiang wrote: > > @@ -312,6 +313,17 @@ static u64 vcpu_get_supported_xcr0(struct kvm_vcpu *vcpu) > > return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; > > } > > > > +static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu) > > +{ > > + struct kvm_cpuid_entry2 *best; > > + > > + best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); > > + if (!best) > > + return 0; > > + > > + return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; > > +} > > Same question as one for patch that added vcpu_get_supported_xcr0() > Why to have per vCPU supported XSS if we assume that all CPUs have the same > CPUID? > > I mean I am not against supporting hybrid CPU models, but KVM currently doesn't > support this and this creates illusion that it does. KVM does "support" hybrid vCPU models in the sense that KVM has allow hybrid models since forever. There are definite things that won't work, e.g. not all relevant CPUID bits are captured in kvm_mmu_page_role, and so KVM will incorrectly share page tables across vCPUs that are technically incompatible. But for many features, heterogenous vCPU models do Just Work as far as KVM is concerned. There likely isn't a real world kernel that supports heterogenous feature sets for things like XSS and XCR0, but that's a guest software limitation, not a limitation of KVM's CPU virtualization. As with many things, KVM's ABI is to let userspace shoot themselves in the foot.
On 9/14/2023 2:33 PM, Yang Weijiang wrote: > Update CPUID.(EAX=0DH,ECX=1).EBX to reflect current required xstate size > due to XSS MSR modification. > CPUID(EAX=0DH,ECX=1).EBX reports the required storage size of all enabled > xstate features in (XCR0 | IA32_XSS). The CPUID value can be used by guest > before allocate sufficient xsave buffer. > > Note, KVM does not yet support any XSS based features, i.e. supported_xss > is guaranteed to be zero at this time. > > Opportunistically modify XSS write access logic as: if !guest_cpuid_has(), > write initiated from host is allowed iff the write is reset operaiton, > i.e., data == 0, reject host_initiated non-reset write and any guest write. Hi Sean & Polo, During code review of Enable CET Virtualization v5 patchset, there were discussions about "do a wholesale cleanup of all the cases that essentially allow userspace to do KVM_SET_MSR before KVM_SET_CPUID2", i.e. force the order between KVM_SET_CPUID2 and KVM_SET_MSR, but allow the host_initiated path with default (generally 0) value. https://lore.kernel.org/kvm/ZM1C+ILRMCfzJxx7@google.com/ https://lore.kernel.org/kvm/CABgObfbvr8F8g5hJN6jn95m7u7m2+8ACkqO25KAZwRmJ9AncZg@mail.gmail.com/ I can take the task to do the code cleanup. Before going any further, I want to confirm it is still the direction intended, right? > > Suggested-by: Sean Christopherson <seanjc@google.com> > Co-developed-by: Zhang Yi Z <yi.z.zhang@linux.intel.com> > Signed-off-by: Zhang Yi Z <yi.z.zhang@linux.intel.com> > Signed-off-by: Yang Weijiang <weijiang.yang@intel.com> > --- > arch/x86/include/asm/kvm_host.h | 1 + > arch/x86/kvm/cpuid.c | 15 ++++++++++++++- > arch/x86/kvm/x86.c | 13 +++++++++---- > 3 files changed, 24 insertions(+), 5 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 0fc5e6312e93..d77b030e996c 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -803,6 +803,7 @@ struct kvm_vcpu_arch { > > u64 xcr0; > u64 guest_supported_xcr0; > + u64 guest_supported_xss; > > struct kvm_pio_request pio; > void *pio_data; > diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c > index 1f206caec559..4e7a820cba62 100644 > --- a/arch/x86/kvm/cpuid.c > +++ b/arch/x86/kvm/cpuid.c > @@ -275,7 +275,8 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e > best = cpuid_entry2_find(entries, nent, 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); > + best->ebx = xstate_required_size(vcpu->arch.xcr0 | > + vcpu->arch.ia32_xss, true); > > best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); > if (kvm_hlt_in_guest(vcpu->kvm) && best && > @@ -312,6 +313,17 @@ static u64 vcpu_get_supported_xcr0(struct kvm_vcpu *vcpu) > return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; > } > > +static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu) > +{ > + struct kvm_cpuid_entry2 *best; > + > + best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); > + if (!best) > + return 0; > + > + return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; > +} > + > static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) > { > struct kvm_cpuid_entry2 *entry; > @@ -358,6 +370,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) > } > > vcpu->arch.guest_supported_xcr0 = vcpu_get_supported_xcr0(vcpu); > + vcpu->arch.guest_supported_xss = vcpu_get_supported_xss(vcpu); > > /* > * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index 1258d1d6dd52..9a616d84bd39 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -3795,20 +3795,25 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) > vcpu->arch.ia32_tsc_adjust_msr += adj; > } > break; > - case MSR_IA32_XSS: > - if (!msr_info->host_initiated && > - !guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) > + case MSR_IA32_XSS: { > + bool host_msr_reset = msr_info->host_initiated && data == 0; > + > + if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES) && > + (!host_msr_reset || !msr_info->host_initiated)) > return 1; > /* > * KVM supports exposing PT to the guest, but does not support > * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than > * XSAVES/XRSTORS to save/restore PT MSRs. > */ > - if (data & ~kvm_caps.supported_xss) > + if (data & ~vcpu->arch.guest_supported_xss) > return 1; > + if (vcpu->arch.ia32_xss == data) > + break; > vcpu->arch.ia32_xss = data; > kvm_update_cpuid_runtime(vcpu); > break; > + } > case MSR_SMI_COUNT: > if (!msr_info->host_initiated) > return 1;
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 0fc5e6312e93..d77b030e996c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -803,6 +803,7 @@ struct kvm_vcpu_arch { u64 xcr0; u64 guest_supported_xcr0; + u64 guest_supported_xss; struct kvm_pio_request pio; void *pio_data; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 1f206caec559..4e7a820cba62 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -275,7 +275,8 @@ static void __kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu, struct kvm_cpuid_e best = cpuid_entry2_find(entries, nent, 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); + best->ebx = xstate_required_size(vcpu->arch.xcr0 | + vcpu->arch.ia32_xss, true); best = __kvm_find_kvm_cpuid_features(vcpu, entries, nent); if (kvm_hlt_in_guest(vcpu->kvm) && best && @@ -312,6 +313,17 @@ static u64 vcpu_get_supported_xcr0(struct kvm_vcpu *vcpu) return (best->eax | ((u64)best->edx << 32)) & kvm_caps.supported_xcr0; } +static u64 vcpu_get_supported_xss(struct kvm_vcpu *vcpu) +{ + struct kvm_cpuid_entry2 *best; + + best = kvm_find_cpuid_entry_index(vcpu, 0xd, 1); + if (!best) + return 0; + + return (best->ecx | ((u64)best->edx << 32)) & kvm_caps.supported_xss; +} + static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent) { struct kvm_cpuid_entry2 *entry; @@ -358,6 +370,7 @@ static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu) } vcpu->arch.guest_supported_xcr0 = vcpu_get_supported_xcr0(vcpu); + vcpu->arch.guest_supported_xss = vcpu_get_supported_xss(vcpu); /* * FP+SSE can always be saved/restored via KVM_{G,S}ET_XSAVE, even if diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 1258d1d6dd52..9a616d84bd39 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3795,20 +3795,25 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) vcpu->arch.ia32_tsc_adjust_msr += adj; } break; - case MSR_IA32_XSS: - if (!msr_info->host_initiated && - !guest_cpuid_has(vcpu, X86_FEATURE_XSAVES)) + case MSR_IA32_XSS: { + bool host_msr_reset = msr_info->host_initiated && data == 0; + + if (!guest_cpuid_has(vcpu, X86_FEATURE_XSAVES) && + (!host_msr_reset || !msr_info->host_initiated)) return 1; /* * KVM supports exposing PT to the guest, but does not support * IA32_XSS[bit 8]. Guests have to use RDMSR/WRMSR rather than * XSAVES/XRSTORS to save/restore PT MSRs. */ - if (data & ~kvm_caps.supported_xss) + if (data & ~vcpu->arch.guest_supported_xss) return 1; + if (vcpu->arch.ia32_xss == data) + break; vcpu->arch.ia32_xss = data; kvm_update_cpuid_runtime(vcpu); break; + } case MSR_SMI_COUNT: if (!msr_info->host_initiated) return 1;