Skip to content

Commit ee6fa05

Browse files
Maxim Levitskybonzini
authored andcommitted
KVM: x86: fix MSR_IA32_TSC read for nested migration
MSR reads/writes should always access the L1 state, since the (nested) hypervisor should intercept all the msrs it wants to adjust, and these that it doesn't should be read by the guest as if the host had read it. However IA32_TSC is an exception. Even when not intercepted, guest still reads the value + TSC offset. The write however does not take any TSC offset into account. This is documented in Intel's SDM and seems also to happen on AMD as well. This creates a problem when userspace wants to read the IA32_TSC value and then write it. (e.g for migration) In this case it reads L2 value but write is interpreted as an L1 value. To fix this make the userspace initiated reads of IA32_TSC return L1 value as well. Huge thanks to Dave Gilbert for helping me understand this very confusing semantic of MSR writes. Signed-off-by: Maxim Levitsky <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 18391e5 commit ee6fa05

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

arch/x86/kvm/x86.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3224,9 +3224,22 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
32243224
case MSR_IA32_POWER_CTL:
32253225
msr_info->data = vcpu->arch.msr_ia32_power_ctl;
32263226
break;
3227-
case MSR_IA32_TSC:
3228-
msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + vcpu->arch.tsc_offset;
3227+
case MSR_IA32_TSC: {
3228+
/*
3229+
* Intel SDM states that MSR_IA32_TSC read adds the TSC offset
3230+
* even when not intercepted. AMD manual doesn't explicitly
3231+
* state this but appears to behave the same.
3232+
*
3233+
* On userspace reads and writes, however, we unconditionally
3234+
* operate L1's TSC value to ensure backwards-compatible
3235+
* behavior for migration.
3236+
*/
3237+
u64 tsc_offset = msr_info->host_initiated ? vcpu->arch.l1_tsc_offset :
3238+
vcpu->arch.tsc_offset;
3239+
3240+
msr_info->data = kvm_scale_tsc(vcpu, rdtsc()) + tsc_offset;
32293241
break;
3242+
}
32303243
case MSR_MTRRcap:
32313244
case 0x200 ... 0x2ff:
32323245
return kvm_mtrr_get_msr(vcpu, msr_info->index, &msr_info->data);

0 commit comments

Comments
 (0)