summaryrefslogtreecommitdiff
path: root/hw/timer/hpet.c
diff options
context:
space:
mode:
authorMatt Lupfer <mlupfer@ddn.com>2014-02-21 21:37:23 -0700
committerMichael S. Tsirkin <mst@redhat.com>2014-03-27 17:48:11 +0200
commitc36ad13fe9ece9a21a8c1dd082473a2b182298ee (patch)
treed8cdb0993f0fb271eb5b1a473b911f107768d7bd /hw/timer/hpet.c
parent5c312079417908381ffca44d18150b6a990c4f0b (diff)
downloadqemu-c36ad13fe9ece9a21a8c1dd082473a2b182298ee.zip
Don't enable a HPET timer if HPET is disabled
A HPET timer can be started when HPET is not yet enabled. This will not generate an interrupt to the guest, but causes problems when HPET is later enabled. A timer that is created and expires at least once before HPET is enabled will have an initialized comparator based on a hpet_offset of 0 (uninitialized). When HPET is enabled, hpet_set_timer() is called a second time, which modifies the timer expiry to a time based on the difference between current ticks (measured with the newly initialized hpet_offset) and the timer's comparator (which was generated before hpet_offset was initialized). This results in a long period of no HPET timer ticks. When this occurs with a CentOS 5.x guest, the guest may not receive timer interrupts during its narrow timer check window and panic on boot. Signed-off-by: Matt Lupfer <mlupfer@ddn.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/timer/hpet.c')
-rw-r--r--hw/timer/hpet.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 1264dfd46a..e15d6bcac7 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -506,7 +506,8 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
timer->cmp = (uint32_t)timer->cmp;
timer->period = (uint32_t)timer->period;
}
- if (activating_bit(old_val, new_val, HPET_TN_ENABLE)) {
+ if (activating_bit(old_val, new_val, HPET_TN_ENABLE) &&
+ hpet_enabled(s)) {
hpet_set_timer(timer);
} else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
hpet_del_timer(timer);