diff --git a/hw/hpet.c b/hw/hpet.c
index 29db325..043b92b 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -206,6 +206,9 @@ static int hpet_load(QEMUFile *f, void *opaque, int version_id)
             qemu_get_timer(f, s->timer[i].qemu_timer);
         }
     }
+    if (hpet_in_legacy_mode()) {
+        hpet_disable_pit();
+    }
     return 0;
 }
 
@@ -475,9 +478,11 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
                 }
                 /* i8254 and RTC are disabled when HPET is in legacy mode */
                 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                    hpet_pit_disable();
+                    hpet_disable_pit();
+                    dprintf("qemu: hpet disabled pit\n");
                 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                    hpet_pit_enable();
+                    hpet_enable_pit();
+                    dprintf("qemu: hpet enabled pit\n");
                 }
                 break;
             case HPET_CFG + 4:
@@ -554,13 +559,15 @@ static void hpet_reset(void *opaque) {
     /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
     s->capability = 0x8086a201ULL;
     s->capability |= ((HPET_CLK_PERIOD) << 32);
-    if (count > 0)
+    if (count > 0) {
         /* we don't enable pit when hpet_reset is first called (by hpet_init)
          * because hpet is taking over for pit here. On subsequent invocations,
          * hpet_reset is called due to system reset. At this point control must
          * be returned to pit until SW reenables hpet.
          */
-        hpet_pit_enable();
+        hpet_enable_pit();
+        dprintf("qemu: hpet enabled pit\n");
+    }
     count = 1;
 }
 
diff --git a/hw/i8254.c b/hw/i8254.c
index 2f229f9..8c8076f 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -25,6 +25,7 @@
 #include "pc.h"
 #include "isa.h"
 #include "qemu-timer.h"
+#include "qemu-kvm.h"
 #include "i8254.h"
 
 //#define DEBUG_PIT
@@ -198,6 +199,9 @@ int pit_get_mode(PITState *pit, int channel)
 
 static inline void pit_load_count(PITChannelState *s, int val)
 {
+    if (s->channel == 0 && pit_state.hpet_legacy_mode) {
+        return;
+    }
     if (val == 0)
         val = 0x10000;
     s->count_load_time = qemu_get_clock(vm_clock);
@@ -371,10 +375,11 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
            (double)(expire_time - current_time) / ticks_per_sec);
 #endif
     s->next_transition_time = expire_time;
-    if (expire_time != -1)
+    if (expire_time != -1) {
         qemu_mod_timer(s->irq_timer, expire_time);
-    else
+    } else {
         qemu_del_timer(s->irq_timer);
+    }
 }
 
 static void pit_irq_timer(void *opaque)
@@ -451,6 +456,7 @@ void pit_reset(void *opaque)
     PITChannelState *s;
     int i;
 
+    pit->hpet_legacy_mode = 0;
     for(i = 0;i < 3; i++) {
         s = &pit->channels[i];
         s->mode = 3;
@@ -460,32 +466,43 @@ void pit_reset(void *opaque)
 }
 
 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
