diff --git a/target/i386/hyperv.h b/include/hw/hyperv/hyperv.h
similarity index 59%
copy from target/i386/hyperv.h
copy to include/hw/hyperv/hyperv.h
index 8d4619c078..d6c8d78353 100644
--- a/target/i386/hyperv.h
+++ b/include/hw/hyperv/hyperv.h
@@ -1,27 +1,20 @@
 /*
- * QEMU KVM Hyper-V support
+ * Hyper-V guest/hypervisor interaction
  *
- * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
- *
- * Authors:
- *  Andrey Smetanin <asmetanin@virtuozzo.com>
+ * Copyright (c) 2015-2018 Virtuozzo International GmbH.
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
- *
  */
 
-#ifndef TARGET_I386_HYPERV_H
-#define TARGET_I386_HYPERV_H
+#ifndef HW_HYPERV_HYPERV_H
+#define HW_HYPERV_HYPERV_H
 
-#include "cpu.h"
-#include "sysemu/kvm.h"
+#include "cpu-qom.h"
 
 typedef struct HvSintRoute HvSintRoute;
 typedef void (*HvSintAckClb)(void *data);
 
-int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
-
 HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
                                    HvSintAckClb sint_ack_clb,
                                    void *sint_ack_clb_data);
@@ -30,9 +23,9 @@ void hyperv_sint_route_unref(HvSintRoute *sint_route);
 
 int hyperv_sint_route_set_sint(HvSintRoute *sint_route);
 
-static inline uint32_t hyperv_vp_index(X86CPU *cpu)
+static inline uint32_t hyperv_vp_index(CPUState *cs)
 {
-    return CPU(cpu)->cpu_index;
+    return cs->cpu_index;
 }
 
 #endif
diff --git a/target/i386/hyperv.h b/target/i386/hyperv.h
index 8d4619c078..5c49251ecb 100644
--- a/target/i386/hyperv.h
+++ b/target/i386/hyperv.h
@@ -16,23 +16,8 @@
 
 #include "cpu.h"
 #include "sysemu/kvm.h"
-
-typedef struct HvSintRoute HvSintRoute;
-typedef void (*HvSintAckClb)(void *data);
+#include "hw/hyperv/hyperv.h"
 
 int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
 
-HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
-                                   HvSintAckClb sint_ack_clb,
-                                   void *sint_ack_clb_data);
-void hyperv_sint_route_ref(HvSintRoute *sint_route);
-void hyperv_sint_route_unref(HvSintRoute *sint_route);
-
-int hyperv_sint_route_set_sint(HvSintRoute *sint_route);
-
-static inline uint32_t hyperv_vp_index(X86CPU *cpu)
-{
-    return CPU(cpu)->cpu_index;
-}
-
 #endif
diff --git a/target/i386/hyperv.c b/hw/hyperv/hyperv.c
similarity index 65%
copy from target/i386/hyperv.c
copy to hw/hyperv/hyperv.c
index 68816642c9..97db87561e 100644
--- a/target/i386/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -1,24 +1,20 @@
 /*
- * QEMU KVM Hyper-V support
+ * Hyper-V guest/hypervisor interaction
  *
- * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
- *
- * Authors:
- *  Andrey Smetanin <asmetanin@virtuozzo.com>
+ * Copyright (c) 2015-2018 Virtuozzo International GmbH.
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
- *
  */
 
 #include "qemu/osdep.h"
 #include "qemu/main-loop.h"
