diff options
author | Avi Kivity <avi@qumranet.com> | 2007-03-25 06:07:27 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:27 -0400 |
commit | 0cc5064d335543a72c5ef904a3f528966fa3f2d2 (patch) | |
tree | 4e6f8b4e013fc24821cb0f1af26d33d906e4d870 /drivers/kvm/svm.c | |
parent | d28c6cfbbc5e2d4fccfe6d733995ed5971ca87f6 (diff) |
KVM: SVM: Ensure timestamp counter monotonicity
When a vcpu is migrated from one cpu to another, its timestamp counter
may lose its monotonic property if the host has unsynced timestamp counters.
This can confuse the guest, sometimes to the point of refusing to boot.
As the rdtsc instruction is rather fast on AMD processors (7-10 cycles),
we can simply record the last host tsc when we drop the cpu, and adjust
the vcpu tsc offset when we detect that we've migrated to a different cpu.
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/svm.c')
-rw-r--r-- | drivers/kvm/svm.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 0542d3357ce1..ca2642fc091f 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -459,7 +459,6 @@ static void init_vmcb(struct vmcb *vmcb) | |||
459 | { | 459 | { |
460 | struct vmcb_control_area *control = &vmcb->control; | 460 | struct vmcb_control_area *control = &vmcb->control; |
461 | struct vmcb_save_area *save = &vmcb->save; | 461 | struct vmcb_save_area *save = &vmcb->save; |
462 | u64 tsc; | ||
463 | 462 | ||
464 | control->intercept_cr_read = INTERCEPT_CR0_MASK | | 463 | control->intercept_cr_read = INTERCEPT_CR0_MASK | |
465 | INTERCEPT_CR3_MASK | | 464 | INTERCEPT_CR3_MASK | |
@@ -517,8 +516,7 @@ static void init_vmcb(struct vmcb *vmcb) | |||
517 | 516 | ||
518 | control->iopm_base_pa = iopm_base; | 517 | control->iopm_base_pa = iopm_base; |
519 | control->msrpm_base_pa = msrpm_base; | 518 | control->msrpm_base_pa = msrpm_base; |
520 | rdtscll(tsc); | 519 | control->tsc_offset = 0; |
521 | control->tsc_offset = -tsc; | ||
522 | control->int_ctl = V_INTR_MASKING_MASK; | 520 | control->int_ctl = V_INTR_MASKING_MASK; |
523 | 521 | ||
524 | init_seg(&save->es); | 522 | init_seg(&save->es); |
@@ -606,11 +604,26 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu) | |||
606 | 604 | ||
607 | static void svm_vcpu_load(struct kvm_vcpu *vcpu) | 605 | static void svm_vcpu_load(struct kvm_vcpu *vcpu) |
608 | { | 606 | { |
609 | get_cpu(); | 607 | int cpu; |
608 | |||
609 | cpu = get_cpu(); | ||
610 | if (unlikely(cpu != vcpu->cpu)) { | ||
611 | u64 tsc_this, delta; | ||
612 | |||
613 | /* | ||
614 | * Make sure that the guest sees a monotonically | ||
615 | * increasing TSC. | ||
616 | */ | ||
617 | rdtscll(tsc_this); | ||
618 | delta = vcpu->host_tsc - tsc_this; | ||
619 | vcpu->svm->vmcb->control.tsc_offset += delta; | ||
620 | vcpu->cpu = cpu; | ||
621 | } | ||
610 | } | 622 | } |
611 | 623 | ||
612 | static void svm_vcpu_put(struct kvm_vcpu *vcpu) | 624 | static void svm_vcpu_put(struct kvm_vcpu *vcpu) |
613 | { | 625 | { |
626 | rdtscll(vcpu->host_tsc); | ||
614 | put_cpu(); | 627 | put_cpu(); |
615 | } | 628 | } |
616 | 629 | ||