public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR
@ 2025-09-18  3:38 Hou Wenlong
  2025-09-18  3:38 ` [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest Hou Wenlong
  2025-09-19 16:28 ` [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR Sean Christopherson
  0 siblings, 2 replies; 9+ messages in thread
From: Hou Wenlong @ 2025-09-18  3:38 UTC (permalink / raw)
  To: kvm
  Cc: Lai Jiangshan, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, linux-kernel

In the user return MSR support, the cached value is always the hardware
value of the specific MSR. Therefore, add a helper to retrieve the
cached value, which can replace the need for RDMSR, for example, to
allow SEV-ES guests to restore the correct host hardware value without
using RDMSR.

Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
---
 arch/x86/include/asm/kvm_host.h | 1 +
 arch/x86/kvm/x86.c              | 8 ++++++++
 2 files changed, 9 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index cb86f3cca3e9..2cbb0f446a9b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -2376,6 +2376,7 @@ int kvm_add_user_return_msr(u32 msr);
 int kvm_find_user_return_msr(u32 msr);
 int kvm_set_user_return_msr(unsigned index, u64 val, u64 mask);
 void kvm_user_return_msr_update_cache(unsigned int index, u64 val);
+u64 kvm_get_user_return_msr_cache(unsigned int index);
 
 static inline bool kvm_is_supported_user_return_msr(u32 msr)
 {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 6d85fbafc679..88d26c86c3b2 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -675,6 +675,14 @@ void kvm_user_return_msr_update_cache(unsigned int slot, u64 value)
 }
 EXPORT_SYMBOL_GPL(kvm_user_return_msr_update_cache);
 
+u64 kvm_get_user_return_msr_cache(unsigned int slot)
+{
+	struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs);
+
+	return msrs->values[slot].curr;
+}
+EXPORT_SYMBOL_GPL(kvm_get_user_return_msr_cache);
+
 static void drop_user_return_notifiers(void)
 {
 	struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs);