-#include "hyperv.h"
-#include "hyperv-proto.h"
+#include "sysemu/kvm.h"
+#include "hw/hyperv/hyperv.h"
 
 struct HvSintRoute {
     uint32_t sint;
-    X86CPU *cpu;
+    CPUState *cs;
     int gsi;
     EventNotifier sint_set_notifier;
     EventNotifier sint_ack_notifier;
@@ -27,57 +23,11 @@ struct HvSintRoute {
     unsigned refcount;
 };
 
-static X86CPU *hyperv_find_vcpu(uint32_t vp_index)
-{
-    X86CPU *cpu = X86_CPU(qemu_get_cpu(vp_index));
-    assert(hyperv_vp_index(cpu) == vp_index);
-    return cpu;
-}
-
-int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
+static CPUState *hyperv_find_vcpu(uint32_t vp_index)
 {
-    CPUX86State *env = &cpu->env;
-
-    switch (exit->type) {
-    case KVM_EXIT_HYPERV_SYNIC:
-        if (!cpu->hyperv_synic) {
-            return -1;
-        }
-
-        /*
-         * For now just track changes in SynIC control and msg/evt pages msr's.
-         * When SynIC messaging/events processing will be added in future
-         * here we will do messages queues flushing and pages remapping.
-         */
-        switch (exit->u.synic.msr) {
-        case HV_X64_MSR_SCONTROL:
-            env->msr_hv_synic_control = exit->u.synic.control;
-            break;
-        case HV_X64_MSR_SIMP:
-            env->msr_hv_synic_msg_page = exit->u.synic.msg_page;
-            break;
-        case HV_X64_MSR_SIEFP:
-            env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
-            break;
-        default:
-            return -1;
-        }
-        return 0;
-    case KVM_EXIT_HYPERV_HCALL: {
-        uint16_t code;
-
-        code  = exit->u.hcall.input & 0xffff;
-        switch (code) {
-        case HV_POST_MESSAGE:
-        case HV_SIGNAL_EVENT:
-        default:
-            exit->u.hcall.result = HV_STATUS_INVALID_HYPERCALL_CODE;
-            return 0;
-        }
-    }
-    default:
-        return -1;
-    }
+    CPUState *cs = qemu_get_cpu(vp_index);
+    assert(hyperv_vp_index(cs) == vp_index);
+    return cs;
 }
 
 static void kvm_hv_sint_ack_handler(EventNotifier *notifier)
@@ -95,10 +45,10 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
     HvSintRoute *sint_route;
     EventNotifier *ack_notifier;
     int r, gsi;
-    X86CPU *cpu;
+    CPUState *cs;
 
-    cpu = hyperv_find_vcpu(vp_index);
-    if (!cpu) {
+    cs = hyperv_find_vcpu(vp_index);
+    if (!cs) {
         return NULL;
     }
 
@@ -132,7 +82,7 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
     sint_route->gsi = gsi;
     sint_route->sint_ack_clb = sint_ack_clb;
     sint_route->sint_ack_clb_data = sint_ack_clb_data;
-    sint_route->cpu = cpu;
+    sint_route->cs = cs;
     sint_route->sint = sint;
     sint_route->refcount = 1;
 
diff --git a/hw/misc/hyperv_testdev.c b/hw/misc/hyperv_testdev.c
index 8654b13d76..02ef606469 100644
--- a/hw/misc/hyperv_testdev.c
+++ b/hw/misc/hyperv_testdev.c
@@ -15,7 +15,7 @@
 #include "qemu/queue.h"
 #include "hw/qdev.h"
 #include "hw/isa/isa.h"
-#include "target/i386/hyperv.h"
+#include "hw/hyperv/hyperv.h"
 
 typedef struct TestSintRoute {
     QLIST_ENTRY(TestSintRoute) le;
diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c
index 68816642c9..1eac727774 100644
--- a/target/i386/hyperv.c
+++ b/target/i386/hyperv.c
@@ -12,28 +12,10 @@
  */
 
 #include "qemu/osdep.h"
-#include "qemu/main-loop.h"
 #include "hyperv.h"
+#include "hw/hyperv/hyperv.h"
 #include "hyperv-proto.h"
 
-struct HvSintRoute {
-    uint32_t sint;
-    X86CPU *cpu;
-    int gsi;
-    EventNotifier sint_set_notifier;
-    EventNotifier sint_ack_notifier;
-    HvSintAckClb sint_ack_clb;
-    void *sint_ack_clb_data;
-    unsigned refcount;
-};
-
-static X86CPU *hyperv_find_vcpu(uint32_t vp_index)
-{
-    X86CPU *cpu = X86_CPU(qemu_get_cpu(vp_index));
-    assert(hyperv_vp_index(cpu) == vp_index);
-    return cpu;
-}
-
 int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
 {
     CPUX86State *env = &cpu->env;
@@ -79,110 +61,3 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
         return -1;
     }
 }
-
-static void kvm_hv_sint_ack_handler(EventNotifier *notifier)
-{
-    HvSintRoute *sint_route = container_of(notifier, HvSintRoute,
-                                           sint_ack_notifier);
-    event_notifier_test_and_clear(notifier);
-    sint_route->sint_ack_clb(sint_route->sint_ack_clb_data);
-}
-
-HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
-                                   HvSintAckClb sint_ack_clb,
-                                   void *sint_ack_clb_data)
-{
-    HvSintRoute *sint_route;
-    EventNotifier *ack_notifier;
-    int r, gsi;
-    X86CPU *cpu;
-
-    cpu = hyperv_find_vcpu(vp_index);
-    if (!cpu) {
-        return NULL;
-    }
-
-    sint_route = g_new0(HvSintRoute, 1);
-    r = event_notifier_init(&sint_route->sint_set_notifier, false);
-    if (r) {
-        goto err;
-    }
-
-    ack_notifier = sint_ack_clb ? &sint_route->sint_ack_notifier : NULL;
-    if (ack_notifier) {
-        r = event_notifier_init(ack_notifier, false);
-        if (r) {
-            goto err_sint_set_notifier;
-        }
-
-        event_notifier_set_handler(ack_notifier, kvm_hv_sint_ack_handler);
-    }
-
-    gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint);
-    if (gsi < 0) {
-        goto err_gsi;
-    }
-
-    r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state,
-                                           &sint_route->sint_set_notifier,
-                                           ack_notifier, gsi);
-    if (r) {
-        goto err_irqfd;
-    }
-    sint_route->gsi = gsi;
-    sint_route->sint_ack_clb = sint_ack_clb;
-    sint_route->sint_ack_clb_data = sint_ack_clb_data;
-    sint_route->cpu = cpu;
-    sint_route->sint = sint;
-    sint_route->refcount = 1;
-
-    return sint_route;
-
-err_irqfd:
-    kvm_irqchip_release_virq(kvm_state, gsi);
-err_gsi:
-    if (ack_notifier) {
-        event_notifier_set_handler(ack_notifier, NULL);
-        event_notifier_cleanup(ack_notifier);
-    }
-err_sint_set_notifier:
-    event_notifier_cleanup(&sint_route->sint_set_notifier);
-err:
-    g_free(sint_route);
-
-    return NULL;
-}
-
-void hyperv_sint_route_ref(HvSintRoute *sint_route)
-{
-    sint_route->refcount++;
-}
-
-void hyperv_sint_route_unref(HvSintRoute *sint_route)
-{
-    if (!sint_route) {
-        return;
-    }
-
-    assert(sint_route->refcount > 0);
-
-    if (--sint_route->refcount) {
-        return;
-    }
-
-    kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state,
-                                          &sint_route->sint_set_notifier,
-                                          sint_route->gsi);
-    kvm_irqchip_release_virq(kvm_state, sint_route->gsi);
-    if (sint_route->sint_ack_clb) {
-        event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
-        event_notifier_cleanup(&sint_route->sint_ack_notifier);
-    }
-    event_notifier_cleanup(&sint_route->sint_set_notifier);
-    g_free(sint_route);
-}
-
-int hyperv_sint_route_set_sint(HvSintRoute *sint_route)
-{
-    return event_notifier_set(&sint_route->sint_set_notifier);
-}
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 0b2a07d3a4..892d4f46c1 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -773,7 +773,7 @@ static int hyperv_init_vcpu(X86CPU *cpu)
         }
         assert(ret == 1);
 
