@@ -741,8 +741,7 @@ static void __init calculate_hvm_max_policy(void)
(1u << SVM_FEATURE_PAUSEFILTER) |
(1u << SVM_FEATURE_DECODEASSISTS));
/* Enable features which are always emulated. */
- p->extd.raw[0xa].d |= ((1u << SVM_FEATURE_VMCBCLEAN) |
- (1u << SVM_FEATURE_TSCRATEMSR));
+ p->extd.raw[0xa].d |= (1u << SVM_FEATURE_VMCBCLEAN);
}
guest_common_max_feature_adjustments(fs);
@@ -146,8 +146,6 @@ int cf_check nsvm_vcpu_reset(struct vcpu *v)
svm->ns_msr_hsavepa = INVALID_PADDR;
svm->ns_ovvmcb_pa = INVALID_PADDR;
- svm->ns_tscratio = DEFAULT_TSC_RATIO;
-
svm->ns_cr_intercepts = 0;
svm->ns_dr_intercepts = 0;
svm->ns_exception_intercepts = 0;
@@ -777,43 +777,6 @@ static int cf_check svm_get_guest_pat(struct vcpu *v, u64 *gpat)
return 1;
}
-static uint64_t scale_tsc(uint64_t host_tsc, uint64_t ratio)
-{
- uint64_t mult, frac, scaled_host_tsc;
-
- if ( ratio == DEFAULT_TSC_RATIO )
- return host_tsc;
-
- /*
- * Suppose the most significant 32 bits of host_tsc and ratio are
- * tsc_h and mult, and the least 32 bits of them are tsc_l and frac,
- * then
- * host_tsc * ratio * 2^-32
- * = host_tsc * (mult * 2^32 + frac) * 2^-32
- * = host_tsc * mult + (tsc_h * 2^32 + tsc_l) * frac * 2^-32
- * = host_tsc * mult + tsc_h * frac + ((tsc_l * frac) >> 32)
- *
- * Multiplications in the last two terms are between 32-bit integers,
- * so both of them can fit in 64-bit integers.
- *
- * Because mult is usually less than 10 in practice, it's very rare
- * that host_tsc * mult can overflow a 64-bit integer.
- */
- mult = ratio >> 32;
- frac = ratio & ((1ULL << 32) - 1);
- scaled_host_tsc = host_tsc * mult;
- scaled_host_tsc += (host_tsc >> 32) * frac;
- scaled_host_tsc += ((host_tsc & ((1ULL << 32) - 1)) * frac) >> 32;
-
- return scaled_host_tsc;
-}
-
-static uint64_t svm_get_tsc_offset(uint64_t host_tsc, uint64_t guest_tsc,
- uint64_t ratio)
-{
- return guest_tsc - scale_tsc(host_tsc, ratio);
-}
-
static void cf_check svm_set_tsc_offset(struct vcpu *v, u64 offset, u64 at_tsc)
{
struct vmcb_struct *vmcb = v->arch.hvm.svm.vmcb;
@@ -832,18 +795,8 @@ static void cf_check svm_set_tsc_offset(struct vcpu *v, u64 offset, u64 at_tsc)
if ( nestedhvm_vcpu_in_guestmode(v) )
{
- struct nestedsvm *svm = &vcpu_nestedsvm(v);
-
n2_tsc_offset = vmcb_get_tsc_offset(n2vmcb) -
vmcb_get_tsc_offset(n1vmcb);
- if ( svm->ns_tscratio != DEFAULT_TSC_RATIO )
- {
- uint64_t guest_tsc = hvm_get_guest_tsc_fixed(v, at_tsc);
-
- n2_tsc_offset = svm_get_tsc_offset(guest_tsc,
- guest_tsc + n2_tsc_offset,
- svm->ns_tscratio);
- }
vmcb_set_tsc_offset(n1vmcb, offset);
}
@@ -1921,10 +1874,6 @@ static int cf_check svm_msr_read_intercept(
*msr_content = nsvm->ns_msr_hsavepa;
break;
- case MSR_AMD64_TSC_RATIO:
- *msr_content = nsvm->ns_tscratio;
- break;
-
case MSR_AMD_OSVW_ID_LENGTH:
case MSR_AMD_OSVW_STATUS:
if ( !d->arch.cpuid->extd.osvw )
@@ -2103,12 +2052,6 @@ static int cf_check svm_msr_write_intercept(
goto gpf;
break;
- case MSR_AMD64_TSC_RATIO:
- if ( msr_content & TSC_RATIO_RSVD_BITS )
- goto gpf;
- nsvm->ns_tscratio = msr_content;
- break;
-
case MSR_IA32_MCx_MISC(4): /* Threshold register */
case MSR_F10_MC4_MISC1 ... MSR_F10_MC4_MISC3:
/*
@@ -18,11 +18,6 @@ struct nestedsvm {
*/
uint64_t ns_ovvmcb_pa;
- /* virtual tscratio holding the value l1 guest writes to the
- * MSR_AMD64_TSC_RATIO MSR.
- */
- uint64_t ns_tscratio;
-
/* Cached real intercepts of the l2 guest */
uint32_t ns_cr_intercepts;
uint32_t ns_dr_intercepts;
The primary purpose of TSC scaling, from our perspective, is to maintain the fiction of an "invariant TSC" across migrates between platforms with different clock speeds. On AMD, the TscRateMSR CPUID bit is unconditionally enabled in the "host cpuid", even if the hardware doesn't actually support it. According to c/s fd14a1943c4 ("nestedsvm: Support TSC Rate MSR"), testing showed that emulating TSC scaling in an L1 was more expensive than emulating TSC scaling on an L0 (due to extra sets of vmexit / vmenter). However, the current implementation seems to be broken. First of all, the final L2 scaling ratio should be a composition of the L0 scaling ratio and the L1 scaling ratio; there's no indication this is being done anywhere. Secondly, it's not clear that the L1 tsc scaling ratio actually affects the L0 tsc scaling ratio. The stored value (ns_tscratio) is used to affect the tsc *offset*, but doesn't seem to actually be factored into d->hvm.tsc_scaling_ratio. (Which shouldn't be per-domain anyway, but per-vcpu.) Having the *offset* scaled according to the nested scaling without the actual RDTSC itself also being scaled has got to produce inconsistent results. For now, just disable the functionality entirely until we can implement it properly: - Don't set TSCRATEMSR in the host CPUID policy - Remove MSR_AMD64_TSC_RATIO emulation handling, so that the guest guests a #GP if it tries to access them (as it should when TSCRATEMSR is clear) - Remove ns_tscratio from struct nestedhvm, and all code that touches it Unfortunately this means ripping out the scaling calculation stuff as well, since it's only used in the nested case; it's there in the git tree if we need it for reference when we re-introduce it. Signed-off-by: George Dunlap <george.dunlap@cloud.com> --- v2: - Port over move to hvm_max_cpu_policy CC: Jan Beulich <jbeulich@suse.com> CC: Andrew Cooper <andrew.cooper3@citrix.com> CC: "Roger Pau Monné" <roger.pau@citrix.com> CC: Wei Liu <wl@xen.org> --- xen/arch/x86/cpu-policy.c | 3 +- xen/arch/x86/hvm/svm/nestedsvm.c | 2 - xen/arch/x86/hvm/svm/svm.c | 57 -------------------- xen/arch/x86/include/asm/hvm/svm/nestedsvm.h | 5 -- 4 files changed, 1 insertion(+), 66 deletions(-)