KVM: SVM: Clear MSR_TSC_AUX[63:32] on write
authorSean Christopherson <seanjc@google.com>
Fri, 23 Apr 2021 22:34:02 +0000 (15:34 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 26 Apr 2021 09:24:43 +0000 (05:24 -0400)
Force clear bits 63:32 of MSR_TSC_AUX on write to emulate current AMD
CPUs, which completely ignore the upper 32 bits, including dropping them
on write.  Emulating AMD hardware will also allow migrating a vCPU from
AMD hardware to Intel hardware without requiring userspace to manually
clear the upper bits, which are reserved on Intel hardware.

Presumably, MSR_TSC_AUX[63:32] are intended to be reserved on AMD, but
sadly the APM doesn't say _anything_ about those bits in the context of
MSR access.  The RDTSCP entry simply states that RCX contains bits 31:0
of the MSR, zero extended.  And even worse is that the RDPID description
implies that it can consume all 64 bits of the MSR:

  RDPID reads the value of TSC_AUX MSR used by the RDTSCP instruction
  into the specified destination register. Normal operand size prefixes
  do not apply and the update is either 32 bit or 64 bit based on the
  current mode.

Emulate current hardware behavior to give KVM the best odds of playing
nice with whatever the behavior of future AMD CPUs happens to be.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20210423223404.3860547-3-seanjc@google.com>
[Fix broken patch. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/svm/svm.c

index 9ed9c7b..9238831 100644 (file)
@@ -2900,12 +2900,22 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
                        return 1;
 
                /*
+                * Per Intel's SDM, bits 63:32 are reserved, but AMD's APM has
+                * incomplete and conflicting architectural behavior.  Current
+                * AMD CPUs completely ignore bits 63:32, i.e. they aren't
+                * reserved and always read as zeros.  Emulate AMD CPU behavior
+                * to avoid explosions if the vCPU is migrated from an AMD host
+                * to an Intel host.
+                */
+               data = (u32)data;
+
+               /*
                 * This is rare, so we update the MSR here instead of using
                 * direct_access_msrs.  Doing that would require a rdmsr in
                 * svm_vcpu_put.
                 */
+               wrmsrl(MSR_TSC_AUX, data);
                svm->tsc_aux = data;
-               wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
                break;
        case MSR_IA32_DEBUGCTLMSR:
                if (!boot_cpu_has(X86_FEATURE_LBRV)) {