diff --git a/kernel/Kbuild b/kernel/Kbuild
index ceb6e4b..a502c02 100644
--- a/kernel/Kbuild
+++ b/kernel/Kbuild
@@ -1,5 +1,5 @@
 EXTRA_CFLAGS := -I$(src)/include -include $(src)/external-module-compat.h
 obj-m := kvm.o kvm-intel.o kvm-amd.o
-kvm-objs := kvm_main.o mmu.o x86_emulate.o anon_inodes.o irq.o i8259.o lapic.o
+kvm-objs := kvm_main.o mmu.o x86_emulate.o anon_inodes.o irq.o i8259.o lapic.o ioapic.o
 kvm-intel-objs := vmx.o vmx-debug.o
 kvm-amd-objs := svm.o
diff --git a/qemu/hw/i8259.c b/qemu/hw/i8259.c
index 117340c..2dcaf7a 100644
--- a/qemu/hw/i8259.c
+++ b/qemu/hw/i8259.c
@@ -581,3 +581,26 @@ void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
     s->alt_irq_func = alt_irq_func;
     s->alt_irq_opaque = alt_irq_opaque;
 }
+
+void pic_k2u(void *s, int id, void *buf, int len)
+{
+    PicState *pic = &((PicState2*)s)->pics[id];
+    if (len != sizeof(PicState)) {
+	printf("Kernel/User PIC device model state different\n");
+	return;
+    }
+    len -= sizeof(PicState2 *);
+    memcpy(pic, buf, len);
+}
+
+void pic_u2k(void *s, int id, void *buf, int len)
+{
+    PicState *pic = &((PicState2*)s)->pics[id];
+    if (len != sizeof(PicState)) {
+	printf("Kernel/User PIC device model state different\n");
+	return;
+    }
+    len -= sizeof(PicState2 *);
+    memcpy(buf, pic, len);
+}
+
diff --git a/qemu/migration.c b/qemu/migration.c
index 6053c98..f60fe6d 100644
--- a/qemu/migration.c
+++ b/qemu/migration.c
@@ -29,6 +29,8 @@
 #endif
 
 #include <sys/wait.h>
+extern void kvm_irqchip_k2u(void);
+extern void kvm_irqchip_u2k(void);
 
 #define MIN_FINALIZE_SIZE	(200 << 10)
 #define MAX_ITERATIONS           30
@@ -180,6 +182,7 @@ static void migrate_finish(MigrationState *s)
         bdrv_flush_all();
         vm_stop(0);
         qemu_put_be32(f, 1);
+	kvm_irqchip_k2u();
         ret = qemu_live_savevm_state(f);
 #ifdef MIGRATION_VERIFY
         save_verify_memory(f, NULL);
@@ -840,6 +843,7 @@ static int migrate_incoming_fd(int fd)
     vm_stop(0);
     if (qemu_live_loadvm_state(f))
         ret = MIG_STAT_DST_LOADVM_FAILED;
+    kvm_irqchip_u2k();
 #ifdef MIGRATION_VERIFY
     if (ret==0) ret=load_verify_memory(f, NULL, 1);
 #endif /* MIGRATION_VERIFY */
diff --git a/qemu/qemu-kvm.c b/qemu/qemu-kvm.c
index 1c7c14e..1c864b7 100644
--- a/qemu/qemu-kvm.c
+++ b/qemu/qemu-kvm.c
@@ -140,6 +140,35 @@ static void fix_realmode_dataseg(struct kvm_segment *seg)
 	seg->s = 1;
 }
 
+extern void *isa_pic;
+extern void pic_k2u(void *s, int id, void *buf, int len);
+extern void pic_u2k(void *s, int id, void *buf, int len);
+void kvm_irqchip_u2k()
+{
+    struct kvm_irqchip chip;
+
+    pic_u2k (isa_pic, 1, &chip.chip, sizeof(chip.chip));
+    chip.chip_id = KVM_IRQCHIP_PIC_MASTER;
+    kvm_set_irqchip(kvm_context, &chip);
+
+    pic_u2k (isa_pic, 0, &chip.chip, sizeof(chip.chip));
+    chip.chip_id = KVM_IRQCHIP_PIC_SLAVE;
+    kvm_set_irqchip(kvm_context, &chip);
+}
+
+void kvm_irqchip_k2u()
+{
+    struct kvm_irqchip chip;
+
+    chip.chip_id = KVM_IRQCHIP_PIC_MASTER;
+    kvm_get_irqchip(kvm_context, &chip);
+    pic_k2u (isa_pic, 1, &chip.chip, sizeof(chip.chip));
+
+    chip.chip_id = KVM_IRQCHIP_PIC_SLAVE;
+    kvm_get_irqchip(kvm_context, &chip);
+    pic_k2u (isa_pic, 0, &chip.chip, sizeof(chip.chip));
+}
+
 static void load_regs(CPUState *env)
 {
     struct kvm_regs regs;
diff --git a/user/kvmctl.c b/user/kvmctl.c
index d610111..00a6131 100644
--- a/user/kvmctl.c
+++ b/user/kvmctl.c
@@ -428,10 +428,34 @@ int kvm_set_irq_level(kvm_context_t kvm, int irq, int level)
 	event.irq = irq;
 	r = ioctl(kvm->vm_fd, KVM_IRQ_LINE, &event);
 	if (r == -1)
-		perror("kvm_set_irq_level");
+		perror("kvm_set_irq_level\n");
 	return 1;
 }
 
+int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
+{
+    int r;
+
+    if (!kvm->irqchip_in_kernel)
+	return 0;
+    r = ioctl(kvm->vm_fd, KVM_GET_IRQCHIP, chip);
+    if (r == -1)
+	perror("kvm_get_irqchip\n");
+    return 1;
+}
+
+int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip)
+{
+    int r;
+
+    if (!kvm->irqchip_in_kernel)
+	return 0;
+    r = ioctl(kvm->vm_fd, KVM_SET_IRQCHIP, chip);
+    if (r == -1)
+	perror("kvm_set_irqchip\n");
+    return 1;
+}
+
 static int handle_io_abi10(kvm_context_t kvm, struct kvm_run_abi10 *run,
 			   int vcpu)
 {
diff --git a/user/kvmctl.h b/user/kvmctl.h
index 68e1664..1bcfd15 100644
--- a/user/kvmctl.h
+++ b/user/kvmctl.h
@@ -413,5 +413,8 @@ int kvm_dirty_pages_log_enable_all(kvm_context_t kvm);
  * \param kvm Pointer to the current kvm_context
  */
 int kvm_dirty_pages_log_reset(kvm_context_t kvm);
+int kvm_get_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
+int kvm_set_irqchip(kvm_context_t kvm, struct kvm_irqchip *chip);
+int kvm_set_irq_level(kvm_context_t kvm, int irq, int level);
 
 #endif
