@@ -213,6 +213,15 @@ struct kvm_ldttss_desc {
213
213
214
214
DEFINE_PER_CPU (struct svm_cpu_data * , svm_data );
215
215
216
+ /*
217
+ * Only MSR_TSC_AUX is switched via the user return hook. EFER is switched via
218
+ * the VMCB, and the SYSCALL/SYSENTER MSRs are handled by VMLOAD/VMSAVE.
219
+ *
220
+ * RDTSCP and RDPID are not used in the kernel, specifically to allow KVM to
221
+ * defer the restoration of TSC_AUX until the CPU returns to userspace.
222
+ */
223
+ #define TSC_AUX_URET_SLOT 0
224
+
216
225
static const u32 msrpm_ranges [] = {0 , 0xc0000000 , 0xc0010000 };
217
226
218
227
#define NUM_MSR_MAPS ARRAY_SIZE(msrpm_ranges)
@@ -958,6 +967,9 @@ static __init int svm_hardware_setup(void)
958
967
kvm_tsc_scaling_ratio_frac_bits = 32 ;
959
968
}
960
969
970
+ if (boot_cpu_has (X86_FEATURE_RDTSCP ))
971
+ kvm_define_user_return_msr (TSC_AUX_URET_SLOT , MSR_TSC_AUX );
972
+
961
973
/* Check for pause filtering support */
962
974
if (!boot_cpu_has (X86_FEATURE_PAUSEFILTER )) {
963
975
pause_filter_count = 0 ;
@@ -1423,19 +1435,10 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
1423
1435
{
1424
1436
struct vcpu_svm * svm = to_svm (vcpu );
1425
1437
struct svm_cpu_data * sd = per_cpu (svm_data , vcpu -> cpu );
1426
- unsigned int i ;
1427
1438
1428
1439
if (svm -> guest_state_loaded )
1429
1440
return ;
1430
1441
1431
- /*
1432
- * Certain MSRs are restored on VMEXIT (sev-es), or vmload of host save
1433
- * area (non-sev-es). Save ones that aren't so we can restore them
1434
- * individually later.
1435
- */
1436
- for (i = 0 ; i < NR_HOST_SAVE_USER_MSRS ; i ++ )
1437
- rdmsrl (host_save_user_msrs [i ], svm -> host_user_msrs [i ]);
1438
-
1439
1442
/*
1440
1443
* Save additional host state that will be restored on VMEXIT (sev-es)
1441
1444
* or subsequent vmload of host save area.
@@ -1454,29 +1457,15 @@ static void svm_prepare_guest_switch(struct kvm_vcpu *vcpu)
1454
1457
}
1455
1458
}
1456
1459
1457
- /* This assumes that the kernel never uses MSR_TSC_AUX */
1458
1460
if (static_cpu_has (X86_FEATURE_RDTSCP ))
1459
- wrmsrl ( MSR_TSC_AUX , svm -> tsc_aux );
1461
+ kvm_set_user_return_msr ( TSC_AUX_URET_SLOT , svm -> tsc_aux , -1ull );
1460
1462
1461
1463
svm -> guest_state_loaded = true;
1462
1464
}
1463
1465
1464
1466
static void svm_prepare_host_switch (struct kvm_vcpu * vcpu )
1465
1467
{
1466
- struct vcpu_svm * svm = to_svm (vcpu );
1467
- unsigned int i ;
1468
-
1469
- if (!svm -> guest_state_loaded )
1470
- return ;
1471
-
1472
- /*
1473
- * Certain MSRs are restored on VMEXIT (sev-es), or vmload of host save
1474
- * area (non-sev-es). Restore the ones that weren't.
1475
- */
1476
- for (i = 0 ; i < NR_HOST_SAVE_USER_MSRS ; i ++ )
1477
- wrmsrl (host_save_user_msrs [i ], svm -> host_user_msrs [i ]);
1478
-
1479
- svm -> guest_state_loaded = false;
1468
+ to_svm (vcpu )-> guest_state_loaded = false;
1480
1469
}
1481
1470
1482
1471
static void svm_vcpu_load (struct kvm_vcpu * vcpu , int cpu )
@@ -2790,6 +2779,7 @@ static int svm_set_vm_cr(struct kvm_vcpu *vcpu, u64 data)
2790
2779
static int svm_set_msr (struct kvm_vcpu * vcpu , struct msr_data * msr )
2791
2780
{
2792
2781
struct vcpu_svm * svm = to_svm (vcpu );
2782
+ int r ;
2793
2783
2794
2784
u32 ecx = msr -> index ;
2795
2785
u64 data = msr -> data ;
@@ -2910,11 +2900,16 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
2910
2900
data = (u32 )data ;
2911
2901
2912
2902
/*
2913
- * This is rare, so we update the MSR here instead of using
2914
- * direct_access_msrs . Doing that would require a rdmsr in
2915
- * svm_vcpu_put .
2903
+ * TSC_AUX is usually changed only during boot and never read
2904
+ * directly . Intercept TSC_AUX instead of exposing it to the
2905
+ * guest via direct_access_msrs, and switch it via user return .
2916
2906
*/
2917
- wrmsrl (MSR_TSC_AUX , data );
2907
+ preempt_disable ();
2908
+ r = kvm_set_user_return_msr (TSC_AUX_URET_SLOT , data , -1ull );
2909
+ preempt_enable ();
2910
+ if (r )
2911
+ return 1 ;
2912
+
2918
2913
svm -> tsc_aux = data ;
2919
2914
break ;
2920
2915
case MSR_IA32_DEBUGCTLMSR :
0 commit comments