aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2008-12-11 14:45:05 -0500
committerAvi Kivity <avi@redhat.com>2009-03-24 05:02:53 -0400
commit53f658b3c33616a4997ee254311b335e59063289 (patch)
treefbef1e51bfa096dd28a00b2449d567f2c3ab6fb9 /arch/x86/kvm
parente8c4a4e8a7cc047dfb3c26b2cbc8599ad3460364 (diff)
KVM: VMX: initialize TSC offset relative to vm creation time
VMX initializes the TSC offset for each vcpu at different times, and also reinitializes it for vcpus other than 0 on APIC SIPI message. This bug causes the TSC's to appear unsynchronized in the guest, even if the host is good. Older Linux kernels don't handle the situation very well, so gettimeofday is likely to go backwards in time: http://www.mail-archive.com/kvm@vger.kernel.org/msg02955.html http://sourceforge.net/tracker/index.php?func=detail&aid=2025534&group_id=180599&atid=893831 Fix it by initializating the offset of each vcpu relative to vm creation time, and moving it from vmx_vcpu_reset to vmx_vcpu_setup, out of the APIC MP init path. Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/vmx.c19
-rw-r--r--arch/x86/kvm/x86.c2
2 files changed, 13 insertions, 8 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index cee81c9a6653..3312047664a4 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -865,11 +865,8 @@ static u64 guest_read_tsc(void)
865 * writes 'guest_tsc' into guest's timestamp counter "register" 865 * writes 'guest_tsc' into guest's timestamp counter "register"
866 * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc 866 * guest_tsc = host_tsc + tsc_offset ==> tsc_offset = guest_tsc - host_tsc
867 */ 867 */
868static void guest_write_tsc(u64 guest_tsc) 868static void guest_write_tsc(u64 guest_tsc, u64 host_tsc)
869{ 869{
870 u64 host_tsc;
871
872 rdtscll(host_tsc);
873 vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc); 870 vmcs_write64(TSC_OFFSET, guest_tsc - host_tsc);
874} 871}
875 872
@@ -934,6 +931,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
934{ 931{
935 struct vcpu_vmx *vmx = to_vmx(vcpu); 932 struct vcpu_vmx *vmx = to_vmx(vcpu);
936 struct kvm_msr_entry *msr; 933 struct kvm_msr_entry *msr;
934 u64 host_tsc;
937 int ret = 0; 935 int ret = 0;
938 936
939 switch (msr_index) { 937 switch (msr_index) {
@@ -959,7 +957,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
959 vmcs_writel(GUEST_SYSENTER_ESP, data); 957 vmcs_writel(GUEST_SYSENTER_ESP, data);
960 break; 958 break;
961 case MSR_IA32_TIME_STAMP_COUNTER: 959 case MSR_IA32_TIME_STAMP_COUNTER:
962 guest_write_tsc(data); 960 rdtscll(host_tsc);
961 guest_write_tsc(data, host_tsc);
963 break; 962 break;
964 case MSR_P6_PERFCTR0: 963 case MSR_P6_PERFCTR0:
965 case MSR_P6_PERFCTR1: 964 case MSR_P6_PERFCTR1:
@@ -2109,7 +2108,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
2109{ 2108{
2110 u32 host_sysenter_cs, msr_low, msr_high; 2109 u32 host_sysenter_cs, msr_low, msr_high;
2111 u32 junk; 2110 u32 junk;
2112 u64 host_pat; 2111 u64 host_pat, tsc_this, tsc_base;
2113 unsigned long a; 2112 unsigned long a;
2114 struct descriptor_table dt; 2113 struct descriptor_table dt;
2115 int i; 2114 int i;
@@ -2237,6 +2236,12 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
2237 vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL); 2236 vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
2238 vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK); 2237 vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
2239 2238
2239 tsc_base = vmx->vcpu.kvm->arch.vm_init_tsc;
2240 rdtscll(tsc_this);
2241 if (tsc_this < vmx->vcpu.kvm->arch.vm_init_tsc)
2242 tsc_base = tsc_this;
2243
2244 guest_write_tsc(0, tsc_base);
2240 2245
2241 return 0; 2246 return 0;
2242} 2247}
@@ -2328,8 +2333,6 @@ static int vmx_vcpu_reset(struct kvm_vcpu *vcpu)
2328 vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0); 2333 vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
2329 vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0); 2334 vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
2330 2335
2331 guest_write_tsc(0);
2332
2333 /* Special registers */ 2336 /* Special registers */
2334 vmcs_write64(GUEST_IA32_DEBUGCTL, 0); 2337 vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
2335 2338
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 873602b5edfd..3b2acfd72d7f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4170,6 +4170,8 @@ struct kvm *kvm_arch_create_vm(void)
4170 /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */ 4170 /* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
4171 set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap); 4171 set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap);
4172 4172
4173 rdtscll(kvm->arch.vm_init_tsc);
4174
4173 return kvm; 4175 return kvm;
4174} 4176}
4175 4177