diff options
author | Josh Boyer <jwboyer@redhat.com> | 2013-03-14 07:45:49 -0400 |
---|---|---|
committer | Josh Boyer <jwboyer@redhat.com> | 2013-03-15 08:32:35 -0400 |
commit | 8a56c6cd5979e5cddaa9886419dde1f58a4cecde (patch) | |
tree | cc8c8d4664d7825828005c9da9ce930ec01ca7a3 /VMX-x86-handle-host-TSC-calibration-failure.patch | |
parent | 73964d96a7a08f2de053d783efe97d3dd1a690a5 (diff) | |
download | kernel-8a56c6cd5979e5cddaa9886419dde1f58a4cecde.tar.gz kernel-8a56c6cd5979e5cddaa9886419dde1f58a4cecde.tar.xz kernel-8a56c6cd5979e5cddaa9886419dde1f58a4cecde.zip |
Fix divide by zero on host TSC calibration failure (rhbz 859282)
Diffstat (limited to 'VMX-x86-handle-host-TSC-calibration-failure.patch')
-rw-r--r-- | VMX-x86-handle-host-TSC-calibration-failure.patch | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/VMX-x86-handle-host-TSC-calibration-failure.patch b/VMX-x86-handle-host-TSC-calibration-failure.patch new file mode 100644 index 000000000..6b6ddd2d2 --- /dev/null +++ b/VMX-x86-handle-host-TSC-calibration-failure.patch @@ -0,0 +1,58 @@ +@@ -, +, @@ + VMX: x86: handle host TSC calibration failure + + If the host TSC calibration fails, tsc_khz is zero (see tsc_init.c). + Handle such case properly in KVM (instead of dividing by zero). + + https://bugzilla.redhat.com/show_bug.cgi?id=859282 + + Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> + Signed-off-by: Gleb Natapov <gleb@redhat.com> +--- a/arch/x86/kvm/x86.c ++++ a/arch/x86/kvm/x86.c +@@ -1079,6 +1079,10 @@ static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz) + u32 thresh_lo, thresh_hi; + int use_scaling = 0; + ++ /* tsc_khz can be zero if TSC calibration fails */ ++ if (this_tsc_khz == 0) ++ return; ++ + /* Compute a scale to convert nanoseconds in TSC cycles */ + kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000, + &vcpu->arch.virtual_tsc_shift, +@@ -1156,20 +1160,23 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr) + ns = get_kernel_ns(); + elapsed = ns - kvm->arch.last_tsc_nsec; + +- /* n.b - signed multiplication and division required */ +- usdiff = data - kvm->arch.last_tsc_write; ++ if (vcpu->arch.virtual_tsc_khz) { ++ /* n.b - signed multiplication and division required */ ++ usdiff = data - kvm->arch.last_tsc_write; + #ifdef CONFIG_X86_64 +- usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; ++ usdiff = (usdiff * 1000) / vcpu->arch.virtual_tsc_khz; + #else +- /* do_div() only does unsigned */ +- asm("idivl %2; xor %%edx, %%edx" +- : "=A"(usdiff) +- : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); ++ /* do_div() only does unsigned */ ++ asm("idivl %2; xor %%edx, %%edx" ++ : "=A"(usdiff) ++ : "A"(usdiff * 1000), "rm"(vcpu->arch.virtual_tsc_khz)); + #endif +- do_div(elapsed, 1000); +- usdiff -= elapsed; +- if (usdiff < 0) +- usdiff = -usdiff; ++ do_div(elapsed, 1000); ++ usdiff -= elapsed; ++ if (usdiff < 0) ++ usdiff = -usdiff; ++ } else ++ usdiff = USEC_PER_SEC; /* disable TSC match window below */ + + /* + * Special case: TSC write with a small delta (1 second) of virtual |