kvm: fix i8254 counter 0 wraparound
authorNickolai Zeldovich <nickolai@csail.mit.edu>
Sat, 15 Dec 2012 11:34:37 +0000 (06:34 -0500)
committerGleb Natapov <gleb@redhat.com>
Tue, 18 Dec 2012 09:12:38 +0000 (11:12 +0200)
The kvm i8254 emulation for counter 0 (but not for counters 1 and 2)
has at least two bugs in mode 0:

1. The OUT bit, computed by pit_get_out(), is never set high.

2. The counter value, computed by pit_get_count(), wraps back around to
   the initial counter value, rather than wrapping back to 0xFFFF
   (which is the behavior described in the comment in __kpit_elapsed,
   the behavior implemented by qemu, and the behavior observed on AMD
   hardware).

The bug stems from __kpit_elapsed computing the elapsed time mod the
initial counter value (stored as nanoseconds in ps->period).  This is both
unnecessary (none of the callers of kpit_elapsed expect the value to be
at most the initial counter value) and incorrect (it causes pit_get_count
to appear to wrap around to the initial counter value rather than 0xFFFF).
Removing this mod from __kpit_elapsed fixes both of the above bugs.

Signed-off-by: Nickolai Zeldovich <nickolai@csail.mit.edu>
Reviewed-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Gleb Natapov <gleb@redhat.com>
arch/x86/kvm/i8254.c

index 11300d2fa71445ff332cbdff30e7c640b959f02d..c1d30b2fc9bb166e42f02557fa5b4c79f79786e9 100644 (file)
@@ -122,7 +122,6 @@ static s64 __kpit_elapsed(struct kvm *kvm)
         */
        remaining = hrtimer_get_remaining(&ps->timer);
        elapsed = ps->period - ktime_to_ns(remaining);
-       elapsed = mod_64(elapsed, ps->period);
 
        return elapsed;
 }