-void hpet_pit_disable(void) {
-    PITChannelState *s;
-    s = &pit_state.channels[0];
-    if (s->irq_timer)
-        qemu_del_timer(s->irq_timer);
+
+void hpet_disable_pit(void)
+{
+    PITChannelState *s = &pit_state.channels[0];
+    if (qemu_kvm_pit_in_kernel()) {
+        kvm_hpet_disable_kpit();
+    } else {
+        if (s->irq_timer) {
+            qemu_del_timer(s->irq_timer);
+        }
+    }
 }
 
 /* When HPET is reset or leaving legacy mode, it must reenable i8254
  * timer 0
  */
 
-void hpet_pit_enable(void)
+void hpet_enable_pit(void)
 {
     PITState *pit = &pit_state;
-    PITChannelState *s;
-    s = &pit->channels[0];
-    s->mode = 3;
-    s->gate = 1;
-    pit_load_count(s, 0);
+    PITChannelState *s = &pit->channels[0];
+    if (qemu_kvm_pit_in_kernel()) {
+        kvm_hpet_enable_kpit();
+    } else {
+        pit_load_count(s, s->count);
+    }
 }
 
 PITState *pit_init(int base, qemu_irq irq)
 {
     PITState *pit = &pit_state;
     PITChannelState *s;
+    int i;
 
+    for (i = 0; i <3 ; i++) {
+        pit->channels[i].channel = i;
+    }
     s = &pit->channels[0];
     /* the timer 0 is connected to an IRQ */
     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
diff --git a/hw/i8254.h b/hw/i8254.h
index ee68ab5..9efd4ab 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -35,6 +35,7 @@
 
 typedef struct PITChannelState {
     int count; /* can be 65536 */
+    uint8_t channel;
     uint16_t latched_count;
     uint8_t count_latched;
     uint8_t status_latched;
@@ -55,6 +56,7 @@ typedef struct PITChannelState {
 
 struct PITState {
     PITChannelState channels[3];
+    uint8_t hpet_legacy_mode;
 };
 
 void pit_save(QEMUFile *f, void *opaque);
diff --git a/hw/pc.h b/hw/pc.h
index 3af22f2..abac8d8 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -74,8 +74,8 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time);
 
 PITState *kvm_pit_init(int base, qemu_irq irq);
 
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
+void hpet_disable_pit(void);
+void hpet_enable_pit(void);
 
 /* vmport.c */
 void vmport_init(void);
diff --git a/kvm/include/x86/asm/kvm.h b/kvm/include/x86/asm/kvm.h
index dc90c47..df8d846 100644
--- a/kvm/include/x86/asm/kvm.h
+++ b/kvm/include/x86/asm/kvm.h
@@ -274,6 +274,7 @@ struct kvm_guest_debug_arch {
 
 struct kvm_pit_state {
 	struct kvm_pit_channel_state channels[3];
+    __u8 hpet_legacy_mode;
 };
 
 struct kvm_reinject_control {
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 7acc0ef..98bd117 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -467,6 +467,26 @@ int kvm_vcpu_inited(CPUState *env)
     return env->kvm_cpu_state.created;
 }
 
+void kvm_hpet_disable_kpit(void)
+{
+    struct kvm_pit_state ps;
+    if (qemu_kvm_pit_in_kernel()) {
+        kvm_get_pit(kvm_context, &ps);
+        ps.hpet_legacy_mode = 1;
+        kvm_set_pit(kvm_context, &ps);
+    }
+}
+
+void kvm_hpet_enable_kpit(void)
+{
+    struct kvm_pit_state ps;
+    if (qemu_kvm_pit_in_kernel()) {
+        kvm_get_pit(kvm_context, &ps);
+        ps.hpet_legacy_mode = 0;
+        kvm_set_pit(kvm_context, &ps);
+    }
+}
+
 int kvm_init_ap(void)
 {
 #ifdef TARGET_I386
diff --git a/qemu-kvm.h b/qemu-kvm.h
index 6bbafbc..c094107 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -34,7 +34,8 @@ int kvm_qemu_check_extension(int ext);
 void kvm_apic_init(CPUState *env);
 /* called from vcpu initialization */
 void qemu_kvm_load_lapic(CPUState *env);
-
+void kvm_hpet_enable_kpit(void);
+void kvm_hpet_disable_kpit(void);
 int kvm_set_irq(int irq, int level, int *status);
 
 int kvm_physical_memory_set_dirty_tracking(int enable);
diff --git a/vl.c b/vl.c
index 9b1d1ab..485b091 100644
--- a/vl.c
+++ b/vl.c
@@ -6056,10 +6056,15 @@ int main(int argc, char **argv, char **envp)
     module_call_init(MODULE_INIT_DEVICE);
 
     if (kvm_enabled()) {
-       kvm_init_ap();
+        kvm_init_ap();
 #ifdef USE_KVM
         if (kvm_irqchip && !qemu_kvm_has_gsi_routing()) {
             irq0override = 0;
+            /* if kernel can't do irq routing, interrupt source
+             * override 0->2 can not be set up as required by hpet,
+             * so disable hpet.
+             */
+            no_hpet=1;
         }
 #endif
     }