-        if (msr_data.entries[0].data != hyperv_vp_index(cpu)) {
+        if (msr_data.entries[0].data != hyperv_vp_index(CPU(cpu))) {
             error_report("kernel's vp_index != QEMU's vp_index");
             return -ENXIO;
         }
@@ -1937,7 +1937,8 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
             kvm_msr_entry_add(cpu, HV_X64_MSR_VP_RUNTIME, env->msr_hv_runtime);
         }
         if (cpu->hyperv_vpindex && hv_vpindex_settable) {
-            kvm_msr_entry_add(cpu, HV_X64_MSR_VP_INDEX, hyperv_vp_index(cpu));
+            kvm_msr_entry_add(cpu, HV_X64_MSR_VP_INDEX,
+                              hyperv_vp_index(CPU(cpu)));
         }
         if (cpu->hyperv_synic) {
             int j;
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index a19c1417ed..b8f4675219 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -9,6 +9,7 @@ devices-dirs-$(CONFIG_SOFTMMU) += cpu/
 devices-dirs-$(CONFIG_SOFTMMU) += display/
 devices-dirs-$(CONFIG_SOFTMMU) += dma/
 devices-dirs-$(CONFIG_SOFTMMU) += gpio/
+devices-dirs-$(CONFIG_SOFTMMU) += hyperv/
 devices-dirs-$(CONFIG_SOFTMMU) += i2c/
 devices-dirs-$(CONFIG_SOFTMMU) += ide/
 devices-dirs-$(CONFIG_SOFTMMU) += input/
diff --git a/hw/hyperv/Makefile.objs b/hw/hyperv/Makefile.objs
new file mode 100644
index 0000000000..19928b726e
--- /dev/null
+++ b/hw/hyperv/Makefile.objs
@@ -0,0 +1 @@
+obj-$(CONFIG_HYPERV) += hyperv.o