base-commit: 603c090664d350b7fdaffbe8e6a6e43829938458
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-18  3:38 [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR Hou Wenlong
@ 2025-09-18  3:38 ` Hou Wenlong
  2025-09-18 18:47   ` Tom Lendacky
  2025-09-19 16:28 ` [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR Sean Christopherson
  1 sibling, 1 reply; 9+ messages in thread
From: Hou Wenlong @ 2025-09-18  3:38 UTC (permalink / raw)
  To: kvm
  Cc: Lai Jiangshan, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Tom Lendacky, linux-kernel

The commit 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support
for virtualized TSC_AUX") assumes that TSC_AUX is not changed by Linux
post-boot, so it always restores the initial host value on #VMEXIT.
However, this is not true in KVM, as it can be modified by user return
MSR support for normal guests. If an SEV-ES guest always restores the
initial host value on #VMEXIT, this may result in the cached value in
user return MSR being different from the hardware value if the previous
vCPU was a non-SEV-ES guest that had called kvm_set_user_return_msr().
Consequently, this may pose a problem when switching back to that vCPU,
as kvm_set_user_return_msr() would not update the hardware value because
the cached value matches the target value. Unlike the TDX case, the
SEV-ES guest has the ability to set the restore value in the host save
area, and the cached value in the user return MSR is always the current
hardware value. Therefore, the cached value could be used directly
without RDMSR in svm_prepare_switch_to_guest(), making this change
minimal.

Fixes: 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support for virtualized TSC_AUX")
Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
---
 arch/x86/kvm/svm/svm.c | 33 ++++++++++++++-------------------
 1 file changed, 14 insertions(+), 19 deletions(-)

diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 1650de78648a..1be9c65ee23b 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void)
 
 	amd_pmu_enable_virt();
 
-	/*
-	 * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type
-	 * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests.
-	 * Since Linux does not change the value of TSC_AUX once set, prime the
-	 * TSC_AUX field now to avoid a RDMSR on every vCPU run.
-	 */
-	if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
-		u32 __maybe_unused msr_hi;
-
-		rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
-	}
-
 	return 0;
 }
 
@@ -1408,12 +1396,19 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
 	/*
 	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
 	 * available. The user return MSR support is not required in this case
-	 * because TSC_AUX is restored on #VMEXIT from the host save area
-	 * (which has been initialized in svm_enable_virtualization_cpu()).
+	 * because TSC_AUX is restored on #VMEXIT from the host save area.
+	 * However, user return MSR could change the value of TSC_AUX in the
+	 * kernel. Therefore, to maintain the logic of user return MSR, set the
+	 * restore value to the cached value of user return MSR, which should
+	 * always reflect the current hardware value.
 	 */
-	if (likely(tsc_aux_uret_slot >= 0) &&
-	    (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
-		kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
+	if (likely(tsc_aux_uret_slot >= 0)) {
+		if (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm))
+			kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
+		else
+			sev_es_host_save_area(sd)->tsc_aux =
+				(u32)kvm_get_user_return_msr_cache(tsc_aux_uret_slot);
+	}
 
 	if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE) &&
 	    !sd->bp_spec_reduce_set) {
@@ -3004,8 +2999,8 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
 		 * TSC_AUX is always virtualized for SEV-ES guests when the
 		 * feature is available. The user return MSR support is not
 		 * required in this case because TSC_AUX is restored on #VMEXIT
-		 * from the host save area (which has been initialized in
-		 * svm_enable_virtualization_cpu()).
+		 * from the host save area (which has been set in
+		 * svm_prepare_switch_to_guest()).
 		 */
 		if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm))
 			break;
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-18  3:38 ` [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest Hou Wenlong
@ 2025-09-18 18:47   ` Tom Lendacky
  2025-09-19 13:15     ` Hou Wenlong
  0 siblings, 1 reply; 9+ messages in thread
From: Tom Lendacky @ 2025-09-18 18:47 UTC (permalink / raw)
  To: Hou Wenlong, kvm
  Cc: Lai Jiangshan, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, linux-kernel

On 9/17/25 22:38, Hou Wenlong wrote:
> The commit 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support
> for virtualized TSC_AUX") assumes that TSC_AUX is not changed by Linux
> post-boot, so it always restores the initial host value on #VMEXIT.
> However, this is not true in KVM, as it can be modified by user return
> MSR support for normal guests. If an SEV-ES guest always restores the
> initial host value on #VMEXIT, this may result in the cached value in
> user return MSR being different from the hardware value if the previous
> vCPU was a non-SEV-ES guest that had called kvm_set_user_return_msr().
> Consequently, this may pose a problem when switching back to that vCPU,
> as kvm_set_user_return_msr() would not update the hardware value because
> the cached value matches the target value. Unlike the TDX case, the
> SEV-ES guest has the ability to set the restore value in the host save
> area, and the cached value in the user return MSR is always the current
> hardware value. Therefore, the cached value could be used directly
> without RDMSR in svm_prepare_switch_to_guest(), making this change
> minimal.

I'm not sure I follow. If Linux never changes the value of TSC_AUX once it
has set it, then how can it ever be different? Have you seen this issue?

Thanks,
Tom

> 
> Fixes: 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support for virtualized TSC_AUX")
> Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
> Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> ---
>  arch/x86/kvm/svm/svm.c | 33 ++++++++++++++-------------------
>  1 file changed, 14 insertions(+), 19 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 1650de78648a..1be9c65ee23b 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void)
>  
>  	amd_pmu_enable_virt();
>  
> -	/*
> -	 * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type
> -	 * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests.
> -	 * Since Linux does not change the value of TSC_AUX once set, prime the
> -	 * TSC_AUX field now to avoid a RDMSR on every vCPU run.
> -	 */
> -	if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
> -		u32 __maybe_unused msr_hi;
> -
> -		rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
> -	}
> -
>  	return 0;
>  }
>  
> @@ -1408,12 +1396,19 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
>  	/*
>  	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
>  	 * available. The user return MSR support is not required in this case
> -	 * because TSC_AUX is restored on #VMEXIT from the host save area
> -	 * (which has been initialized in svm_enable_virtualization_cpu()).
> +	 * because TSC_AUX is restored on #VMEXIT from the host save area.
> +	 * However, user return MSR could change the value of TSC_AUX in the
> +	 * kernel. Therefore, to maintain the logic of user return MSR, set the
> +	 * restore value to the cached value of user return MSR, which should
> +	 * always reflect the current hardware value.
>  	 */
> -	if (likely(tsc_aux_uret_slot >= 0) &&
> -	    (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
> -		kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
> +	if (likely(tsc_aux_uret_slot >= 0)) {
> +		if (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm))
> +			kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
> +		else
> +			sev_es_host_save_area(sd)->tsc_aux =
> +				(u32)kvm_get_user_return_msr_cache(tsc_aux_uret_slot);
> +	}
>  
>  	if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE) &&
>  	    !sd->bp_spec_reduce_set) {
> @@ -3004,8 +2999,8 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
>  		 * TSC_AUX is always virtualized for SEV-ES guests when the
>  		 * feature is available. The user return MSR support is not
>  		 * required in this case because TSC_AUX is restored on #VMEXIT
> -		 * from the host save area (which has been initialized in
> -		 * svm_enable_virtualization_cpu()).
> +		 * from the host save area (which has been set in
> +		 * svm_prepare_switch_to_guest()).
>  		 */
>  		if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm))
>  			break;


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-18 18:47   ` Tom Lendacky
@ 2025-09-19 13:15     ` Hou Wenlong
  2025-09-19 16:23       ` Sean Christopherson
  0 siblings, 1 reply; 9+ messages in thread
From: Hou Wenlong @ 2025-09-19 13:15 UTC (permalink / raw)
  To: Tom Lendacky
  Cc: kvm, Lai Jiangshan, Sean Christopherson, Paolo Bonzini,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, linux-kernel

On Thu, Sep 18, 2025 at 01:47:06PM -0500, Tom Lendacky wrote:
> On 9/17/25 22:38, Hou Wenlong wrote:
> > The commit 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support
> > for virtualized TSC_AUX") assumes that TSC_AUX is not changed by Linux
> > post-boot, so it always restores the initial host value on #VMEXIT.
> > However, this is not true in KVM, as it can be modified by user return
> > MSR support for normal guests. If an SEV-ES guest always restores the
> > initial host value on #VMEXIT, this may result in the cached value in
> > user return MSR being different from the hardware value if the previous
> > vCPU was a non-SEV-ES guest that had called kvm_set_user_return_msr().
> > Consequently, this may pose a problem when switching back to that vCPU,
> > as kvm_set_user_return_msr() would not update the hardware value because
> > the cached value matches the target value. Unlike the TDX case, the
> > SEV-ES guest has the ability to set the restore value in the host save
> > area, and the cached value in the user return MSR is always the current
> > hardware value. Therefore, the cached value could be used directly
> > without RDMSR in svm_prepare_switch_to_guest(), making this change
> > minimal.
> 
> I'm not sure I follow. If Linux never changes the value of TSC_AUX once it
> has set it, then how can it ever be different? Have you seen this issue?
> 
> Thanks,
> Tom
>
Hi, Tom.

IIUD, the normal guest still uses the user return MSR to load the guest
TSC_AUX value into the hardware when TSC_AUX virtualization is
supported.  However, the user return MSR only restores the host value
when returning to userspace, rather than when the vCPU is scheduled out.
This may lead to an issue during vCPU switching on a single pCPU, which
appears as follows:

       normal vCPU -> SEV-ES vCPU -> normal vCPU

When the normal vCPU switches to the SEV-ES vCPU, the hardware TSC_AUX
value remains as the guest value set in kvm_set_user_return_msr() by the
normal vCPU.  After the #VMEXIT from the SEV-ES vCPU, the hardware value
becomes the host value. However, the cached TSC_AUX value in the user
return MSR remains the guest value of previous normal vCPU. Therefore,
when switching back to that normal vCPU, kvm_set_user_return_msr() does
not perform a WRMSR to load the guest value into the hardware, because
the cached value matches the target value. As a result, during the
execution of the normal vCPU, the normal vCPU would get an incorrect
TSC_AUX value for RDTSCP/RDPID.

I didn't find the available description of TSC_AUX virtualization in
APM; all my analysis is based on the current KVM code. Am I missing
something?

Thanks.

> > 
> > Fixes: 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support for virtualized TSC_AUX")
> > Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
> > Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> > ---
> >  arch/x86/kvm/svm/svm.c | 33 ++++++++++++++-------------------
> >  1 file changed, 14 insertions(+), 19 deletions(-)
> > 
> > diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> > index 1650de78648a..1be9c65ee23b 100644
> > --- a/arch/x86/kvm/svm/svm.c
> > +++ b/arch/x86/kvm/svm/svm.c
> > @@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void)
> >  
> >  	amd_pmu_enable_virt();
> >  
> > -	/*
> > -	 * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type
> > -	 * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests.
> > -	 * Since Linux does not change the value of TSC_AUX once set, prime the
> > -	 * TSC_AUX field now to avoid a RDMSR on every vCPU run.
> > -	 */
> > -	if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
> > -		u32 __maybe_unused msr_hi;
> > -
> > -		rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
> > -	}
> > -
> >  	return 0;
> >  }
> >  
> > @@ -1408,12 +1396,19 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
> >  	/*
> >  	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
> >  	 * available. The user return MSR support is not required in this case
> > -	 * because TSC_AUX is restored on #VMEXIT from the host save area
> > -	 * (which has been initialized in svm_enable_virtualization_cpu()).
> > +	 * because TSC_AUX is restored on #VMEXIT from the host save area.
> > +	 * However, user return MSR could change the value of TSC_AUX in the
> > +	 * kernel. Therefore, to maintain the logic of user return MSR, set the
> > +	 * restore value to the cached value of user return MSR, which should
> > +	 * always reflect the current hardware value.
> >  	 */
> > -	if (likely(tsc_aux_uret_slot >= 0) &&
> > -	    (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
> > -		kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
> > +	if (likely(tsc_aux_uret_slot >= 0)) {
> > +		if (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm))
> > +			kvm_set_user_return_msr(tsc_aux_uret_slot, svm->tsc_aux, -1ull);
> > +		else
> > +			sev_es_host_save_area(sd)->tsc_aux =
> > +				(u32)kvm_get_user_return_msr_cache(tsc_aux_uret_slot);
> > +	}
> >  
> >  	if (cpu_feature_enabled(X86_FEATURE_SRSO_BP_SPEC_REDUCE) &&
> >  	    !sd->bp_spec_reduce_set) {
> > @@ -3004,8 +2999,8 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
> >  		 * TSC_AUX is always virtualized for SEV-ES guests when the
> >  		 * feature is available. The user return MSR support is not
> >  		 * required in this case because TSC_AUX is restored on #VMEXIT
> > -		 * from the host save area (which has been initialized in
> > -		 * svm_enable_virtualization_cpu()).
> > +		 * from the host save area (which has been set in
> > +		 * svm_prepare_switch_to_guest()).
> >  		 */
> >  		if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm))
> >  			break;

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-19 13:15     ` Hou Wenlong
@ 2025-09-19 16:23       ` Sean Christopherson
  2025-09-19 16:30         ` Sean Christopherson
  2025-09-20  6:52         ` Hou Wenlong
  0 siblings, 2 replies; 9+ messages in thread
From: Sean Christopherson @ 2025-09-19 16:23 UTC (permalink / raw)
  To: Hou Wenlong
  Cc: Tom Lendacky, kvm, Lai Jiangshan, Paolo Bonzini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	linux-kernel

On Fri, Sep 19, 2025, Hou Wenlong wrote:
> On Thu, Sep 18, 2025 at 01:47:06PM -0500, Tom Lendacky wrote:
> > On 9/17/25 22:38, Hou Wenlong wrote:
> > > The commit 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support
> > > for virtualized TSC_AUX") assumes that TSC_AUX is not changed by Linux
> > > post-boot, so it always restores the initial host value on #VMEXIT.
> > > However, this is not true in KVM, as it can be modified by user return
> > > MSR support for normal guests. If an SEV-ES guest always restores the
> > > initial host value on #VMEXIT, this may result in the cached value in
> > > user return MSR being different from the hardware value if the previous
> > > vCPU was a non-SEV-ES guest that had called kvm_set_user_return_msr().
> > > Consequently, this may pose a problem when switching back to that vCPU,
> > > as kvm_set_user_return_msr() would not update the hardware value because
> > > the cached value matches the target value. Unlike the TDX case, the
> > > SEV-ES guest has the ability to set the restore value in the host save
> > > area, and the cached value in the user return MSR is always the current
> > > hardware value. Therefore, the cached value could be used directly
> > > without RDMSR in svm_prepare_switch_to_guest(), making this change
> > > minimal.
> > 
> > I'm not sure I follow. If Linux never changes the value of TSC_AUX once it
> > has set it, then how can it ever be different? Have you seen this issue?
> > 
> > Thanks,
> > Tom
> >
> Hi, Tom.
> 
> IIUD, the normal guest still uses the user return MSR to load the guest
> TSC_AUX value into the hardware when TSC_AUX virtualization is
> supported.  However, the user return MSR only restores the host value
> when returning to userspace, rather than when the vCPU is scheduled out.
> This may lead to an issue during vCPU switching on a single pCPU, which
> appears as follows:
> 
>        normal vCPU -> SEV-ES vCPU -> normal vCPU
> 
> When the normal vCPU switches to the SEV-ES vCPU, the hardware TSC_AUX
> value remains as the guest value set in kvm_set_user_return_msr() by the
> normal vCPU.  After the #VMEXIT from the SEV-ES vCPU, the hardware value
> becomes the host value. However, the cached TSC_AUX value in the user
> return MSR remains the guest value of previous normal vCPU. Therefore,
> when switching back to that normal vCPU, kvm_set_user_return_msr() does
> not perform a WRMSR to load the guest value into the hardware, because
> the cached value matches the target value. As a result, during the
> execution of the normal vCPU, the normal vCPU would get an incorrect
> TSC_AUX value for RDTSCP/RDPID.
> 
> I didn't find the available description of TSC_AUX virtualization in
> APM; all my analysis is based on the current KVM code.

I'm guessing TSC_AUX virtualization works like SEV-ES, where hardware context
switches the MSR on VMRUN/#VMEXIT.

> Am I missing something?

Nope, I don't think so.  I also found the changelog a bit confusing though.  I
would say omit the details about Linux not changing the value, and instead focus
on the need to re-load the current hardware value.  That should be intuitive for
all readers, and is correct regradless of what/whose value is currently in hardware.

I also think we should handle setting hostsa->tsc_aux in
sev_es_prepare_switch_to_guest().  That obviously requires duplicating some of
logic related to SEV-ES and TSC_AUX, but I think I prefer that to splitting the
handling of the host save area.

How's this look? (compile tested only)

--
Subject: [PATCH] KVM: SVM: Re-load current, not host, TSC_AUX on #VMEXIT from
 SEV-ES guest

Prior to running an SEV-ES guest, set TSC_AUX in the host save area to the
current value in hardware, as tracked by the user return infrastructure,
instead of always loading the host's desired value for the CPU.  If the
pCPU is also running a non-SEV-ES vCPU, loading the hosts value on #VMEXIT
could clobber the other vCPU's value, e.g. if the SEV-ES vCPU preempted
the non-SEV-ES vCPU.

Note, unlike TDX, which blindly _zeroes_ TSC_AUX on exit, SEV-ES CPUs
can load an arbitrary value.  Stuff the current value in the host save
area instead of refreshing the user return cache so that KVM doesn't need
to track whether or not the vCPU actually enterred the guest and thus
loaded TSC_AUX from the host save area.

Fixes: 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support for virtualized TSC_AUX")
Cc: stable@vger.kernel.org
Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
[sean: handle the SEV-ES case in sev_es_prepare_switch_to_guest()]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 arch/x86/kvm/svm/sev.c | 14 +++++++++++++-
 arch/x86/kvm/svm/svm.c | 26 +++++++-------------------
 arch/x86/kvm/svm/svm.h |  4 +++-
 3 files changed, 23 insertions(+), 21 deletions(-)

diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
index cce48fff2e6c..95767b9d0d55 100644
--- a/arch/x86/kvm/svm/sev.c
+++ b/arch/x86/kvm/svm/sev.c
@@ -4664,7 +4664,9 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu)
 	return 0;
 }
 
-void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa)
+void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm,
+				    struct sev_es_save_area *hostsa,
+				    int tsc_aux_uret_slot)
 {
 	struct kvm *kvm = svm->vcpu.kvm;
 
@@ -4712,6 +4714,16 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are
 		hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2);
 		hostsa->dr3_addr_mask = amd_get_dr_addr_mask(3);
 	}
+
+	/*
+	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
+	 * available, i.e. TSC_AUX is loaded on #VMEXIT from the host save area.
+	 * Set the save area to the current hardware value, i.e. the current
+	 * user return value, so that the correct value is restored on #VMEXIT.
+	 */
+	if (cpu_feature_enabled(X86_FEATURE_V_TSC_AUX) &&
+	    !WARN_ON_ONCE(tsc_aux_uret_slot < 0))
+		hostsa->tsc_aux = kvm_get_user_return_msr(tsc_aux_uret_slot);
 }
 
 void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index 67f4eed01526..662cf680faf7 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void)
 
 	amd_pmu_enable_virt();
 
-	/*
-	 * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type
-	 * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests.
-	 * Since Linux does not change the value of TSC_AUX once set, prime the
-	 * TSC_AUX field now to avoid a RDMSR on every vCPU run.
-	 */
-	if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
-		u32 __maybe_unused msr_hi;
-
-		rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
-	}
-
 	return 0;
 }
 
@@ -1400,16 +1388,17 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
 	 */
 	vmsave(sd->save_area_pa);
 	if (sev_es_guest(vcpu->kvm))
-		sev_es_prepare_switch_to_guest(svm, sev_es_host_save_area(sd));
+		sev_es_prepare_switch_to_guest(svm, sev_es_host_save_area(sd),
+					       tsc_aux_uret_slot);
 
 	if (tsc_scaling)
 		__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
 
 	/*
-	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
-	 * available. The user return MSR support is not required in this case
-	 * because TSC_AUX is restored on #VMEXIT from the host save area
-	 * (which has been initialized in svm_enable_virtualization_cpu()).
+	 * TSC_AUX is always virtualized (context switched by hardware) for
+	 * SEV-ES guests when the feature is available.  For non-SEV-ES guests,
+	 * context switch TSC_AUX via the user_return MSR infrastructure (not
+	 * all CPUs support TSC_AUX virtualization).
 	 */
 	if (likely(tsc_aux_uret_slot >= 0) &&
 	    (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
@@ -3004,8 +2993,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
 		 * TSC_AUX is always virtualized for SEV-ES guests when the
 		 * feature is available. The user return MSR support is not
 		 * required in this case because TSC_AUX is restored on #VMEXIT
-		 * from the host save area (which has been initialized in
-		 * svm_enable_virtualization_cpu()).
+		 * from the host save area.
 		 */
 		if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm))
 			break;
diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
index 5d39c0b17988..4fda677e8ab3 100644
--- a/arch/x86/kvm/svm/svm.h
+++ b/arch/x86/kvm/svm/svm.h
@@ -831,7 +831,9 @@ void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm);
 int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);
 void sev_es_recalc_msr_intercepts(struct kvm_vcpu *vcpu);
 void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
-void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa);
+void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm,
+				    struct sev_es_save_area *hostsa,
+				    int tsc_aux_uret_slot);
 void sev_es_unmap_ghcb(struct vcpu_svm *svm);
 
 #ifdef CONFIG_KVM_AMD_SEV

base-commit: 60e396349c19320485a249005256d1fafee60290
--

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR
  2025-09-18  3:38 [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR Hou Wenlong
  2025-09-18  3:38 ` [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest Hou Wenlong
@ 2025-09-19 16:28 ` Sean Christopherson
  1 sibling, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2025-09-19 16:28 UTC (permalink / raw)
  To: Hou Wenlong
  Cc: kvm, Lai Jiangshan, Paolo Bonzini, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, linux-kernel

On Thu, Sep 18, 2025, Hou Wenlong wrote:
> In the user return MSR support, the cached value is always the hardware
> value of the specific MSR. Therefore, add a helper to retrieve the
> cached value, which can replace the need for RDMSR, for example, to
> allow SEV-ES guests to restore the correct host hardware value without
> using RDMSR.
> 
> Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> ---
>  arch/x86/include/asm/kvm_host.h | 1 +
>  arch/x86/kvm/x86.c              | 8 ++++++++
>  2 files changed, 9 insertions(+)
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index cb86f3cca3e9..2cbb0f446a9b 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -2376,6 +2376,7 @@ int kvm_add_user_return_msr(u32 msr);
>  int kvm_find_user_return_msr(u32 msr);
>  int kvm_set_user_return_msr(unsigned index, u64 val, u64 mask);
>  void kvm_user_return_msr_update_cache(unsigned int index, u64 val);
> +u64 kvm_get_user_return_msr_cache(unsigned int index);

s/index/slot (the existing helpers need to be changed).  The user_return APIs
deliberately use "slot" to try and make it more obvious that they take the slot
within the array, not the index of the MSR.

>  static inline bool kvm_is_supported_user_return_msr(u32 msr)
>  {
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 6d85fbafc679..88d26c86c3b2 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -675,6 +675,14 @@ void kvm_user_return_msr_update_cache(unsigned int slot, u64 value)
>  }
>  EXPORT_SYMBOL_GPL(kvm_user_return_msr_update_cache);
>  
> +u64 kvm_get_user_return_msr_cache(unsigned int slot)

I vote to drop "cache".  I don't love the existing kvm_user_return_msr_update_cache()
name (or implementation).  I would much rather that code be (I'll post a separate
patch) the below, to capture that the "cache" version is performing a subest of
the kvm_set_user_return_msr(). 

void __kvm_set_user_return_msr(unsigned int slot, u64 value)
{
	struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs);

	msrs->values[slot].curr = value;
	kvm_user_return_register_notifier(msrs);
}
EXPORT_SYMBOL_GPL(__kvm_set_user_return_msr);

int kvm_set_user_return_msr(unsigned slot, u64 value, u64 mask)
{
	struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs);
	int err;

	value = (value & mask) | (msrs->values[slot].host & ~mask);
	if (value == msrs->values[slot].curr)
		return 0;
	err = wrmsrq_safe(kvm_uret_msrs_list[slot], value);
	if (err)
		return 1;

	__kvm_set_user_return_msr(slot, value);
	return 0;
}
EXPORT_SYMBOL_GPL(kvm_set_user_return_msr);

> +{
> +	struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs);
> +
> +	return msrs->values[slot].curr;

This can be a one-liner.  How about this?

---
 arch/x86/include/asm/kvm_host.h | 1 +
 arch/x86/kvm/x86.c              | 6 ++++++
 2 files changed, 7 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 17772513b9cc..14236006266b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -2376,6 +2376,7 @@ int kvm_add_user_return_msr(u32 msr);
 int kvm_find_user_return_msr(u32 msr);
 int kvm_set_user_return_msr(unsigned index, u64 val, u64 mask);
 void kvm_user_return_msr_update_cache(unsigned int index, u64 val);
+u64 kvm_get_user_return_msr(unsigned int slot);
 
 static inline bool kvm_is_supported_user_return_msr(u32 msr)
 {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e07936efacd4..801bf6172a21 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -675,6 +675,12 @@ void kvm_user_return_msr_update_cache(unsigned int slot, u64 value)
 }
 EXPORT_SYMBOL_GPL(kvm_user_return_msr_update_cache);
 
+u64 kvm_get_user_return_msr(unsigned int slot)
+{
+	return this_cpu_ptr(user_return_msrs)->values[slot].curr;
+}
+EXPORT_SYMBOL_GPL(kvm_get_user_return_msr);
+
 static void drop_user_return_notifiers(void)
 {
 	struct kvm_user_return_msrs *msrs = this_cpu_ptr(user_return_msrs);

base-commit: c8fbf7ceb2ae3f64b0c377c8c21f6df577a13eb4
-- 

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-19 16:23       ` Sean Christopherson
@ 2025-09-19 16:30         ` Sean Christopherson
  2025-09-19 16:45           ` Sean Christopherson
  2025-09-20  6:52         ` Hou Wenlong
  1 sibling, 1 reply; 9+ messages in thread
From: Sean Christopherson @ 2025-09-19 16:30 UTC (permalink / raw)
  To: Hou Wenlong
  Cc: Tom Lendacky, kvm, Lai Jiangshan, Paolo Bonzini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	linux-kernel

On Fri, Sep 19, 2025, Sean Christopherson wrote:
> On Fri, Sep 19, 2025, Hou Wenlong wrote:
> > On Thu, Sep 18, 2025 at 01:47:06PM -0500, Tom Lendacky wrote:
> How's this look? (compile tested only)

Almost forgot...

If the suggested changes look good, no need to send a v2, I'll apply with my
suggested fixups (but definitely feel free to object to any of the suggestions).

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-19 16:30         ` Sean Christopherson
@ 2025-09-19 16:45           ` Sean Christopherson
  0 siblings, 0 replies; 9+ messages in thread
From: Sean Christopherson @ 2025-09-19 16:45 UTC (permalink / raw)
  To: Hou Wenlong
  Cc: Tom Lendacky, kvm, Lai Jiangshan, Paolo Bonzini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	linux-kernel

On Fri, Sep 19, 2025, Sean Christopherson wrote:
> On Fri, Sep 19, 2025, Sean Christopherson wrote:
> > On Fri, Sep 19, 2025, Hou Wenlong wrote:
> > > On Thu, Sep 18, 2025 at 01:47:06PM -0500, Tom Lendacky wrote:
> > How's this look? (compile tested only)
> 
> Almost forgot...
> 
> If the suggested changes look good, no need to send a v2, I'll apply with my
> suggested fixups (but definitely feel free to object to any of the suggestions).

And talking to myself...  On second thought, I'll officially post a v2 so that
there's a better paper trail.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest
  2025-09-19 16:23       ` Sean Christopherson
  2025-09-19 16:30         ` Sean Christopherson
@ 2025-09-20  6:52         ` Hou Wenlong
  1 sibling, 0 replies; 9+ messages in thread
From: Hou Wenlong @ 2025-09-20  6:52 UTC (permalink / raw)
  To: Sean Christopherson
  Cc: Tom Lendacky, kvm, Lai Jiangshan, Paolo Bonzini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	linux-kernel

On Fri, Sep 19, 2025 at 09:23:26AM -0700, Sean Christopherson wrote:
> On Fri, Sep 19, 2025, Hou Wenlong wrote:
> > On Thu, Sep 18, 2025 at 01:47:06PM -0500, Tom Lendacky wrote:
> > > On 9/17/25 22:38, Hou Wenlong wrote:
> > > > The commit 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support
> > > > for virtualized TSC_AUX") assumes that TSC_AUX is not changed by Linux
> > > > post-boot, so it always restores the initial host value on #VMEXIT.
> > > > However, this is not true in KVM, as it can be modified by user return
> > > > MSR support for normal guests. If an SEV-ES guest always restores the
> > > > initial host value on #VMEXIT, this may result in the cached value in
> > > > user return MSR being different from the hardware value if the previous
> > > > vCPU was a non-SEV-ES guest that had called kvm_set_user_return_msr().
> > > > Consequently, this may pose a problem when switching back to that vCPU,
> > > > as kvm_set_user_return_msr() would not update the hardware value because
> > > > the cached value matches the target value. Unlike the TDX case, the
> > > > SEV-ES guest has the ability to set the restore value in the host save
> > > > area, and the cached value in the user return MSR is always the current
> > > > hardware value. Therefore, the cached value could be used directly
> > > > without RDMSR in svm_prepare_switch_to_guest(), making this change
> > > > minimal.
> > > 
> > > I'm not sure I follow. If Linux never changes the value of TSC_AUX once it
> > > has set it, then how can it ever be different? Have you seen this issue?
> > > 
> > > Thanks,
> > > Tom
> > >
> > Hi, Tom.
> > 
> > IIUD, the normal guest still uses the user return MSR to load the guest
> > TSC_AUX value into the hardware when TSC_AUX virtualization is
> > supported.  However, the user return MSR only restores the host value
> > when returning to userspace, rather than when the vCPU is scheduled out.
> > This may lead to an issue during vCPU switching on a single pCPU, which
> > appears as follows:
> > 
> >        normal vCPU -> SEV-ES vCPU -> normal vCPU
> > 
> > When the normal vCPU switches to the SEV-ES vCPU, the hardware TSC_AUX
> > value remains as the guest value set in kvm_set_user_return_msr() by the
> > normal vCPU.  After the #VMEXIT from the SEV-ES vCPU, the hardware value
> > becomes the host value. However, the cached TSC_AUX value in the user
> > return MSR remains the guest value of previous normal vCPU. Therefore,
> > when switching back to that normal vCPU, kvm_set_user_return_msr() does
> > not perform a WRMSR to load the guest value into the hardware, because
> > the cached value matches the target value. As a result, during the
> > execution of the normal vCPU, the normal vCPU would get an incorrect
> > TSC_AUX value for RDTSCP/RDPID.
> > 
> > I didn't find the available description of TSC_AUX virtualization in
> > APM; all my analysis is based on the current KVM code.
> 
> I'm guessing TSC_AUX virtualization works like SEV-ES, where hardware context
> switches the MSR on VMRUN/#VMEXIT.
> 
> > Am I missing something?
> 
> Nope, I don't think so.  I also found the changelog a bit confusing though.  I
> would say omit the details about Linux not changing the value, and instead focus
> on the need to re-load the current hardware value.  That should be intuitive for
> all readers, and is correct regradless of what/whose value is currently in hardware.
> 
> I also think we should handle setting hostsa->tsc_aux in
> sev_es_prepare_switch_to_guest().  That obviously requires duplicating some of
> logic related to SEV-ES and TSC_AUX, but I think I prefer that to splitting the
> handling of the host save area.
> 
> How's this look? (compile tested only)
>

I'm fine with it. Thanks for your fixup; I think I need to improve my
changlog next time. :)

