Skip to content

Commit 29da8c8

Browse files
bysuisean-jc
authored andcommitted
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 host's value on #VMEXIT could clobber the other vCPU's value, e.g. if the SEV-ES vCPU preempted the non-SEV-ES vCPU, in which case KVM expects the other vCPU's TSC_AUX value to be resident in hardware. Note, unlike TDX, which blindly _zeroes_ TSC_AUX on TD-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. Opportunistically tag tsc_aux_uret_slot as read-only after init to guard against unexpected modifications, and to make it obvious that using the variable in sev_es_prepare_switch_to_guest() is safe. Fixes: 916e3e5 ("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()] Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com> Link: https://lore.kernel.org/r/20250923153738.1875174-3-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 9bc3663 commit 29da8c8

File tree

3 files changed

+18
-19
lines changed

3 files changed

+18
-19
lines changed

arch/x86/kvm/svm/sev.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4666,6 +4666,16 @@ void sev_es_prepare_switch_to_guest(struct vcpu_svm *svm, struct sev_es_save_are
46664666
hostsa->dr2_addr_mask = amd_get_dr_addr_mask(2);
46674667
hostsa->dr3_addr_mask = amd_get_dr_addr_mask(3);
46684668
}
4669+
4670+
/*
4671+
* TSC_AUX is always virtualized for SEV-ES guests when the feature is
4672+
* available, i.e. TSC_AUX is loaded on #VMEXIT from the host save area.
4673+
* Set the save area to the current hardware value, i.e. the current
4674+
* user return value, so that the correct value is restored on #VMEXIT.
4675+
*/
4676+
if (cpu_feature_enabled(X86_FEATURE_V_TSC_AUX) &&
4677+
!WARN_ON_ONCE(tsc_aux_uret_slot < 0))
4678+
hostsa->tsc_aux = kvm_get_user_return_msr(tsc_aux_uret_slot);
46694679
}
46704680

46714681
void sev_vcpu_deliver_sipi_vector(struct kvm_vcpu *vcpu, u8 vector)

arch/x86/kvm/svm/svm.c

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ static DEFINE_MUTEX(vmcb_dump_mutex);
195195
* RDTSCP and RDPID are not used in the kernel, specifically to allow KVM to
196196
* defer the restoration of TSC_AUX until the CPU returns to userspace.
197197
*/
198-
static int tsc_aux_uret_slot __read_mostly = -1;
198+
int tsc_aux_uret_slot __ro_after_init = -1;
199199

200200
static int get_npt_level(void)
201201
{
@@ -577,18 +577,6 @@ static int svm_enable_virtualization_cpu(void)
577577

578578
amd_pmu_enable_virt();
579579

580-
/*
581-
* If TSC_AUX virtualization is supported, TSC_AUX becomes a swap type
582-
* "B" field (see sev_es_prepare_switch_to_guest()) for SEV-ES guests.
583-
* Since Linux does not change the value of TSC_AUX once set, prime the
584-
* TSC_AUX field now to avoid a RDMSR on every vCPU run.
585-
*/
586-
if (boot_cpu_has(X86_FEATURE_V_TSC_AUX)) {
587-
u32 __maybe_unused msr_hi;
588-
589-
rdmsr(MSR_TSC_AUX, sev_es_host_save_area(sd)->tsc_aux, msr_hi);
590-
}
591-
592580
return 0;
593581
}
594582

@@ -1406,10 +1394,10 @@ static void svm_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
14061394
__svm_write_tsc_multiplier(vcpu->arch.tsc_scaling_ratio);
14071395

14081396
/*
1409-
* TSC_AUX is always virtualized for SEV-ES guests when the feature is
1410-
* available. The user return MSR support is not required in this case
1411-
* because TSC_AUX is restored on #VMEXIT from the host save area
1412-
* (which has been initialized in svm_enable_virtualization_cpu()).
1397+
* TSC_AUX is always virtualized (context switched by hardware) for
1398+
* SEV-ES guests when the feature is available. For non-SEV-ES guests,
1399+
* context switch TSC_AUX via the user_return MSR infrastructure (not
1400+
* all CPUs support TSC_AUX virtualization).
14131401
*/
14141402
if (likely(tsc_aux_uret_slot >= 0) &&
14151403
(!boot_cpu_has(X86_FEATURE_V_TSC_AUX) || !sev_es_guest(vcpu->kvm)))
@@ -3004,8 +2992,7 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
30042992
* TSC_AUX is always virtualized for SEV-ES guests when the
30052993
* feature is available. The user return MSR support is not
30062994
* required in this case because TSC_AUX is restored on #VMEXIT
3007-
* from the host save area (which has been initialized in
3008-
* svm_enable_virtualization_cpu()).
2995+
* from the host save area.
30092996
*/
30102997
if (boot_cpu_has(X86_FEATURE_V_TSC_AUX) && sev_es_guest(vcpu->kvm))
30112998
break;

arch/x86/kvm/svm/svm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ extern bool x2avic_enabled;
5252
extern bool vnmi;
5353
extern int lbrv;
5454

55+
extern int tsc_aux_uret_slot __ro_after_init;
56+
5557
/*
5658
* Clean bits in VMCB.
5759
* VMCB_ALL_CLEAN_MASK might also need to

0 commit comments

Comments
 (0)