Thanks!

> --
> Subject: [PATCH] KVM: SVM: Re-load current, not host, TSC_AUX on #VMEXIT from
>  SEV-ES guest
> 
> Prior to running an SEV-ES guest, set TSC_AUX in the host save area to the
> current value in hardware, as tracked by the user return infrastructure,
> instead of always loading the host's desired value for the CPU.  If the
> pCPU is also running a non-SEV-ES vCPU, loading the hosts value on #VMEXIT
> could clobber the other vCPU's value, e.g. if the SEV-ES vCPU preempted
> the non-SEV-ES vCPU.
> 
> Note, unlike TDX, which blindly _zeroes_ TSC_AUX on exit, SEV-ES CPUs
> can load an arbitrary value.  Stuff the current value in the host save
> area instead of refreshing the user return cache so that KVM doesn't need
> to track whether or not the vCPU actually enterred the guest and thus
> loaded TSC_AUX from the host save area.
> 
> Fixes: 916e3e5f26ab ("KVM: SVM: Do not use user return MSR support for virtualized TSC_AUX")
> Cc: stable@vger.kernel.org
> Suggested-by: Lai Jiangshan <jiangshan.ljs@antgroup.com>
> Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> [sean: handle the SEV-ES case in sev_es_prepare_switch_to_guest()]
> Signed-off-by: Sean Christopherson <seanjc@google.com>
> ---
>  arch/x86/kvm/svm/sev.c | 14 +++++++++++++-
>  arch/x86/kvm/svm/svm.c | 26 +++++++-------------------
>  arch/x86/kvm/svm/svm.h |  4 +++-
>  3 files changed, 23 insertions(+), 21 deletions(-)
> 
> diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
> index cce48fff2e6c..95767b9d0d55 100644
> --- a/arch/x86/kvm/svm/sev.c
> +++ b/arch/x86/kvm/svm/sev.c
> @@ -4664,7 +4664,9 @@ int sev_vcpu_create(struct kvm_vcpu *vcpu)
>  	return 0;
>  }
>  
> -void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa)
> +void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm,
> +				    struct sev_es_save_area *hostsa,
> +				    int tsc_aux_uret_slot)
>  {
>  	struct kvm *kvm = svm->vcpu.kvm;
>  
> @@ -4712,6 +4714,16 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are
>  		hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2);
>  		hostsa->dr3_addr_mask = amd_get_dr_addr_mask(3);
>  	}
> +
> +	/*
> +	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
> +	 * available, i.e. TSC_AUX is loaded on #VMEXIT from the host save area.
> +	 * Set the save area to the current hardware value, i.e. the current
> +	 * user return value, so that the correct value is restored on #VMEXIT.
> +	 */
> +	if (cpu_feature_enabled(X86_FEATURE_V_TSC_AUX) &&
> +	    !WARN_ON_ONCE(tsc_aux_uret_slot < 0))
> +		hostsa->tsc_aux = kvm_get_user_return_msr(tsc_aux_uret_slot);
>  }
>  
>  void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)
> diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
> index 67f4eed01526..662cf680faf7 100644
> --- a/arch/x86/kvm/svm/svm.c
> +++ b/arch/x86/kvm/svm/svm.c
> @@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void)
>  
>  	amd_pmu_enable_virt();
>  
> -	/*
> -	 * If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type
> -	 * "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests.
> -	 * Since Linux does not change the value of TSC_AUX once set, prime the
> -	 * TSC_AUX field now to avoid a RDMSR on every vCPU run.
> -	 */
> -	if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
> -		u32 __maybe_unused msr_hi;
> -
> -		rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
> -	}
> -
>  	return 0;
>  }
>  
> @@ -1400,16 +1388,17 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
>  	 */
>  	vmsave(sd->save_area_pa);
>  	if (sev_es_guest(vcpu->kvm))
> -		sev_es_prepare_switch_to_guest(svm, sev_es_host_save_area(sd));
> +		sev_es_prepare_switch_to_guest(svm, sev_es_host_save_area(sd),
> +					       tsc_aux_uret_slot);
>  
>  	if (tsc_scaling)
>  		__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
>  
>  	/*
> -	 * TSC_AUX is always virtualized for SEV-ES guests when the feature is
> -	 * available. The user return MSR support is not required in this case
> -	 * because TSC_AUX is restored on #VMEXIT from the host save area
> -	 * (which has been initialized in svm_enable_virtualization_cpu()).
> +	 * TSC_AUX is always virtualized (context switched by hardware) for
> +	 * SEV-ES guests when the feature is available.  For non-SEV-ES guests,
> +	 * context switch TSC_AUX via the user_return MSR infrastructure (not
> +	 * all CPUs support TSC_AUX virtualization).
>  	 */
>  	if (likely(tsc_aux_uret_slot >= 0) &&
>  	    (!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
> @@ -3004,8 +2993,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
>  		 * TSC_AUX is always virtualized for SEV-ES guests when the
>  		 * feature is available. The user return MSR support is not
>  		 * required in this case because TSC_AUX is restored on #VMEXIT
> -		 * from the host save area (which has been initialized in
> -		 * svm_enable_virtualization_cpu()).
> +		 * from the host save area.
>  		 */
>  		if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm))
>  			break;
> diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
> index 5d39c0b17988..4fda677e8ab3 100644
> --- a/arch/x86/kvm/svm/svm.h
> +++ b/arch/x86/kvm/svm/svm.h
> @@ -831,7 +831,9 @@ void sev_vcpu_after_set_cpuid(struct vcpu_svm *svm);
>  int sev_es_string_io(struct vcpu_svm *svm, int size, unsigned int port, int in);
>  void sev_es_recalc_msr_intercepts(struct kvm_vcpu *vcpu);
>  void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector);
> -void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_area *hostsa);
> +void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm,
> +				    struct sev_es_save_area *hostsa,
> +				    int tsc_aux_uret_slot);
>  void sev_es_unmap_ghcb(struct vcpu_svm *svm);
>  
>  #ifdef CONFIG_KVM_AMD_SEV
> 
> base-commit: 60e396349c19320485a249005256d1fafee60290
> --

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-09-20  6:52 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18  3:38 [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR Hou Wenlong
2025-09-18  3:38 ` [PATCH 2/2] KVM: SVM: Use cached value as restore value of TSC_AUX for SEV-ES guest Hou Wenlong
2025-09-18 18:47   ` Tom Lendacky
2025-09-19 13:15     ` Hou Wenlong
2025-09-19 16:23       ` Sean Christopherson
2025-09-19 16:30         ` Sean Christopherson
2025-09-19 16:45           ` Sean Christopherson
2025-09-20  6:52         ` Hou Wenlong
2025-09-19 16:28 ` [PATCH 1/2] KVM: x86: Add helper to retrieve cached value of user return MSR Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox