All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/5] hyperv: VMBus implementation
@ 2020-04-03 14:23 Jon Doron
  2020-04-03 14:23 ` [PATCH v1 1/5] hyperv: expose API to determine if synic is enabled Jon Doron
                   ` (5 more replies)
  0 siblings, 6 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 14:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, vkuznets, ehabkost, Jon Doron

This is a rebase of the old patchset from Roman for HyperV VMBus
implementation.

How to use:
-device vmbus-bridge

Later on new paravirtualized devices can be implemented on top of it
(Network/SCSI/etc.)

Jon Doron (5):
  hyperv: expose API to determine if synic is enabled
  hyperv: SControl is optional to enable SynIc
  vmbus: add vmbus protocol definitions
  vmbus: vmbus implementation
  i386: Hyper-V VMBus ACPI DSDT entry

 Makefile.objs                  |    1 +
 hw/Kconfig                     |    1 +
 hw/Makefile.objs               |    1 +
 hw/hyperv/hyperv.c             |  250 ++--
 hw/i386/Kconfig                |    1 +
 hw/i386/acpi-build.c           |   42 +
 hw/i386/pc_q35.c               |    2 +
 hw/vmbus/Kconfig               |    3 +
 hw/vmbus/Makefile.objs         |    1 +
 hw/vmbus/trace-events          |    8 +
 hw/vmbus/vmbus.c               | 2422 ++++++++++++++++++++++++++++++++
 include/hw/hyperv/hyperv.h     |    3 +
 include/hw/vmbus/vmbus-proto.h |  222 +++
 include/hw/vmbus/vmbus.h       |  109 ++
 target/i386/hyperv.c           |    2 +
 15 files changed, 2986 insertions(+), 82 deletions(-)
 create mode 100644 hw/vmbus/Kconfig
 create mode 100644 hw/vmbus/Makefile.objs
 create mode 100644 hw/vmbus/trace-events
 create mode 100644 hw/vmbus/vmbus.c
 create mode 100644 include/hw/vmbus/vmbus-proto.h
 create mode 100644 include/hw/vmbus/vmbus.h

-- 
2.24.1



^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v1 1/5] hyperv: expose API to determine if synic is enabled
  2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
@ 2020-04-03 14:23 ` Jon Doron
  2020-04-03 14:23 ` [PATCH v1 2/5] hyperv: SControl is optional to enable SynIc Jon Doron
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 14:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, vkuznets, ehabkost, Jon Doron

Signed-off-by: Jon Doron <arilou@gmail.com>
---
 hw/hyperv/hyperv.c         | 8 ++++++++
 include/hw/hyperv/hyperv.h | 1 +
 2 files changed, 9 insertions(+)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index 8ca3706f5b..ddf4f32c60 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -37,6 +37,13 @@ typedef struct SynICState {
 #define TYPE_SYNIC "hyperv-synic"
 #define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
 
+static bool synic_enabled;
+
+bool hyperv_is_synic_enabled(void)
+{
+    return synic_enabled;
+}
+
 static SynICState *get_synic(CPUState *cs)
 {
     return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
@@ -133,6 +140,7 @@ void hyperv_synic_add(CPUState *cs)
     object_property_add_child(OBJECT(cs), "synic", obj, &error_abort);
     object_unref(obj);
     object_property_set_bool(obj, true, "realized", &error_abort);
+    synic_enabled = true;
 }
 
 void hyperv_synic_reset(CPUState *cs)
diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h
index 597381cb01..a63ee0003c 100644
--- a/include/hw/hyperv/hyperv.h
+++ b/include/hw/hyperv/hyperv.h
@@ -79,5 +79,6 @@ void hyperv_synic_add(CPUState *cs);
 void hyperv_synic_reset(CPUState *cs);
 void hyperv_synic_update(CPUState *cs, bool enable,
                          hwaddr msg_page_addr, hwaddr event_page_addr);
+bool hyperv_is_synic_enabled(void);
 
 #endif
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v1 2/5] hyperv: SControl is optional to enable SynIc
  2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
  2020-04-03 14:23 ` [PATCH v1 1/5] hyperv: expose API to determine if synic is enabled Jon Doron
@ 2020-04-03 14:23 ` Jon Doron
  2020-04-03 14:23 ` [PATCH v1 3/5] vmbus: add vmbus protocol definitions Jon Doron
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 14:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, vkuznets, ehabkost, Jon Doron

SynIc can be enabled regardless of the SControl mechanisim which can
register a GSI for a given SintRoute.

This behaviour can achived by setting enabling SIMP and then the guest
will poll on the message slot.

Once there is another message pending the host will set the message slot
with the pending flag.
When the guest polls from the message slot, incase the pending flag is
set it will write to the HV_X64_MSR_EOM indicating it has cleared the
slow and we can try and push our message again.

Signed-off-by: Jon Doron <arilou@gmail.com>
---
 hw/hyperv/hyperv.c         | 242 ++++++++++++++++++++++++-------------
 include/hw/hyperv/hyperv.h |   2 +
 target/i386/hyperv.c       |   2 +
 3 files changed, 164 insertions(+), 82 deletions(-)

diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c
index ddf4f32c60..1dc577a0ab 100644
--- a/hw/hyperv/hyperv.c
+++ b/hw/hyperv/hyperv.c
@@ -20,18 +20,72 @@
 #include "qemu/rcu_queue.h"
 #include "hw/hyperv/hyperv.h"
 
+/*
+ * KVM has its own message producers (SynIC timers).  To guarantee
+ * serialization with both KVM vcpu and the guest cpu, the messages are first
+ * staged in an intermediate area and then posted to the SynIC message page in
+ * the vcpu thread.
+ */
+typedef struct HvSintStagedMessage {
+    /* message content staged by hyperv_post_msg */
+    struct hyperv_message msg;
+    /* callback + data (r/o) to complete the processing in a BH */
+    HvSintMsgCb cb;
+    void *cb_data;
+    /* message posting status filled by cpu_post_msg */
+    int status;
+    /* passing the buck: */
+    enum {
+        /* initial state */
+        HV_STAGED_MSG_FREE,
+        /*
+         * hyperv_post_msg (e.g. in main loop) grabs the staged area (FREE ->
+         * BUSY), copies msg, and schedules cpu_post_msg on the assigned cpu
+         */
+        HV_STAGED_MSG_BUSY,
+        /*
+         * cpu_post_msg (vcpu thread) tries to copy staged msg to msg slot,
+         * notify the guest, records the status, marks the posting done (BUSY
+         * -> POSTED), and schedules sint_msg_bh BH
+         */
+        HV_STAGED_MSG_POSTED,
+        /*
+         * sint_msg_bh (BH) verifies that the posting is done, runs the
+         * callback, and starts over (POSTED -> FREE)
+         */
+    } state;
+} HvSintStagedMessage;
+
+struct SynICState;
+
+struct HvSintRoute {
+    uint32_t sint;
+    struct SynICState *synic;
+    int gsi;
+    EventNotifier sint_set_notifier;
+    EventNotifier sint_ack_notifier;
+
+    HvSintStagedMessage *staged_msg;
+
+    unsigned refcount;
+    QLIST_ENTRY(HvSintRoute) link;
+};
+
 typedef struct SynICState {
     DeviceState parent_obj;
 
     CPUState *cs;
 
-    bool enabled;
+    bool sctl_enabled;
     hwaddr msg_page_addr;
     hwaddr event_page_addr;
     MemoryRegion msg_page_mr;
     MemoryRegion event_page_mr;
     struct hyperv_message_page *msg_page;
     struct hyperv_event_flags_page *event_page;
+
+    QemuMutex sint_routes_mutex;
+    QLIST_HEAD(, HvSintRoute) sint_routes;
 } SynICState;
 
 #define TYPE_SYNIC "hyperv-synic"
@@ -49,11 +103,11 @@ static SynICState *get_synic(CPUState *cs)
     return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
 }
 
-static void synic_update(SynICState *synic, bool enable,
+static void synic_update(SynICState *synic, bool sctl_enable,
                          hwaddr msg_page_addr, hwaddr event_page_addr)
 {
 
-    synic->enabled = enable;
+    synic->sctl_enabled = sctl_enable;
     if (synic->msg_page_addr != msg_page_addr) {
         if (synic->msg_page_addr) {
             memory_region_del_subregion(get_system_memory(),
@@ -78,7 +132,7 @@ static void synic_update(SynICState *synic, bool enable,
     }
 }
 
-void hyperv_synic_update(CPUState *cs, bool enable,
+void hyperv_synic_update(CPUState *cs, bool sctl_enable,
                          hwaddr msg_page_addr, hwaddr event_page_addr)
 {
     SynICState *synic = get_synic(cs);
@@ -87,7 +141,7 @@ void hyperv_synic_update(CPUState *cs, bool enable,
         return;
     }
 
-    synic_update(synic, enable, msg_page_addr, event_page_addr);
+    synic_update(synic, sctl_enable, msg_page_addr, event_page_addr);
 }
 
 static void synic_realize(DeviceState *dev, Error **errp)
@@ -108,16 +162,20 @@ static void synic_realize(DeviceState *dev, Error **errp)
                            sizeof(*synic->event_page), &error_abort);
     synic->msg_page = memory_region_get_ram_ptr(&synic->msg_page_mr);
     synic->event_page = memory_region_get_ram_ptr(&synic->event_page_mr);
+    qemu_mutex_init(&synic->sint_routes_mutex);
+    QLIST_INIT(&synic->sint_routes);
 
     g_free(msgp_name);
     g_free(eventp_name);
 }
+
 static void synic_reset(DeviceState *dev)
 {
     SynICState *synic = SYNIC(dev);
     memset(synic->msg_page, 0, sizeof(*synic->msg_page));
     memset(synic->event_page, 0, sizeof(*synic->event_page));
     synic_update(synic, false, 0, 0);
+    assert(QLIST_EMPTY(&synic->sint_routes));
 }
 
 static void synic_class_init(ObjectClass *klass, void *data)
@@ -166,54 +224,6 @@ static void synic_register_types(void)
 
 type_init(synic_register_types)
 
-/*
- * KVM has its own message producers (SynIC timers).  To guarantee
- * serialization with both KVM vcpu and the guest cpu, the messages are first
- * staged in an intermediate area and then posted to the SynIC message page in
- * the vcpu thread.
- */
-typedef struct HvSintStagedMessage {
-    /* message content staged by hyperv_post_msg */
-    struct hyperv_message msg;
-    /* callback + data (r/o) to complete the processing in a BH */
-    HvSintMsgCb cb;
-    void *cb_data;
-    /* message posting status filled by cpu_post_msg */
-    int status;
-    /* passing the buck: */
-    enum {
-        /* initial state */
-        HV_STAGED_MSG_FREE,
-        /*
-         * hyperv_post_msg (e.g. in main loop) grabs the staged area (FREE ->
-         * BUSY), copies msg, and schedules cpu_post_msg on the assigned cpu
-         */
-        HV_STAGED_MSG_BUSY,
-        /*
-         * cpu_post_msg (vcpu thread) tries to copy staged msg to msg slot,
-         * notify the guest, records the status, marks the posting done (BUSY
-         * -> POSTED), and schedules sint_msg_bh BH
-         */
-        HV_STAGED_MSG_POSTED,
-        /*
-         * sint_msg_bh (BH) verifies that the posting is done, runs the
-         * callback, and starts over (POSTED -> FREE)
-         */
-    } state;
-} HvSintStagedMessage;
-
-struct HvSintRoute {
-    uint32_t sint;
-    SynICState *synic;
-    int gsi;
-    EventNotifier sint_set_notifier;
-    EventNotifier sint_ack_notifier;
-
-    HvSintStagedMessage *staged_msg;
-
-    unsigned refcount;
-};
-
 static CPUState *hyperv_find_vcpu(uint32_t vp_index)
 {
     CPUState *cs = qemu_get_cpu(vp_index);
@@ -257,7 +267,7 @@ static void cpu_post_msg(CPUState *cs, run_on_cpu_data data)
 
     assert(staged_msg->state == HV_STAGED_MSG_BUSY);
 
-    if (!synic->enabled || !synic->msg_page_addr) {
+    if (!synic->msg_page_addr) {
         staged_msg->status = -ENXIO;
         goto posted;
     }
@@ -341,7 +351,7 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno)
     if (eventno > HV_EVENT_FLAGS_COUNT) {
         return -EINVAL;
     }
-    if (!synic->enabled || !synic->event_page_addr) {
+    if (!synic->sctl_enabled || !synic->event_page_addr) {
         return -ENXIO;
     }
 
@@ -362,11 +372,13 @@ int hyperv_set_event_flag(HvSintRoute *sint_route, unsigned eventno)
 HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
                                    HvSintMsgCb cb, void *cb_data)
 {
-    HvSintRoute *sint_route;
-    EventNotifier *ack_notifier;
+    HvSintRoute *sint_route = NULL;
+    EventNotifier *ack_notifier = NULL;
     int r, gsi;
     CPUState *cs;
     SynICState *synic;
+    bool ack_event_initialized = false, sint_notifier_initialized = false,
+         irqfd_initialized = false;
 
     cs = hyperv_find_vcpu(vp_index);
     if (!cs) {
@@ -379,57 +391,82 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
     }
 
     sint_route = g_new0(HvSintRoute, 1);
-    r = event_notifier_init(&sint_route->sint_set_notifier, false);
-    if (r) {
-        goto err;
+    if (!sint_route) {
+        goto cleanup_err;
     }
 
+    sint_route->gsi = 0;
+    sint_route->synic = synic;
+    sint_route->sint = sint;
+    sint_route->refcount = 1;
 
     ack_notifier = cb ? &sint_route->sint_ack_notifier : NULL;
     if (ack_notifier) {
         sint_route->staged_msg = g_new0(HvSintStagedMessage, 1);
+        if (!sint_route->staged_msg) {
+            goto cleanup_err;
+        }
         sint_route->staged_msg->cb = cb;
         sint_route->staged_msg->cb_data = cb_data;
 
         r = event_notifier_init(ack_notifier, false);
         if (r) {
-            goto err_sint_set_notifier;
+            goto cleanup_err;
         }
-
         event_notifier_set_handler(ack_notifier, sint_ack_handler);
+        ack_event_initialized = true;
+    }
+
+    /* See if we are done or we need to setup a GSI for this SintRoute */
+    if (!synic->sctl_enabled) {
+        goto cleanup;
+    }
+
+    /* We need to setup a GSI for this SintRoute */
+    r = event_notifier_init(&sint_route->sint_set_notifier, false);
+    if (r) {
+        goto cleanup_err;
     }
+    sint_notifier_initialized = true;
 
     gsi = kvm_irqchip_add_hv_sint_route(kvm_state, vp_index, sint);
     if (gsi < 0) {
-        goto err_gsi;
+        goto cleanup_err;
     }
+    irqfd_initialized = true;
 
     r = kvm_irqchip_add_irqfd_notifier_gsi(kvm_state,
                                            &sint_route->sint_set_notifier,
                                            ack_notifier, gsi);
     if (r) {
-        goto err_irqfd;
+        goto cleanup_err;
     }
     sint_route->gsi = gsi;
-    sint_route->synic = synic;
-    sint_route->sint = sint;
-    sint_route->refcount = 1;
-
+cleanup:
+    qemu_mutex_lock(&synic->sint_routes_mutex);
+    QLIST_INSERT_HEAD_RCU(&synic->sint_routes, sint_route, link);
+    qemu_mutex_unlock(&synic->sint_routes_mutex);
     return sint_route;
 
-err_irqfd:
-    kvm_irqchip_release_virq(kvm_state, gsi);
-err_gsi:
+cleanup_err:
+    if (irqfd_initialized) {
+        kvm_irqchip_release_virq(kvm_state, gsi);
+    }
+
+    if (sint_notifier_initialized) {
+        event_notifier_cleanup(&sint_route->sint_set_notifier);
+    }
+
     if (ack_notifier) {
-        event_notifier_set_handler(ack_notifier, NULL);
-        event_notifier_cleanup(ack_notifier);
+        if (ack_event_initialized) {
+            event_notifier_set_handler(ack_notifier, NULL);
+            event_notifier_cleanup(ack_notifier);
+        }
+
         g_free(sint_route->staged_msg);
     }
-err_sint_set_notifier:
-    event_notifier_cleanup(&sint_route->sint_set_notifier);
-err:
-    g_free(sint_route);
 
+    g_free(sint_route);
     return NULL;
 }
 
@@ -440,6 +477,8 @@ void hyperv_sint_route_ref(HvSintRoute *sint_route)
 
 void hyperv_sint_route_unref(HvSintRoute *sint_route)
 {
+    SynICState *synic;
+
     if (!sint_route) {
         return;
     }
@@ -450,21 +489,33 @@ void hyperv_sint_route_unref(HvSintRoute *sint_route)
         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);
+    synic = sint_route->synic;
+    qemu_mutex_lock(&synic->sint_routes_mutex);
+    QLIST_REMOVE_RCU(sint_route, link);
+    qemu_mutex_unlock(&synic->sint_routes_mutex);
+
+    if (sint_route->gsi) {
+        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);
+        event_notifier_cleanup(&sint_route->sint_set_notifier);
+    }
+
     if (sint_route->staged_msg) {
         event_notifier_set_handler(&sint_route->sint_ack_notifier, NULL);
         event_notifier_cleanup(&sint_route->sint_ack_notifier);
         g_free(sint_route->staged_msg);
     }
-    event_notifier_cleanup(&sint_route->sint_set_notifier);
     g_free(sint_route);
 }
 
 int hyperv_sint_route_set_sint(HvSintRoute *sint_route)
 {
+    if (!sint_route->gsi) {
+        return 0;
+    }
+
     return event_notifier_set(&sint_route->sint_set_notifier);
 }
 
@@ -528,6 +579,33 @@ unlock:
     return ret;
 }
 
+int hyperv_synic_eom(CPUState *cs)
+{
+    SynICState *synic = get_synic(cs);
+    HvSintRoute *sint_route;
+
+    if (!synic) {
+        return -1;
+    }
+
+    qemu_mutex_lock(&synic->sint_routes_mutex);
+    QLIST_FOREACH(sint_route, &synic->sint_routes, link) {
+        HvSintStagedMessage *staged_msg = sint_route->staged_msg;
+
+        /* Skip a SintRoute that has a GSI registered with it */
+        if (sint_route->gsi ||
+            atomic_read(&staged_msg->state) != HV_STAGED_MSG_POSTED) {
+            continue;
+        }
+
+        aio_bh_schedule_oneshot(qemu_get_aio_context(), sint_msg_bh,
+                                sint_route);
+    }
+    qemu_mutex_unlock(&synic->sint_routes_mutex);
+
+    return 0;
+}
+
 uint16_t hyperv_hcall_post_message(uint64_t param, bool fast)
 {
     uint16_t ret;
diff --git a/include/hw/hyperv/hyperv.h b/include/hw/hyperv/hyperv.h
index a63ee0003c..ef9f6b6c09 100644
--- a/include/hw/hyperv/hyperv.h
+++ b/include/hw/hyperv/hyperv.h
@@ -28,6 +28,8 @@ void hyperv_sint_route_unref(HvSintRoute *sint_route);
 
 int hyperv_sint_route_set_sint(HvSintRoute *sint_route);
 
+int hyperv_synic_eom(CPUState *cs);
+
 /*
  * Submit a message to be posted in vcpu context.  If the submission succeeds,
  * the status of posting the message is reported via the callback associated
diff --git a/target/i386/hyperv.c b/target/i386/hyperv.c
index 26efc1e0e6..f11268df48 100644
--- a/target/i386/hyperv.c
+++ b/target/i386/hyperv.c
@@ -66,6 +66,8 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
         case HV_X64_MSR_SIEFP:
             env->msr_hv_synic_evt_page = exit->u.synic.evt_page;
             break;
+        case HV_X64_MSR_EOM:
+            return hyperv_synic_eom(CPU(cpu));
         default:
             return -1;
         }
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v1 3/5] vmbus: add vmbus protocol definitions
  2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
  2020-04-03 14:23 ` [PATCH v1 1/5] hyperv: expose API to determine if synic is enabled Jon Doron
  2020-04-03 14:23 ` [PATCH v1 2/5] hyperv: SControl is optional to enable SynIc Jon Doron
@ 2020-04-03 14:23 ` Jon Doron
  2020-04-03 14:23 ` [PATCH v1 4/5] vmbus: vmbus implementation Jon Doron
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 14:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, vkuznets, Roman Kagan, ehabkost, Jon Doron

Add a header with data structures and constants used in Hyper-V VMBus
hypervisor <-> guest interactions.

Based on the respective stuff from Linux kernel.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Jon Doron <arilou@gmail.com>
---
 include/hw/vmbus/vmbus-proto.h | 222 +++++++++++++++++++++++++++++++++
 1 file changed, 222 insertions(+)
 create mode 100644 include/hw/vmbus/vmbus-proto.h

diff --git a/include/hw/vmbus/vmbus-proto.h b/include/hw/vmbus/vmbus-proto.h
new file mode 100644
index 0000000000..80882e4fc6
--- /dev/null
+++ b/include/hw/vmbus/vmbus-proto.h
@@ -0,0 +1,222 @@
+/*
+ * QEMU Hyper-V VMBus support
+ *
+ * Copyright (c) 2017-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 VMBUS_PROTO_H
+#define VMBUS_PROTO_H
+
+#define VMBUS_VERSION_WS2008                    ((0 << 16) | (13))
+#define VMBUS_VERSION_WIN7                      ((1 << 16) | (1))
+#define VMBUS_VERSION_WIN8                      ((2 << 16) | (4))
+#define VMBUS_VERSION_WIN8_1                    ((3 << 16) | (0))
+#define VMBUS_VERSION_WIN10                     ((4 << 16) | (0))
+#define VMBUS_VERSION_INVAL                     -1
+#define VMBUS_VERSION_CURRENT                   VMBUS_VERSION_WIN10
+
+#define VMBUS_MESSAGE_CONNECTION_ID             1
+#define VMBUS_EVENT_CONNECTION_ID               2
+#define VMBUS_MONITOR_CONNECTION_ID             3
+#define VMBUS_SINT                              2
+
+#define VMBUS_MSG_INVALID               0
+#define VMBUS_MSG_OFFERCHANNEL          1
+#define VMBUS_MSG_RESCIND_CHANNELOFFER  2
+#define VMBUS_MSG_REQUESTOFFERS         3
+#define VMBUS_MSG_ALLOFFERS_DELIVERED   4
+#define VMBUS_MSG_OPENCHANNEL           5
+#define VMBUS_MSG_OPENCHANNEL_RESULT    6
+#define VMBUS_MSG_CLOSECHANNEL          7
+#define VMBUS_MSG_GPADL_HEADER          8
+#define VMBUS_MSG_GPADL_BODY            9
+#define VMBUS_MSG_GPADL_CREATED         10
+#define VMBUS_MSG_GPADL_TEARDOWN        11
+#define VMBUS_MSG_GPADL_TORNDOWN        12
+#define VMBUS_MSG_RELID_RELEASED        13
+#define VMBUS_MSG_INITIATE_CONTACT      14
+#define VMBUS_MSG_VERSION_RESPONSE      15
+#define VMBUS_MSG_UNLOAD                16
+#define VMBUS_MSG_UNLOAD_RESPONSE       17
+#define VMBUS_MSG_COUNT                 18
+
+#define VMBUS_MESSAGE_SIZE_ALIGN        sizeof(uint64_t)
+
+#define VMBUS_PACKET_INVALID                    0x0
+#define VMBUS_PACKET_SYNCH                      0x1
+#define VMBUS_PACKET_ADD_XFER_PAGESET           0x2
+#define VMBUS_PACKET_RM_XFER_PAGESET            0x3
+#define VMBUS_PACKET_ESTABLISH_GPADL            0x4
+#define VMBUS_PACKET_TEARDOWN_GPADL             0x5
+#define VMBUS_PACKET_DATA_INBAND                0x6
+#define VMBUS_PACKET_DATA_USING_XFER_PAGES      0x7
+#define VMBUS_PACKET_DATA_USING_GPADL           0x8
+#define VMBUS_PACKET_DATA_USING_GPA_DIRECT      0x9
+#define VMBUS_PACKET_CANCEL_REQUEST             0xa
+#define VMBUS_PACKET_COMP                       0xb
+#define VMBUS_PACKET_DATA_USING_ADDITIONAL_PKT  0xc
+#define VMBUS_PACKET_ADDITIONAL_DATA            0xd
+
+#define VMBUS_CHANNEL_USER_DATA_SIZE            120
+
+#define VMBUS_OFFER_MONITOR_ALLOCATED           0x1
+#define VMBUS_OFFER_INTERRUPT_DEDICATED         0x1
+
+#define VMBUS_RING_BUFFER_FEAT_PENDING_SZ       (1ul << 0)
+
+#define VMBUS_CHANNEL_ENUMERATE_DEVICE_INTERFACE      0x1
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_TRANSFER_PAGES  0x2
+#define VMBUS_CHANNEL_SERVER_SUPPORTS_GPADLS          0x4
+#define VMBUS_CHANNEL_NAMED_PIPE_MODE                 0x10
+#define VMBUS_CHANNEL_LOOPBACK_OFFER                  0x100
+#define VMBUS_CHANNEL_PARENT_OFFER                    0x200
+#define VMBUS_CHANNEL_REQUEST_MONITORED_NOTIFICATION  0x400
+#define VMBUS_CHANNEL_TLNPI_PROVIDER_OFFER            0x2000
+
+#define VMBUS_PACKET_FLAG_REQUEST_COMPLETION    1
+
+typedef struct vmbus_message_header {
+    uint32_t message_type;
+    uint32_t _padding;
+} vmbus_message_header;
+
+typedef struct vmbus_message_initiate_contact {
+    vmbus_message_header header;
+    uint32_t version_requested;
+    uint32_t target_vcpu;
+    uint64_t interrupt_page;
+    uint64_t monitor_page1;
+    uint64_t monitor_page2;
+} vmbus_message_initiate_contact;
+
+typedef struct vmbus_message_version_response {
+    vmbus_message_header header;
+    uint8_t version_supported;
+    uint8_t status;
+} vmbus_message_version_response;
+
+typedef struct vmbus_message_offer_channel {
+    vmbus_message_header header;
+    uint8_t  type_uuid[16];
+    uint8_t  instance_uuid[16];
+    uint64_t _reserved1;
+    uint64_t _reserved2;
+    uint16_t channel_flags;
+    uint16_t mmio_size_mb;
+    uint8_t  user_data[VMBUS_CHANNEL_USER_DATA_SIZE];
+    uint16_t sub_channel_index;
+    uint16_t _reserved3;
+    uint32_t child_relid;
+    uint8_t  monitor_id;
+    uint8_t  monitor_flags;      // VMBUS_OFFER_MONITOR_*
+    uint16_t interrupt_flags;    // VMBUS_OFFER_INTERRUPT_*
+    uint32_t connection_id;
+} vmbus_message_offer_channel;
+
+typedef struct vmbus_message_rescind_channel_offer {
+    vmbus_message_header header;
+    uint32_t child_relid;
+} vmbus_message_rescind_channel_offer;
+
+typedef struct vmbus_gpa_range {
+    uint32_t byte_count;
+    uint32_t byte_offset;
+    uint64_t pfn_array[0];
+} vmbus_gpa_range;
+
+typedef struct vmbus_message_gpadl_header {
+    vmbus_message_header header;
+    uint32_t child_relid;
+    uint32_t gpadl_id;
+    uint16_t range_buflen;
+    uint16_t rangecount;
+    vmbus_gpa_range range;
+} QEMU_PACKED vmbus_message_gpadl_header;
+
+typedef struct vmbus_message_gpadl_body {
+    vmbus_message_header header;
+    uint32_t message_number;
+    uint32_t gpadl_id;
+    uint64_t pfn_array[0];
+} vmbus_message_gpadl_body;
+
+typedef struct vmbus_message_gpadl_created {
+    vmbus_message_header header;
+    uint32_t child_relid;
+    uint32_t gpadl_id;
+    uint32_t status;
+} vmbus_message_gpadl_created;
+
+typedef struct vmbus_message_gpadl_teardown {
+    vmbus_message_header header;
+    uint32_t child_relid;
+    uint32_t gpadl_id;
+} vmbus_message_gpadl_teardown;
+
+typedef struct vmbus_message_gpadl_torndown {
+    vmbus_message_header header;
+    uint32_t gpadl_id;
+} vmbus_message_gpadl_torndown;
+
+typedef struct vmbus_message_open_channel {
+    vmbus_message_header header;
+    uint32_t child_relid;
+    uint32_t open_id;
+    uint32_t ring_buffer_gpadl_id;
+    uint32_t target_vp;
+    uint32_t ring_buffer_offset;
+    uint8_t  user_data[VMBUS_CHANNEL_USER_DATA_SIZE];
+} vmbus_message_open_channel;
+
+typedef struct vmbus_message_open_result {
+    vmbus_message_header header;
+    uint32_t child_relid;
+    uint32_t open_id;
+    uint32_t status;
+} vmbus_message_open_result;
+
+typedef struct vmbus_message_close_channel {
+    vmbus_message_header header;
+    uint32_t child_relid;
+} vmbus_message_close_channel;
+
+typedef struct vmbus_ring_buffer {
+    uint32_t write_index;
+    uint32_t read_index;
+    uint32_t interrupt_mask;
+    uint32_t pending_send_sz;
+    uint32_t _reserved1[12];
+    uint32_t feature_bits;     // VMBUS_RING_BUFFER_FEAT_*
+} vmbus_ring_buffer;
+
+typedef struct vmbus_packet_hdr {
+    uint16_t type;
+    uint16_t offset_qwords;
+    uint16_t len_qwords;
+    uint16_t flags;
+    uint64_t transaction_id;
+} vmbus_packet_hdr;
+
+typedef struct vmbus_pkt_gpa_direct {
+    uint32_t _reserved;
+    uint32_t rangecount;
+    vmbus_gpa_range range[0];
+} vmbus_pkt_gpa_direct;
+
+typedef struct vmbus_xferpg_range {
+    uint32_t byte_count;
+    uint32_t byte_offset;
+} vmbus_xferpg_range;
+
+typedef struct vmbus_pkt_xferpg {
+    uint16_t buffer_id;
+    uint8_t sender_owns_set;
+    uint8_t _reserved;
+    uint32_t rangecount;
+    vmbus_xferpg_range range[0];
+} vmbus_pkt_xferpg;
+
+#endif
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v1 4/5] vmbus: vmbus implementation
  2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
                   ` (2 preceding siblings ...)
  2020-04-03 14:23 ` [PATCH v1 3/5] vmbus: add vmbus protocol definitions Jon Doron
@ 2020-04-03 14:23 ` Jon Doron
  2020-04-03 14:23 ` [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry Jon Doron
  2020-04-03 22:48 ` [PATCH v1 0/5] hyperv: VMBus implementation no-reply
  5 siblings, 0 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 14:23 UTC (permalink / raw)
  To: qemu-devel; +Cc: pbonzini, vkuznets, Roman Kagan, ehabkost, Jon Doron

Add the VMBus infrastructure -- bus, devices, root bridge, vmbus state
machine, vmbus channel interactions, etc.

TODO:
 - split into smaller palatable pieces
 - more comments
 - check and handle corner cases

Kudos to Evgeny Yakovlev (formerly eyakovlev@virtuozzo.com) and Andrey
Smetatin (formerly asmetanin@virtuozzo.com) for research and
prototyping.

VMBus is a collection of technologies.  At its lowest layer, it's a message
passing and signaling mechanism, allowing efficient passing of messages to and
from guest VMs.  A layer higher, it's a mechanism for defining channels of
communication, where each channel is tagged with a type (which implies a
protocol) and a instance ID.  A layer higher than that, it's a bus driver,
serving as the basis of device enumeration within a VM, where a channel can
optionally be exposed as a paravirtual device.  When a server-side (paravirtual
back-end) component wishes to offer a channel to a guest VM, it does so by
specifying a channel type, a mode, and an instance ID.  VMBus then exposes this
in the guest.

More information about VMBus can be found in the file
vmbuskernelmodeclientlibapi.h in Microsoft's WDK.

Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Jon Doron <arilou@gmail.com>
---
 Makefile.objs            |    1 +
 hw/Kconfig               |    1 +
 hw/Makefile.objs         |    1 +
 hw/i386/Kconfig          |    1 +
 hw/i386/pc_q35.c         |    2 +
 hw/vmbus/Kconfig         |    3 +
 hw/vmbus/Makefile.objs   |    1 +
 hw/vmbus/trace-events    |    8 +
 hw/vmbus/vmbus.c         | 2422 ++++++++++++++++++++++++++++++++++++++
 include/hw/vmbus/vmbus.h |  109 ++
 10 files changed, 2549 insertions(+)
 create mode 100644 hw/vmbus/Kconfig
 create mode 100644 hw/vmbus/Makefile.objs
 create mode 100644 hw/vmbus/trace-events
 create mode 100644 hw/vmbus/vmbus.c
 create mode 100644 include/hw/vmbus/vmbus.h

diff --git a/Makefile.objs b/Makefile.objs
index a7c967633a..4943e7bf73 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -185,6 +185,7 @@ trace-events-subdirs += hw/watchdog
 trace-events-subdirs += hw/xen
 trace-events-subdirs += hw/gpio
 trace-events-subdirs += hw/riscv
+trace-events-subdirs += hw/vmbus
 trace-events-subdirs += migration
 trace-events-subdirs += net
 trace-events-subdirs += ui
diff --git a/hw/Kconfig b/hw/Kconfig
index ecf491bf04..49ace0a4b5 100644
--- a/hw/Kconfig
+++ b/hw/Kconfig
@@ -39,6 +39,7 @@ source usb/Kconfig
 source virtio/Kconfig
 source vfio/Kconfig
 source watchdog/Kconfig
+source vmbus/Kconfig
 
 # arch Kconfig
 source arm/Kconfig
diff --git a/hw/Makefile.objs b/hw/Makefile.objs
index 660e2b4373..9037bc8095 100644
--- a/hw/Makefile.objs
+++ b/hw/Makefile.objs
@@ -40,6 +40,7 @@ devices-dirs-$(CONFIG_MEM_DEVICE) += mem/
 devices-dirs-$(CONFIG_NUBUS) += nubus/
 devices-dirs-y += semihosting/
 devices-dirs-y += smbios/
+devices-dirs-$(CONFIG_VMBUS) += vmbus/
 endif
 
 common-obj-y += $(devices-dirs-y)
diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig
index c93f32f657..838ec28667 100644
--- a/hw/i386/Kconfig
+++ b/hw/i386/Kconfig
@@ -23,6 +23,7 @@ config PC
     imply TPM_TIS_ISA
     imply VGA_PCI
     imply VIRTIO_VGA
+    imply VMBUS
     select FDC
     select I8259
     select I8254
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index d37c425e22..767c137718 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -54,6 +54,7 @@
 #include "qemu/error-report.h"
 #include "sysemu/numa.h"
 #include "hw/mem/nvdimm.h"
+#include "hw/vmbus/vmbus.h"
 
 /* ICH9 AHCI has 6 ports */
 #define MAX_SATA_PORTS     6
@@ -346,6 +347,7 @@ static void pc_q35_machine_options(MachineClass *m)
     machine_class_allow_dynamic_sysbus_dev(m, TYPE_AMD_IOMMU_DEVICE);
     machine_class_allow_dynamic_sysbus_dev(m, TYPE_INTEL_IOMMU_DEVICE);
     machine_class_allow_dynamic_sysbus_dev(m, TYPE_RAMFB_DEVICE);
+    machine_class_allow_dynamic_sysbus_dev(m, TYPE_VMBUS_BRIDGE);
     m->max_cpus = 288;
 }
 
diff --git a/hw/vmbus/Kconfig b/hw/vmbus/Kconfig
new file mode 100644
index 0000000000..e925c2a9be
--- /dev/null
+++ b/hw/vmbus/Kconfig
@@ -0,0 +1,3 @@
+config VMBUS
+    bool
+    depends on HYPERV
diff --git a/hw/vmbus/Makefile.objs b/hw/vmbus/Makefile.objs
new file mode 100644
index 0000000000..3f0708588e
--- /dev/null
+++ b/hw/vmbus/Makefile.objs
@@ -0,0 +1 @@
+obj-y += vmbus.o
diff --git a/hw/vmbus/trace-events b/hw/vmbus/trace-events
new file mode 100644
index 0000000000..4e1c507cb8
--- /dev/null
+++ b/hw/vmbus/trace-events
@@ -0,0 +1,8 @@
+# vmbus
+vmbus_initiate_contact(uint32_t version, uint32_t vcpu, uint64_t monitor_page1, uint64_t monitor_page2, uint64_t interrupt_page) "version requested %d, target vcpu %d, monitor pages 0x%"PRIx64" 0x%"PRIx64", interrupt page 0x%"PRIx64""
+vmbus_recv_message(uint32_t type, uint32_t size) "recvd message type %d, size %d"
+vmbus_signal_event(void) "vmbus event signaled"
+vmbus_signal_channel(uint32_t relid) "signaling channel id %d"
+vmbus_post_msg(uint32_t type, uint32_t size) "posting message type %d, size %d"
+vmbus_post_reply_callback(int status) "staged message status %d"
+vmbus_process_incoming_message(uint32_t message_type) "processing incoming message %d"
diff --git a/hw/vmbus/vmbus.c b/hw/vmbus/vmbus.c
new file mode 100644
index 0000000000..18e254f5c2
--- /dev/null
+++ b/hw/vmbus/vmbus.c
@@ -0,0 +1,2422 @@
+/*
+ * QEMU Hyper-V VMBus
+ *
+ * Copyright (c) 2017-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/error-report.h"
+#include "qemu/main-loop.h"
+#include "qemu/uuid.h"
+#include "qapi/error.h"
+#include "hw/vmbus/vmbus.h"
+#include "hw/sysbus.h"
+#include "hw/hyperv/hyperv.h"
+#include "migration/vmstate.h"
+#include "trace.h"
+
+#define TYPE_VMBUS "vmbus"
+#define VMBUS(obj) OBJECT_CHECK(VMBus, (obj), TYPE_VMBUS)
+
+#define VMBUS_CHAN_RELID_COUNT      HV_EVENT_FLAGS_COUNT
+#define VMBUS_CHAN_FIRST_RELID      1 /* 0 is reserved */
+#define VMBUS_CHAN_CONNID_COUNT     HV_EVENT_FLAGS_COUNT
+#define VMBUS_CHAN_FIRST_CONNID     (VMBUS_MONITOR_CONNECTION_ID + 1)
+
+#define VMBUS_VMSTATE_VERSION_ID    1
+
+#define VMBUS_RX_QUEUE_CAPACITY     16
+
+typedef struct VMBusGpadl {
+    QTAILQ_ENTRY(VMBusGpadl) link;
+
+    uint32_t id;
+    uint32_t child_relid;
+
+    uint32_t num_gfns;
+    uint32_t seen_gfns;
+    uint64_t *gfns;
+
+    bool alive;
+    bool in_use;
+} VMBusGpadl;
+
+typedef enum VMBusOfferState {
+    VMOFFER_INIT,
+    VMOFFER_SENDING,
+    VMOFFER_SENT,
+} VMBusOfferState;
+
+typedef enum VMBusChannelState {
+    VMCHAN_INIT,
+    VMCHAN_OPENING,
+    VMCHAN_OPEN,
+} VMBusChannelState;
+
+typedef struct VMBusRingBuf {
+    VMBusGpadl *gpadl;
+    AddressSpace *as;
+    DMADirection dir;
+    dma_addr_t rb_addr;
+    uint32_t base;
+    uint32_t len;
+    uint32_t my_idx;
+    uint32_t pending_sz;
+} VMBusRingBuf;
+
+typedef struct VMBusChannel {
+    VMBusDevice *dev;
+
+    uint32_t relid;
+    uint16_t subchan_idx;
+    uint32_t connid;
+    uint32_t open_id;
+    uint32_t target_vp;
+    uint32_t rb_gpadl;
+    uint32_t rb_rcv_offset;
+
+    VMBusOfferState offer_state;
+    VMBusChannelState state;
+
+    VMBusChannelNotifyCb notify_cb;
+    EventNotifier notifier;
+
+    VMBus *vmbus;
+    HvSintRoute *notify_route;
+    VMBusGpadl *gpadl;
+
+    VMBusRingBuf ringbuf_rcv;
+    VMBusRingBuf ringbuf_snd;
+
+    uint32_t snd_reserved;
+
+    QTAILQ_ENTRY(VMBusChannel) link;
+} VMBusChannel;
+
+typedef enum VMBusState {
+    VMBUS_LISTEN,
+    VMBUS_HANDSHAKE,
+    VMBUS_OFFER,
+    VMBUS_CREATE_GPADL,
+    VMBUS_TEARDOWN_GPADL,
+    VMBUS_OPEN_CHANNEL,
+    VMBUS_UNLOAD,
+    VMBUS_STATE_MAX
+} VMBusState;
+
+typedef struct VMBus {
+    BusState parent;
+
+    VMBusState state;
+    bool msg_in_progress;
+    uint32_t version;
+    uint32_t target_vp;
+    HvSintRoute *sint_route;
+    hwaddr int_page_gpa;
+
+    DECLARE_BITMAP(chan_relid_bitmap, VMBUS_CHAN_RELID_COUNT);
+    DECLARE_BITMAP(connection_id_bitmap, VMBUS_CHAN_CONNID_COUNT);
+
+    struct hyperv_post_message_input rx_queue[VMBUS_RX_QUEUE_CAPACITY];
+    uint8_t rx_queue_head;
+    uint8_t rx_queue_size;
+    QemuMutex rx_queue_lock;
+
+    QTAILQ_HEAD(, VMBusGpadl) gpadl_list;
+    QTAILQ_HEAD(, VMBusChannel) channel_list;
+
+    EventNotifier notifier;
+} VMBus;
+
+static void vmbus_resched(VMBus *vmbus);
+static void vmbus_msg_cb(void *data, int status);
+
+static bool gpadl_full(VMBusGpadl *gpadl)
+{
+    return gpadl->seen_gfns == gpadl->num_gfns;
+}
+
+static bool gpadl_broken(VMBusGpadl *gpadl)
+{
+    return !gpadl->num_gfns;
+}
+
+static VMBusGpadl *create_gpadl(VMBus *vmbus, uint32_t id,
+                                uint32_t child_relid, uint32_t num_gfns)
+{
+    VMBusGpadl *gpadl = g_new0(VMBusGpadl, 1);
+
+    gpadl->id = id;
+    gpadl->child_relid = child_relid;
+    gpadl->num_gfns = num_gfns;
+    gpadl->gfns = g_new(uint64_t, num_gfns);
+    QTAILQ_INSERT_HEAD(&vmbus->gpadl_list, gpadl, link);
+    return gpadl;
+}
+
+static void free_gpadl(VMBus *vmbus, VMBusGpadl *gpadl)
+{
+    QTAILQ_REMOVE(&vmbus->gpadl_list, gpadl, link);
+    g_free(gpadl->gfns);
+    g_free(gpadl);
+}
+
+static VMBusGpadl *find_gpadl(VMBus *vmbus, uint32_t gpadl_id)
+{
+    VMBusGpadl *gpadl;
+    QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) {
+        if (gpadl->id == gpadl_id) {
+            return gpadl;
+        }
+    }
+    return NULL;
+}
+
+VMBusGpadl *vmbus_get_gpadl(VMBusChannel *chan, uint32_t gpadl_id)
+{
+    VMBusGpadl *gpadl = find_gpadl(chan->vmbus, gpadl_id);
+    if (gpadl) {
+        if (!gpadl->alive || gpadl->in_use) {
+            return NULL;
+        }
+        gpadl->in_use = true;
+    }
+    return gpadl;
+}
+
+void vmbus_put_gpadl(VMBusGpadl *gpadl)
+{
+    gpadl->in_use = false;
+}
+
+uint32_t vmbus_gpadl_len(VMBusGpadl *gpadl)
+{
+    return gpadl->num_gfns * TARGET_PAGE_SIZE;
+}
+
+typedef struct GpadlIter {
+    VMBusGpadl *gpadl;
+    AddressSpace *as;
+    DMADirection dir;
+    uint32_t off;
+    /* cached mapping of the currently accessed page, up to page boundary */
+    void *map;
+} GpadlIter;
+
+static void gpadl_iter_init(GpadlIter *iter, VMBusGpadl *gpadl,
+                            AddressSpace *as, DMADirection dir, uint32_t off)
+{
+    iter->gpadl = gpadl;
+    iter->as = as;
+    iter->dir = dir;
+    iter->off = off;
+    iter->map = NULL;
+}
+
+static ssize_t gpadl_iter_rw(GpadlIter *iter, void *buf, uint32_t len)
+{
+    ssize_t ret = len;
+
+    while (len) {
+        uint32_t off_pgoff = iter->off & ~TARGET_PAGE_MASK;
+        uint32_t pgleft = TARGET_PAGE_SIZE - off_pgoff;
+        uint32_t cplen = MIN(pgleft, len);
+        void *p;
+
+        if (!iter->map) {
+            dma_addr_t maddr;
+            dma_addr_t mlen = pgleft;
+            uint32_t idx = iter->off >> TARGET_PAGE_BITS;
+            assert(idx < iter->gpadl->num_gfns);
+
+            maddr = (iter->gpadl->gfns[idx] << TARGET_PAGE_BITS) | off_pgoff;
+
+            iter->map = dma_memory_map(iter->as, maddr, &mlen, iter->dir);
+            if (mlen != pgleft) {
+                dma_memory_unmap(iter->as, iter->map, mlen, iter->dir, 0);
+                return -EFAULT;
+            }
+        }
+
+        p = (void *)(((uintptr_t)iter->map & TARGET_PAGE_MASK) | off_pgoff);
+        if (iter->dir == DMA_DIRECTION_FROM_DEVICE) {
+            memcpy(p, buf, cplen);
+        } else {
+            memcpy(buf, p, cplen);
+        }
+
+        buf += cplen;
+        len -= cplen;
+        iter->off += cplen;
+        if (cplen == pgleft) {
+            uint32_t mlen = TARGET_PAGE_SIZE -
+                ((uintptr_t)iter->map & ~TARGET_PAGE_MASK);
+            dma_memory_unmap(iter->as, iter->map, mlen, iter->dir, mlen);
+            iter->map = NULL;
+        }
+    }
+
+    return ret;
+}
+
+static void gpadl_iter_done(GpadlIter *iter)
+{
+    if (iter->map) {
+        uint32_t map_pgoff = (uintptr_t)iter->map & ~TARGET_PAGE_MASK;
+        uint32_t off_pgoff = iter->off & ~TARGET_PAGE_MASK;
+        assert(map_pgoff <= off_pgoff);
+        dma_memory_unmap(iter->as, iter->map, TARGET_PAGE_SIZE - map_pgoff,
+                         iter->dir, off_pgoff - map_pgoff);
+    }
+}
+
+static void gpadl_iter_set(GpadlIter *iter, uint32_t new_off)
+{
+    if (iter->map) {
+        uint32_t map_pgoff = (uintptr_t)iter->map & ~TARGET_PAGE_MASK;
+        uint32_t off_pgoff = iter->off & ~TARGET_PAGE_MASK;
+        if ((iter->off & TARGET_PAGE_MASK) != (new_off & TARGET_PAGE_MASK) ||
+            (new_off & ~TARGET_PAGE_MASK) < map_pgoff) {
+            dma_memory_unmap(iter->as, iter->map, TARGET_PAGE_SIZE - map_pgoff,
+                             iter->dir, off_pgoff - map_pgoff);
+            iter->map = NULL;
+        }
+    }
+    iter->off = new_off;
+}
+
+ssize_t vmbus_iov_to_gpadl(VMBusChannel *chan, VMBusGpadl *gpadl, uint32_t off,
+                           const struct iovec *iov, size_t iov_cnt)
+{
+    GpadlIter iter;
+    size_t i;
+    ssize_t ret = 0;
+
+    gpadl_iter_init(&iter, gpadl, chan->dev->dma_as,
+                    DMA_DIRECTION_FROM_DEVICE, off);
+    for (i = 0; i < iov_cnt; i++) {
+        ret = gpadl_iter_rw(&iter, iov[i].iov_base, iov[i].iov_len);
+        if (ret < 0) {
+            goto out;
+        }
+    }
+out:
+    gpadl_iter_done(&iter);
+    return ret;
+}
+
+int vmbus_map_sgl(QEMUSGList *sgl, DMADirection dir, struct iovec *iov,
+                  unsigned iov_cnt, size_t len, size_t off)
+{
+    int ret_cnt = 0, ret;
+    unsigned i;
+    ScatterGatherEntry *sg = sgl->sg;
+
+    for (i = 0; i < sgl->nsg; i++) {
+        if (sg[i].len > off) {
+            break;
+        }
+        off -= sg[i].len;
+    }
+    for (; len && i < sgl->nsg; i++) {
+        dma_addr_t mlen = MIN(sg[i].len - off, len);
+        dma_addr_t addr = sg[i].base + off;
+        len -= mlen;
+        off = 0;
+
+        for (; mlen; ret_cnt++) {
+            dma_addr_t l = mlen;
+            dma_addr_t a = addr;
+
+            if (ret_cnt == iov_cnt) {
+                ret = -ENOBUFS;
+                goto err;
+            }
+
+            iov[ret_cnt].iov_base = dma_memory_map(sgl->as, a, &l, dir);
+            if (!l) {
+                ret = -EFAULT;
+                goto err;
+            }
+            iov[ret_cnt].iov_len = l;
+            addr += l;
+            mlen -= l;
+        }
+    }
+
+    return ret_cnt;
+err:
+    vmbus_unmap_sgl(sgl, dir, iov, ret_cnt, 0);
+    return ret;
+}
+
+void vmbus_unmap_sgl(QEMUSGList *sgl, DMADirection dir, struct iovec *iov,
+                     unsigned iov_cnt, size_t accessed)
+{
+    unsigned i;
+
+    for (i = 0; i < iov_cnt; i++) {
+        size_t acsd = MIN(accessed, iov[i].iov_len);
+        dma_memory_unmap(sgl->as, iov[i].iov_base, iov[i].iov_len, dir, acsd);
+        accessed -= acsd;
+    }
+}
+
+static int gpadl_pre_load(void *opaque)
+{
+    memset(opaque, 0, sizeof(VMBusGpadl));
+    return 0;
+}
+
+static const VMStateDescription vmstate_gpadl = {
+    .name = "vmbus/gpadl",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .pre_load = gpadl_pre_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(id, VMBusGpadl),
+        VMSTATE_UINT32(child_relid, VMBusGpadl),
+        VMSTATE_UINT32(num_gfns, VMBusGpadl),
+        VMSTATE_UINT32(seen_gfns, VMBusGpadl),
+        VMSTATE_VARRAY_UINT32_ALLOC(gfns, VMBusGpadl, num_gfns, 0,
+                                    vmstate_info_uint64, uint64_t),
+        VMSTATE_BOOL(alive, VMBusGpadl),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static vmbus_ring_buffer *ringbuf_map(const VMBusRingBuf *ringbuf)
+{
+    vmbus_ring_buffer *rb;
+    dma_addr_t mlen = sizeof(*rb);
+
+    rb = dma_memory_map(ringbuf->as, ringbuf->rb_addr, &mlen,
+                        DMA_DIRECTION_FROM_DEVICE);
+    if (mlen != sizeof(*rb)) {
+        dma_memory_unmap(ringbuf->as, rb, mlen, DMA_DIRECTION_FROM_DEVICE, 0);
+        return NULL;
+    }
+    return rb;
+}
+
+static void ringbuf_unmap(const VMBusRingBuf *ringbuf, vmbus_ring_buffer *rb,
+                          bool dirty)
+{
+    dma_memory_unmap(ringbuf->as, rb, sizeof(*rb), 1, dirty ? sizeof(*rb) : 0);
+}
+
+static int ringbuf_init(VMBusRingBuf *ringbuf, VMBusChannel *chan,
+                        DMADirection dir)
+{
+    int ret = 0;
+    int off_pg, len_pg;
+    vmbus_ring_buffer *rb;
+    VMBusGpadl *gpadl = chan->gpadl;
+
+    if (dir == DMA_DIRECTION_FROM_DEVICE) {
+        off_pg = chan->rb_rcv_offset;
+        len_pg = gpadl->num_gfns - chan->rb_rcv_offset;
+    } else {
+        off_pg = 0;
+        len_pg = chan->rb_rcv_offset;
+    }
+
+    if (len_pg < 1) {
+        return -EINVAL;
+    }
+
+    ringbuf->gpadl = gpadl;
+    ringbuf->as = chan->dev->dma_as;
+    ringbuf->dir = dir;
+    ringbuf->rb_addr = gpadl->gfns[off_pg] << TARGET_PAGE_BITS;
+    ringbuf->base = (off_pg + 1) << TARGET_PAGE_BITS;
+    ringbuf->len = (len_pg - 1) << TARGET_PAGE_BITS;
+
+    rb = ringbuf_map(ringbuf);
+    if (!rb) {
+        return -EFAULT;
+    }
+
+    if (dir == DMA_DIRECTION_FROM_DEVICE) {
+        ringbuf->my_idx = rb->write_index;
+        rb->feature_bits |= VMBUS_RING_BUFFER_FEAT_PENDING_SZ;
+        ringbuf->pending_sz = rb->pending_send_sz;
+    } else {
+        ringbuf->my_idx = rb->read_index;
+    }
+    if (ringbuf->my_idx >= ringbuf->len) {
+        error_report("%s: inconsistent ring buffer: idx:%u len:%u", __func__,
+                     ringbuf->my_idx, ringbuf->len);
+        ret = -EIO;
+        goto out;
+    }
+
+out:
+    ringbuf_unmap(ringbuf, rb, true);
+    return ret;
+}
+
+typedef struct VMBusRingIter {
+    VMBusRingBuf *ringbuf;
+    vmbus_ring_buffer *rb;
+    GpadlIter gpiter;
+} VMBusRingIter;
+
+static int ring_iter_init(VMBusRingIter *iter, VMBusRingBuf *ringbuf)
+{
+    iter->ringbuf = ringbuf;
+    gpadl_iter_init(&iter->gpiter, ringbuf->gpadl, ringbuf->as, ringbuf->dir,
+                    ringbuf->base + ringbuf->my_idx);
+    iter->rb = ringbuf_map(ringbuf);
+    return iter->rb ? 0 : -EFAULT;
+}
+
+static uint32_t rb_avail(uint32_t my_idx, uint32_t other_idx, uint32_t len,
+                         bool is_write)
+{
+    uint32_t ret = other_idx + len - my_idx - is_write;
+    if (ret >= len) {
+        ret -= len;
+    }
+    return ret;
+}
+
+static bool ring_iter_rcv_update_idx(VMBusRingIter *iter)
+{
+    VMBusRingBuf *ringbuf = iter->ringbuf;
+    vmbus_ring_buffer *rb = iter->rb;
+    uint32_t old_idx = ringbuf->my_idx;
+
+    assert(ringbuf->dir == DMA_DIRECTION_TO_DEVICE);
+
+    ringbuf->my_idx = iter->gpiter.off - ringbuf->base;
+
+    /*
+     * make sure the data operation is finished before we update the index;
+     * pairs with (the guest-side equivalent of) the final smp_mb() in
+     * ringbuf_snd_request_room()
+     */
+    smp_mb();
+
+    rb->read_index = ringbuf->my_idx;
+    smp_mb();
+
+    if (rb->interrupt_mask) {
+        return false;
+    }
+
+    if (rb->feature_bits & VMBUS_RING_BUFFER_FEAT_PENDING_SZ) {
+        uint32_t other_idx;
+        uint32_t wanted = rb->pending_send_sz;
+
+        /* barrier-less shortcut */
+        if (!wanted) {
+            return false;
+        }
+
+        /* pairs with smp_mb() in ringbuf_snd_request_room() */
+        smp_rmb();
+        other_idx = rb->write_index;
+
+        /* other (write) side wasn't blocked on our (read) state */
+        if (rb_avail(other_idx, old_idx, ringbuf->len, true) >= wanted) {
+            return false;
+        }
+        /* there's not enough space for the other (write) side */
+        if (rb_avail(other_idx, ringbuf->my_idx, ringbuf->len, true) <
+            wanted) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool ring_iter_snd_update_idx(VMBusRingIter *iter)
+{
+    VMBusRingBuf *ringbuf = iter->ringbuf;
+    vmbus_ring_buffer *rb = iter->rb;
+    uint32_t old_idx = ringbuf->my_idx;
+    uint32_t wlen;
+
+    assert(ringbuf->dir == DMA_DIRECTION_FROM_DEVICE);
+
+    ringbuf->my_idx = iter->gpiter.off - ringbuf->base;
+    wlen = rb_avail(old_idx, ringbuf->my_idx, ringbuf->len, false);
+
+    if (ringbuf->pending_sz) {
+        /* we didn't have enough room at ringbuf_snd_request_room() */
+        assert(wlen < ringbuf->pending_sz);
+        /* successful send reduces our needs; inform the other side */
+        ringbuf->pending_sz -= wlen;
+        rb->pending_send_sz = ringbuf->pending_sz;
+    }
+
+    /*
+     * make sure the data operation is finished before we update the index;
+     * pairs with (the guest-side equivalent of) the barrier in
+     * ring_iter_avail()
+     */
+    smp_mb();
+
+    rb->write_index = ringbuf->my_idx;
+    smp_mb();
+
+    if (rb->interrupt_mask) {
+        return false;
+    }
+
+    /*
+     * other (read) side hasn't caught up with our (write) previous state
+     * so it's not blocked
+     */
+    if (rb_avail(rb->read_index, ringbuf->my_idx, ringbuf->len, false) >
+        wlen) {
+        return false;
+    }
+    return true;
+}
+
+static void ring_iter_done(VMBusRingIter *iter, bool dirty)
+{
+    gpadl_iter_done(&iter->gpiter);
+    ringbuf_unmap(iter->ringbuf, iter->rb, dirty);
+}
+
+static uint32_t ring_iter_rcv_avail(VMBusRingIter *iter)
+{
+    uint32_t other_idx;
+    assert(iter->gpiter.dir == DMA_DIRECTION_TO_DEVICE);
+
+    other_idx = iter->rb->write_index;
+    /*
+     * pairs with (the guest-side equivalent of) the barrier at the
+     * beginning of ring_iter_snd_update_idx()
+     */
+    smp_mb();
+
+    return rb_avail(iter->gpiter.off - iter->ringbuf->base, other_idx,
+                    iter->ringbuf->len, false);
+}
+
+static int ring_iter_rw(VMBusRingIter *iter, void *buf, uint32_t len)
+{
+    int ret1 = 0, ret2 = 0;
+    uint32_t remain = iter->ringbuf->len + iter->ringbuf->base -
+        iter->gpiter.off;
+
+    if (len >= remain) {
+        ret1 = gpadl_iter_rw(&iter->gpiter, buf, remain);
+        if (ret1 < 0) {
+            return ret1;
+        }
+        assert(!iter->gpiter.map);
+        gpadl_iter_set(&iter->gpiter, iter->ringbuf->base);
+        buf += remain;
+        len -= remain;
+    }
+    ret2 = gpadl_iter_rw(&iter->gpiter, buf, len);
+    if (ret2 < 0) {
+        return ret2;
+    }
+    return ret1 + ret2;
+}
+
+static void ring_iter_set(VMBusRingIter *iter, uint32_t new_off)
+{
+    new_off += iter->ringbuf->my_idx;
+    if (new_off >= iter->ringbuf->len) {
+        new_off -= iter->ringbuf->len;
+    }
+    gpadl_iter_set(&iter->gpiter, iter->ringbuf->base + new_off);
+}
+
+static int ringbuf_snd_request_room(VMBusRingBuf *ringbuf, uint32_t needed)
+{
+    uint32_t avail;
+    bool dirty = false;
+    vmbus_ring_buffer *rb;
+
+    assert(ringbuf->dir == DMA_DIRECTION_FROM_DEVICE);
+
+    rb = ringbuf_map(ringbuf);
+    if (!rb) {
+        return -EFAULT;
+    }
+
+    avail = rb_avail(ringbuf->my_idx, rb->read_index, ringbuf->len, true);
+
+    if (needed <= avail) {
+        needed = 0;
+    }
+
+    if (needed != ringbuf->pending_sz) {
+        ringbuf->pending_sz = needed;
+        /* pairs with smp_rmb() in ring_iter_rcv_update_idx() */
+        smp_mb();
+        rb->pending_send_sz = needed;
+        dirty = true;
+    }
+    /*
+     * pairs with (the guest-side equivalent of) smp_mb() at the
+     * beginning of ring_iter_rcv_update_idx()
+     */
+    smp_mb();
+
+    ringbuf_unmap(ringbuf, rb, dirty);
+    return needed ? -ENOSPC : 0;
+}
+
+
+VMBusDevice *vmbus_channel_device(VMBusChannel *chan)
+{
+    return chan->dev;
+}
+
+VMBusChannel *vmbus_device_channel(VMBusDevice *dev, uint32_t chan_idx)
+{
+    if (chan_idx >= dev->num_channels) {
+        return NULL;
+    }
+    return &dev->channels[chan_idx];
+}
+
+uint32_t vmbus_channel_idx(VMBusChannel *chan)
+{
+    return chan - chan->dev->channels;
+}
+
+void vmbus_notify_channel(VMBusChannel *chan)
+{
+    event_notifier_set(&chan->notifier);
+}
+
+static bool channel_broken(VMBusChannel *chan)
+{
+    return !chan->gpadl;
+}
+
+static int signal_channel(VMBusChannel *chan)
+{
+    int res = 0;
+    unsigned long *int_map, mask;
+    unsigned idx;
+    hwaddr addr = chan->vmbus->int_page_gpa;
+    hwaddr len = TARGET_PAGE_SIZE / 2, dirty = 0;
+
+    trace_vmbus_signal_channel(chan->relid);
+
+    if (!addr) {
+        return hyperv_set_event_flag(chan->notify_route, chan->relid);
+    }
+
+    int_map = cpu_physical_memory_map(addr, &len, 1);
+    if (len != TARGET_PAGE_SIZE / 2) {
+        res = -ENXIO;
+        goto unmap;
+    }
+
+    idx = BIT_WORD(chan->relid);
+    mask = BIT_MASK(chan->relid);
+    if ((atomic_fetch_or(&int_map[idx], mask) & mask) != mask) {
+        res = hyperv_sint_route_set_sint(chan->notify_route);
+        dirty = len;
+    }
+
+unmap:
+    cpu_physical_memory_unmap(int_map, len, 1, dirty);
+    return res;
+}
+
+int vmbus_channel_send(VMBusChannel *chan, uint16_t pkt_type,
+                       void *desc, uint32_t desclen,
+                       void *msg, uint32_t msglen,
+                       bool need_comp, uint64_t transaction_id)
+{
+    int ret = 0;
+    vmbus_packet_hdr hdr;
+    uint32_t totlen;
+    VMBusRingIter iter;
+
+    if (chan->state != VMCHAN_OPEN) {
+        return -EINVAL;
+    }
+
+    ret = ring_iter_init(&iter, &chan->ringbuf_snd);
+    if (ret) {
+        return ret;
+    }
+
+    hdr.type = pkt_type;
+    hdr.offset_qwords = sizeof(hdr) / sizeof(uint64_t) +
+        DIV_ROUND_UP(desclen, sizeof(uint64_t));
+    hdr.len_qwords = hdr.offset_qwords +
+        DIV_ROUND_UP(msglen, sizeof(uint64_t));
+    hdr.flags = need_comp ? VMBUS_PACKET_FLAG_REQUEST_COMPLETION : 0;
+    hdr.transaction_id = transaction_id;
+    totlen = (hdr.len_qwords + 1) * sizeof(uint64_t);
+
+    assert(totlen <= chan->snd_reserved);
+
+    ret = ring_iter_rw(&iter, &hdr, sizeof(hdr));
+    if (ret < 0) {
+        goto out;
+    }
+    if (desclen) {
+        assert(desc);
+        ret = ring_iter_rw(&iter, desc, desclen);
+        if (ret < 0) {
+            goto out;
+        }
+        ring_iter_set(&iter, hdr.offset_qwords * sizeof(uint64_t));
+    }
+    ret = ring_iter_rw(&iter, msg, msglen);
+    if (ret < 0) {
+        goto out;
+    }
+    ring_iter_set(&iter, totlen);
+
+    if (ring_iter_snd_update_idx(&iter)) {
+        signal_channel(chan);
+    }
+    chan->snd_reserved -= totlen;
+out:
+    ring_iter_done(&iter, ret >= 0);
+    return ret;
+}
+
+int vmbus_chan_send_completion(VMBusChanReq *req)
+{
+    assert(req->comp);
+    return vmbus_channel_send(req->chan, VMBUS_PACKET_COMP, NULL, 0, req->comp,
+                              req->msglen, false, req->transaction_id);
+}
+
+int vmbus_channel_reserve(VMBusChannel *chan,
+                          uint32_t desclen, uint32_t msglen)
+{
+    uint32_t needed = chan->snd_reserved +
+        sizeof(vmbus_packet_hdr) +
+        ROUND_UP(desclen, sizeof(uint64_t)) +
+        ROUND_UP(msglen, sizeof(uint64_t)) +
+        sizeof(uint64_t);
+
+    int ret = ringbuf_snd_request_room(&chan->ringbuf_snd, needed);
+
+    if (!ret) {
+        chan->snd_reserved = needed;
+    }
+    return ret;
+}
+
+static int sgl_from_gpa_ranges(VMBusRingIter *iter, uint32_t len,
+                               VMBusChanReq *req)
+{
+    int ret;
+    vmbus_pkt_gpa_direct hdr;
+    hwaddr curaddr = 0;
+    hwaddr curlen = 0;
+    int num;
+
+    if (len < sizeof(hdr)) {
+        return -EIO;
+    }
+    ret = ring_iter_rw(iter, &hdr, sizeof(hdr));
+    if (ret < 0) {
+        return ret;
+    }
+    len -= sizeof(hdr);
+
+    num = (len - hdr.rangecount * sizeof(vmbus_gpa_range)) / sizeof(uint64_t);
+    if (num < 0) {
+        return -EIO;
+    }
+    qemu_sglist_init(&req->sgl, DEVICE(req->chan->dev), num, iter->gpiter.as);
+
+    for (; hdr.rangecount; hdr.rangecount--) {
+        vmbus_gpa_range range;
+
+        if (len < sizeof(range)) {
+            goto eio;
+        }
+        ret = ring_iter_rw(iter, &range, sizeof(range));
+        if (ret < 0) {
+            goto err;
+        }
+        len -= sizeof(range);
+
+        if (range.byte_offset & TARGET_PAGE_MASK) {
+            goto eio;
+        }
+
+        for (; range.byte_count; range.byte_offset = 0) {
+            uint64_t paddr;
+            uint32_t plen = MIN(range.byte_count,
+                                TARGET_PAGE_SIZE - range.byte_offset);
+
+            if (len < sizeof(uint64_t)) {
+                goto eio;
+            }
+            ret = ring_iter_rw(iter, &paddr, sizeof(paddr));
+            if (ret < 0) {
+                goto err;
+            }
+            len -= sizeof(uint64_t);
+            paddr <<= TARGET_PAGE_BITS;
+            paddr |= range.byte_offset;
+            range.byte_count -= plen;
+
+            if (curaddr + curlen == paddr) {
+                /* consecutive fragments - join */
+                curlen += plen;
+            } else {
+                if (curlen) {
+                    qemu_sglist_add(&req->sgl, curaddr, curlen);
+                }
+
+                curaddr = paddr;
+                curlen = plen;
+            }
+        }
+    }
+
+    if (curlen) {
+        qemu_sglist_add(&req->sgl, curaddr, curlen);
+    }
+
+    return 0;
+eio:
+    ret = -EIO;
+err:
+    qemu_sglist_destroy(&req->sgl);
+    return ret;
+}
+
+static VMBusChanReq *vmbus_alloc_req(VMBusChannel *chan,
+                                     uint32_t size, uint16_t pkt_type,
+                                     uint32_t msglen, uint64_t transaction_id,
+                                     bool with_comp)
+{
+    VMBusChanReq *req;
+    uint32_t msgoff = QEMU_ALIGN_UP(size, __alignof__(*req->msg));
+    uint32_t compoff = QEMU_ALIGN_UP(msgoff + msglen, __alignof__(*req->comp));
+    uint32_t complen = with_comp ? msglen : 0;
+    uint32_t totlen = compoff + complen;
+
+    req = g_malloc0(totlen);
+    req->chan = chan;
+    req->pkt_type = pkt_type;
+    req->msg = (void *)req + msgoff;
+    req->msglen = msglen;
+    req->transaction_id = transaction_id;
+    req->comp = with_comp ? ((void *)req + compoff) : NULL;
+    return req;
+}
+
+void *vmbus_channel_recv(VMBusChannel *chan, uint32_t size)
+{
+    VMBusRingIter iter;
+    vmbus_packet_hdr hdr = {0};
+    VMBusChanReq *req = NULL;
+    uint32_t avail;
+    uint32_t pktlen, msglen, msgoff, desclen;
+    bool with_comp;
+
+    assert(size >= sizeof(*req));
+
+    if (chan->state != VMCHAN_OPEN) {
+        return NULL;
+    }
+
+    if (ring_iter_init(&iter, &chan->ringbuf_rcv)) {
+        return NULL;
+    }
+
+    avail = ring_iter_rcv_avail(&iter);
+    if (avail < sizeof(hdr)) {
+        goto err;
+    }
+
+    if (ring_iter_rw(&iter, &hdr, sizeof(hdr)) < 0) {
+        goto err;
+    }
+
+    pktlen = hdr.len_qwords * sizeof(uint64_t);
+    if (pktlen + sizeof(uint64_t) > avail) {
+        goto err;
+    }
+
+    msgoff = hdr.offset_qwords * sizeof(uint64_t);
+    if (msgoff > pktlen || msgoff < sizeof(hdr)) {
+        error_report("%s: malformed packet: %u %u", __func__, msgoff, pktlen);
+        goto err;
+    }
+
+    msglen = pktlen - msgoff;
+
+    with_comp = hdr.flags & VMBUS_PACKET_FLAG_REQUEST_COMPLETION;
+    if (with_comp && vmbus_channel_reserve(chan, 0, msglen)) {
+        goto err;
+    }
+
+    req = vmbus_alloc_req(chan, size, hdr.type, msglen, hdr.transaction_id,
+                          with_comp);
+
+    switch (hdr.type) {
+    case VMBUS_PACKET_DATA_USING_GPA_DIRECT:
+        desclen = msgoff - sizeof(hdr);
+        if (sgl_from_gpa_ranges(&iter, desclen, req) < 0) {
+            error_report("%s: failed to convert GPA ranges to SGL", __func__);
+            goto err;
+        }
+        break;
+    case VMBUS_PACKET_DATA_INBAND:
+    case VMBUS_PACKET_COMP:
+        break;
+    default:
+        error_report("%s: unexpected msg type: %x", __func__, hdr.type);
+        goto err;
+    }
+
+    ring_iter_set(&iter, msgoff);
+    if (ring_iter_rw(&iter, req->msg, msglen) < 0) {
+        goto err;
+    }
+    ring_iter_set(&iter, pktlen + sizeof(uint64_t));
+
+    if (ring_iter_rcv_update_idx(&iter)) {
+        signal_channel(chan);
+    }
+    ring_iter_done(&iter, true);
+    return req;
+err:
+    vmbus_release_req(req);
+    ring_iter_done(&iter, false);
+    return NULL;
+}
+
+void vmbus_release_req(void *req)
+{
+    VMBusChanReq *r = req;
+
+    if (!req) {
+        return;
+    }
+
+    if (r->sgl.dev) {
+        qemu_sglist_destroy(&r->sgl);
+    }
+    g_free(req);
+}
+
+static const VMStateDescription vmstate_sgent = {
+    .name = "vmbus/sgentry",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT64(base, ScatterGatherEntry),
+        VMSTATE_UINT64(len, ScatterGatherEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+typedef struct VMBusChanReqSave {
+    uint16_t chan_idx;
+    uint16_t pkt_type;
+    uint32_t msglen;
+    void *msg;
+    uint64_t transaction_id;
+    bool with_comp;
+    uint32_t num;
+    ScatterGatherEntry *sgl;
+} VMBusChanReqSave;
+
+static const VMStateDescription vmstate_vmbus_chan_req = {
+    .name = "vmbus/vmbus_chan_req",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT16(chan_idx, VMBusChanReqSave),
+        VMSTATE_UINT16(pkt_type, VMBusChanReqSave),
+        VMSTATE_UINT32(msglen, VMBusChanReqSave),
+        VMSTATE_VBUFFER_ALLOC_UINT32(msg, VMBusChanReqSave, 0, NULL, msglen),
+        VMSTATE_UINT64(transaction_id, VMBusChanReqSave),
+        VMSTATE_BOOL(with_comp, VMBusChanReqSave),
+        VMSTATE_UINT32(num, VMBusChanReqSave),
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(sgl, VMBusChanReqSave, num,
+                                             vmstate_sgent, ScatterGatherEntry),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void vmbus_save_req(QEMUFile *f, VMBusChanReq *req)
+{
+    VMBusChanReqSave req_save;
+
+    req_save.chan_idx = req->chan->subchan_idx;
+    req_save.pkt_type = req->pkt_type;
+    req_save.msglen = req->msglen;
+    req_save.msg = req->msg;
+    req_save.transaction_id = req->transaction_id;
+    req_save.with_comp = !!req->comp;
+    req_save.num = req->sgl.nsg;
+    req_save.sgl = g_memdup(req->sgl.sg,
+                            req_save.num * sizeof(ScatterGatherEntry));
+
+    vmstate_save_state(f, &vmstate_vmbus_chan_req, &req_save, NULL);
+
+    g_free(req_save.sgl);
+}
+
+void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size)
+{
+    VMBusChanReqSave req_save;
+    VMBusChanReq *req = NULL;
+    VMBusChannel *chan = NULL;
+    uint32_t i;
+
+    vmstate_load_state(f, &vmstate_vmbus_chan_req, &req_save, 0);
+
+    if (req_save.chan_idx >= dev->num_channels) {
+        error_report("%s: %u(chan_idx) > %u(num_channels)", __func__,
+                     req_save.chan_idx, dev->num_channels);
+        goto out;
+    }
+    chan = &dev->channels[req_save.chan_idx];
+
+    if (vmbus_channel_reserve(chan, 0, req_save.msglen)) {
+        goto out;
+    }
+
+    req = vmbus_alloc_req(chan, size, req_save.pkt_type, req_save.msglen,
+                          req_save.transaction_id, req_save.with_comp);
+    if (req_save.msglen) {
+        memcpy(req->msg, req_save.msg, req_save.msglen);
+    }
+
+    for (i = 0; i < req_save.num; i++) {
+        qemu_sglist_add(&req->sgl, req_save.sgl[i].base, req_save.sgl[i].len);
+    }
+
+out:
+    if (req_save.msglen) {
+        g_free(req_save.msg);
+    }
+    if (req_save.num) {
+        g_free(req_save.sgl);
+    }
+    return req;
+}
+
+static void channel_event_cb(EventNotifier *e)
+{
+    VMBusChannel *chan = container_of(e, VMBusChannel, notifier);
+    if (event_notifier_test_and_clear(e)) {
+        chan->notify_cb(chan);
+    }
+}
+
+static int register_chan_ids(VMBusChannel *chan)
+{
+    int ret;
+
+    ret = hyperv_set_event_flag_handler(chan->connid, &chan->notifier);
+    if (ret) {
+        return ret;
+    }
+
+    set_bit(chan->relid, chan->vmbus->chan_relid_bitmap);
+    set_bit(chan->connid, chan->vmbus->connection_id_bitmap);
+    return 0;
+}
+
+static void unregister_chan_ids(VMBusChannel *chan)
+{
+    clear_bit(chan->connid, chan->vmbus->connection_id_bitmap);
+    clear_bit(chan->relid, chan->vmbus->chan_relid_bitmap);
+    hyperv_set_event_flag_handler(chan->connid, NULL);
+}
+
+static void init_channel(VMBus *vmbus, VMBusDevice *dev, VMBusDeviceClass *vdc,
+                         VMBusChannel *chan, uint16_t idx, Error **errp)
+{
+    int res;
+
+    chan->dev = dev;
+    chan->notify_cb = vdc->chan_notify_cb;
+    chan->subchan_idx = idx;
+    chan->vmbus = vmbus;
+
+    chan->relid = find_next_zero_bit(vmbus->chan_relid_bitmap,
+                                     VMBUS_CHAN_RELID_COUNT,
+                                     VMBUS_CHAN_FIRST_RELID);
+    if (chan->relid == VMBUS_CHAN_RELID_COUNT) {
+        error_setg(errp, "no spare relid");
+        return;
+    }
+
+    chan->connid = find_next_zero_bit(vmbus->connection_id_bitmap,
+                                      VMBUS_CHAN_CONNID_COUNT,
+                                      VMBUS_CHAN_FIRST_CONNID);
+    if (chan->connid == VMBUS_CHAN_CONNID_COUNT) {
+        error_setg(errp, "no spare connid");
+        return;
+    }
+
+    res = event_notifier_init(&chan->notifier, 0);
+    if (res) {
+        error_setg(errp, "event_notifier_init: %d", res);
+        return;
+    }
+
+    event_notifier_set_handler(&chan->notifier, channel_event_cb);
+
+    res = register_chan_ids(chan);
+    if (res) {
+        error_setg(errp, "register_chan_ids: %d", res);
+        event_notifier_cleanup(&chan->notifier);
+        return;
+    }
+}
+
+static void deinit_channel(VMBusChannel *chan)
+{
+    assert(chan->state == VMCHAN_INIT);
+    QTAILQ_REMOVE(&chan->vmbus->channel_list, chan, link);
+    unregister_chan_ids(chan);
+    event_notifier_cleanup(&chan->notifier);
+}
+
+static void create_channels(VMBus *vmbus, VMBusDevice *dev, Error **errp)
+{
+    uint16_t i;
+    VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(dev);
+    Error *err = NULL;
+
+    dev->num_channels = vdc->num_channels ? vdc->num_channels(dev) : 1;
+    if (dev->num_channels < 1) {
+        error_setg(&err, "invalid #channels: %u", dev->num_channels);
+        goto error_out;
+    }
+
+    dev->channels = g_new0(VMBusChannel, dev->num_channels);
+    for (i = 0; i < dev->num_channels; i++) {
+        init_channel(vmbus, dev, vdc, &dev->channels[i], i, &err);
+        if (err) {
+            goto err_init;
+        }
+
+        /*
+         * The guest drivers depend on the device subchannels (channels #1+) to
+         * be offered after the main channel (channel #0) of that device.  To
+         * ensure that, record the channels on the channel list in the order
+         * they appear within the device.
+         */
+        QTAILQ_INSERT_TAIL(&vmbus->channel_list, &dev->channels[i], link);
+    }
+
+    return;
+
+err_init:
+    while (i--) {
+        deinit_channel(&dev->channels[i]);
+    }
+error_out:
+    error_propagate(errp, err);
+}
+
+static void free_channels(VMBus *vmbus, VMBusDevice *dev)
+{
+    uint16_t i;
+    for (i = 0; i < dev->num_channels; i++) {
+        deinit_channel(&dev->channels[i]);
+    }
+    g_free(dev->channels);
+}
+
+static HvSintRoute *make_sint_route(VMBus *vmbus, uint32_t vp_index)
+{
+    VMBusChannel *chan;
+
+    if (vp_index == vmbus->target_vp) {
+        hyperv_sint_route_ref(vmbus->sint_route);
+        return vmbus->sint_route;
+    }
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->target_vp == vp_index && chan->notify_route) {
+            hyperv_sint_route_ref(chan->notify_route);
+            return chan->notify_route;
+        }
+    }
+
+    return hyperv_sint_route_new(vp_index, VMBUS_SINT, NULL, NULL);
+}
+
+static void open_channel(VMBusChannel *chan)
+{
+    VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(chan->dev);
+
+    chan->gpadl = vmbus_get_gpadl(chan, chan->rb_gpadl);
+    if (!chan->gpadl) {
+        return;
+    }
+
+    if (ringbuf_init(&chan->ringbuf_rcv, chan, DMA_DIRECTION_TO_DEVICE) ||
+        ringbuf_init(&chan->ringbuf_snd, chan, DMA_DIRECTION_FROM_DEVICE)) {
+        goto put_gpadl;
+    }
+
+    chan->notify_route = make_sint_route(chan->vmbus, chan->target_vp);
+    if (!chan->notify_route) {
+        goto put_gpadl;
+    }
+
+    if (vdc->open_channel && vdc->open_channel(chan->dev)) {
+        goto err_vdc_open;
+    }
+
+    return;
+
+err_vdc_open:
+    hyperv_sint_route_unref(chan->notify_route);
+put_gpadl:
+    vmbus_put_gpadl(chan->gpadl);
+    chan->gpadl = NULL;
+}
+
+static void close_channel(VMBusChannel *chan)
+{
+    VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(chan->dev);
+
+    if (chan->state != VMCHAN_OPEN) {
+        return;
+    }
+
+    if (vdc->close_channel) {
+        vdc->close_channel(chan->dev);
+    }
+
+    vmbus_put_gpadl(chan->gpadl);
+    chan->gpadl = NULL;
+    chan->state = VMCHAN_INIT;
+    chan->snd_reserved = 0;
+    hyperv_sint_route_unref(chan->notify_route);
+    chan->notify_route = NULL;
+}
+
+static int channel_post_load(void *opaque, int version_id)
+{
+    VMBusChannel *chan = opaque;
+
+    if (chan->state == VMCHAN_OPENING || chan->state == VMCHAN_OPEN) {
+        open_channel(chan);
+    }
+
+    /*
+     * if the channel was still transitioning we'll report failure via reply
+     * message, no need to error out now
+     */
+    if (chan->state == VMCHAN_OPEN && channel_broken(chan)) {
+        chan->state = VMCHAN_INIT;
+        return -1;
+    }
+
+    if (chan->state == VMCHAN_OPEN) {
+        /* resume processing on the guest side if it missed the notification */
+        hyperv_sint_route_set_sint(chan->notify_route);
+    }
+    return 0;
+}
+
+static const VMStateDescription vmstate_channel = {
+    .name = "vmbus/channel",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .post_load = channel_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(relid, VMBusChannel),
+        VMSTATE_UINT16(subchan_idx, VMBusChannel),
+        VMSTATE_UINT32(connid, VMBusChannel),
+        VMSTATE_UINT32(open_id, VMBusChannel),
+        VMSTATE_UINT32(target_vp, VMBusChannel),
+        VMSTATE_UINT32(rb_gpadl, VMBusChannel),
+        VMSTATE_UINT32(rb_rcv_offset, VMBusChannel),
+        VMSTATE_UINT32(offer_state, VMBusChannel),
+        VMSTATE_UINT32(state, VMBusChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static VMBusChannel *find_channel(VMBus *vmbus, uint32_t relid)
+{
+    VMBusChannel *chan;
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->relid == relid) {
+            return chan;
+        }
+    }
+    return NULL;
+}
+
+static int enqueue_incoming_message(VMBus *vmbus,
+                                    const struct hyperv_post_message_input *msg)
+{
+    uint8_t idx, prev_size;
+
+    qemu_mutex_lock(&vmbus->rx_queue_lock);
+
+    if (vmbus->rx_queue_size == VMBUS_RX_QUEUE_CAPACITY) {
+        qemu_mutex_unlock(&vmbus->rx_queue_lock);
+        return -ENOBUFS;
+    }
+
+    prev_size = vmbus->rx_queue_size;
+    idx = (vmbus->rx_queue_head + vmbus->rx_queue_size) %
+        VMBUS_RX_QUEUE_CAPACITY;
+    memcpy(&vmbus->rx_queue[idx], msg, sizeof(*msg));
+    vmbus->rx_queue_size++;
+
+    qemu_mutex_unlock(&vmbus->rx_queue_lock);
+
+    /* only need to resched if the queue was empty before */
+    if (!prev_size) {
+        vmbus_resched(vmbus);
+    }
+
+    return 0;
+}
+
+static uint16_t vmbus_recv_message(const struct hyperv_post_message_input *msg,
+                                   void *data)
+{
+    VMBus *vmbus = data;
+    struct vmbus_message_header *vmbus_msg;
+
+    if (msg->message_type != HV_MESSAGE_VMBUS) {
+        return HV_STATUS_INVALID_HYPERCALL_INPUT;
+    }
+
+    if (msg->payload_size < sizeof(struct vmbus_message_header)) {
+        return HV_STATUS_INVALID_HYPERCALL_INPUT;
+    }
+
+    vmbus_msg = (struct vmbus_message_header*)msg->payload;
+
+    trace_vmbus_recv_message(vmbus_msg->message_type, msg->payload_size);
+
+    if (vmbus_msg->message_type == VMBUS_MSG_INVALID ||
+        vmbus_msg->message_type >= VMBUS_MSG_COUNT) {
+        error_report("vmbus: unknown message type %#x",
+                     vmbus_msg->message_type);
+        return HV_STATUS_INVALID_HYPERCALL_INPUT;
+    }
+
+    if (enqueue_incoming_message(vmbus, msg)) {
+        return HV_STATUS_INSUFFICIENT_BUFFERS;
+    }
+    return HV_STATUS_SUCCESS;
+}
+
+static bool vmbus_initialized(VMBus *vmbus)
+{
+    return vmbus->version > 0 && vmbus->version <= VMBUS_VERSION_CURRENT;
+}
+
+static void vmbus_reset_all(VMBus *vmbus)
+{
+    qbus_reset_all(BUS(vmbus));
+}
+
+static void post_msg(VMBus *vmbus, void *msgdata, uint32_t msglen)
+{
+    int ret;
+    struct hyperv_message msg = {
+        .header.message_type = HV_MESSAGE_VMBUS,
+    };
+
+    assert(!vmbus->msg_in_progress);
+    assert(msglen <= sizeof(msg.payload));
+    assert(msglen >= sizeof(struct vmbus_message_header));
+
+    vmbus->msg_in_progress = true;
+
+    trace_vmbus_post_msg(((struct vmbus_message_header *)msgdata)->message_type,
+                         msglen);
+
+    memcpy(msg.payload, msgdata, msglen);
+    msg.header.payload_size = ROUND_UP(msglen, VMBUS_MESSAGE_SIZE_ALIGN);
+
+    ret = hyperv_post_msg(vmbus->sint_route, &msg);
+    if (ret == 0 || ret == -EAGAIN) {
+        return;
+    }
+
+    error_report("message delivery fatal failure: %d; aborting vmbus", ret);
+    vmbus_reset_all(vmbus);
+}
+
+static int vmbus_init(VMBus *vmbus)
+{
+    if (vmbus->target_vp != (uint32_t)-1) {
+        vmbus->sint_route = hyperv_sint_route_new(vmbus->target_vp, VMBUS_SINT,
+                                                  vmbus_msg_cb, vmbus);
+        if (!vmbus->sint_route) {
+            error_report("failed to set up SINT route");
+            return -ENOMEM;
+        }
+    }
+    return 0;
+}
+
+static void vmbus_deinit(VMBus *vmbus)
+{
+    while (!QTAILQ_EMPTY(&vmbus->gpadl_list)) {
+        free_gpadl(vmbus, QTAILQ_FIRST(&vmbus->gpadl_list));
+    }
+
+    hyperv_sint_route_unref(vmbus->sint_route);
+
+    vmbus->sint_route = NULL;
+    vmbus->int_page_gpa = 0;
+    vmbus->target_vp = (uint32_t)-1;
+    vmbus->version = 0;
+    vmbus->state = VMBUS_LISTEN;
+    vmbus->msg_in_progress = false;
+}
+
+static void handle_initiate_contact(VMBus *vmbus,
+                                    vmbus_message_initiate_contact *msg,
+                                    uint32_t msglen)
+{
+    if (msglen < sizeof(*msg)) {
+        return;
+    }
+
+    trace_vmbus_initiate_contact(msg->version_requested, msg->target_vcpu,
+            msg->monitor_page1, msg->monitor_page2, msg->interrupt_page);
+
+    /*
+     * Reset vmbus on INITIATE_CONTACT regardless of its previous state.
+     * Useful, in particular, with vmbus-aware BIOS which can't shut vmbus down
+     * before handing over to OS loader.
+     */
+    vmbus_reset_all(vmbus);
+
+    vmbus->target_vp = msg->target_vcpu;
+    vmbus->version = msg->version_requested;
+    if (vmbus->version < VMBUS_VERSION_WIN8) {
+        /* linux passes interrupt page even when it doesn't need it */
+        vmbus->int_page_gpa = msg->interrupt_page;
+    }
+    vmbus->state = VMBUS_HANDSHAKE;
+
+    if (vmbus_init(vmbus)) {
+        error_report("failed to init vmbus; aborting");
+        vmbus_deinit(vmbus);
+        return;
+    }
+}
+
+static void send_handshake(VMBus *vmbus)
+{
+    struct vmbus_message_version_response msg = {
+        .header.message_type = VMBUS_MSG_VERSION_RESPONSE,
+        .version_supported = vmbus_initialized(vmbus),
+    };
+
+    post_msg(vmbus, &msg, sizeof(msg));
+}
+
+static void complete_handshake(VMBus *vmbus)
+{
+    vmbus->state = VMBUS_LISTEN;
+}
+
+static void handle_request_offers(VMBus *vmbus, void *msgdata, uint32_t msglen)
+{
+    VMBusChannel *chan;
+
+    if (!vmbus_initialized(vmbus)) {
+        return;
+    }
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->offer_state == VMOFFER_INIT) {
+            chan->offer_state = VMOFFER_SENDING;
+            break;
+        }
+    }
+
+    vmbus->state = VMBUS_OFFER;
+}
+
+static void send_offer(VMBus *vmbus)
+{
+    VMBusChannel *chan;
+    struct vmbus_message_header alloffers_msg = {
+        .message_type = VMBUS_MSG_ALLOFFERS_DELIVERED,
+    };
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->offer_state == VMOFFER_SENDING) {
+            VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(chan->dev);
+            QemuUUID classid = vdc->classid;
+            QemuUUID instanceid = chan->dev->instanceid;
+            struct vmbus_message_offer_channel msg = {
+                .header.message_type = VMBUS_MSG_OFFERCHANNEL,
+                .child_relid = chan->relid,
+                .connection_id = chan->connid,
+                .channel_flags = vdc->channel_flags,
+                .mmio_size_mb = vdc->mmio_size_mb,
+                .sub_channel_index = vmbus_channel_idx(chan),
+                .interrupt_flags = VMBUS_OFFER_INTERRUPT_DEDICATED,
+            };
+
+            /* Hyper-V wants LE GUIDs */
+            classid = qemu_uuid_bswap(classid);
+            memcpy(msg.type_uuid, &classid, sizeof(classid));
+            instanceid = qemu_uuid_bswap(instanceid);
+            memcpy(msg.instance_uuid, &instanceid, sizeof(instanceid));
+
+            post_msg(vmbus, &msg, sizeof(msg));
+            return;
+        }
+    }
+
+    /* no more offers, send completion message */
+    post_msg(vmbus, &alloffers_msg, sizeof(alloffers_msg));
+}
+
+static void complete_offer(VMBus *vmbus)
+{
+    VMBusChannel *chan;
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->offer_state == VMOFFER_SENDING) {
+            chan->offer_state = VMOFFER_SENT;
+            chan = QTAILQ_NEXT(chan, link);
+            if (chan) {
+                chan->offer_state = VMOFFER_SENDING;
+            }
+            /* more offers or terminator, no state transition */
+            return;
+        }
+    }
+    /* no more offers, can listen again */
+    vmbus->state = VMBUS_LISTEN;
+}
+
+
+static void handle_gpadl_header(VMBus *vmbus, vmbus_message_gpadl_header *msg,
+                                uint32_t msglen)
+{
+    VMBusGpadl *gpadl;
+    uint32_t num_gfns_tot, num_gfns, i;
+
+    if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) {
+        return;
+    }
+
+    if (msg->rangecount != 1 ||
+        (msg->range.byte_count & (TARGET_PAGE_SIZE - 1)) ||
+        find_gpadl(vmbus, msg->gpadl_id)) {
+        /* create a temporary broken GPADL to reply with failure */
+        num_gfns_tot = 0;
+    } else {
+        num_gfns_tot = msg->range.byte_count  >> TARGET_PAGE_BITS;
+    }
+
+    gpadl = create_gpadl(vmbus, msg->gpadl_id, msg->child_relid, num_gfns_tot);
+
+    num_gfns = (msglen - sizeof(*msg)) / sizeof(uint64_t);
+    if (num_gfns > num_gfns_tot) {
+        num_gfns = num_gfns_tot;
+    }
+
+    for (i = 0; i < num_gfns; i++) {
+        gpadl->gfns[gpadl->seen_gfns++] = msg->range.pfn_array[i];
+    }
+
+    if (gpadl_full(gpadl)) {
+        vmbus->state = VMBUS_CREATE_GPADL;
+    }
+}
+
+static void handle_gpadl_body(VMBus *vmbus, vmbus_message_gpadl_body *msg,
+                              uint32_t msglen)
+{
+    VMBusGpadl *gpadl;
+    uint32_t num_gfns_left, num_gfns, i;
+
+    if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) {
+        return;
+    }
+
+    gpadl = find_gpadl(vmbus, msg->gpadl_id);
+    if (!gpadl) {
+        /* create a temporary broken GPADL to reply with failure */
+        gpadl = create_gpadl(vmbus, msg->gpadl_id, 0, 0);
+    }
+
+    num_gfns_left = gpadl->num_gfns - gpadl->seen_gfns;
+    num_gfns = (msglen - sizeof(*msg)) / sizeof(uint64_t);
+    assert(num_gfns_left);
+    if (num_gfns > num_gfns_left) {
+        num_gfns = num_gfns_left;
+    }
+
+    for (i = 0; i < num_gfns; i++) {
+        gpadl->gfns[gpadl->seen_gfns++] = msg->pfn_array[i];
+    }
+
+    if (gpadl_full(gpadl)) {
+        vmbus->state = VMBUS_CREATE_GPADL;
+    }
+}
+
+static void send_create_gpadl(VMBus *vmbus)
+{
+    VMBusGpadl *gpadl;
+
+    QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) {
+        if (gpadl_full(gpadl) && !gpadl->alive) {
+            struct vmbus_message_gpadl_created msg = {
+                .header.message_type = VMBUS_MSG_GPADL_CREATED,
+                .gpadl_id = gpadl->id,
+                .child_relid = gpadl->child_relid,
+                .status = gpadl_broken(gpadl),
+            };
+
+            post_msg(vmbus, &msg, sizeof(msg));
+            return;
+        }
+    }
+
+    assert(false);
+}
+
+static void complete_create_gpadl(VMBus *vmbus)
+{
+    VMBusGpadl *gpadl;
+
+    QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) {
+        if (gpadl_full(gpadl) && !gpadl->alive) {
+            if (gpadl_broken(gpadl)) {
+                free_gpadl(vmbus, gpadl);
+            } else {
+                gpadl->alive = true;
+            }
+
+            vmbus->state = VMBUS_LISTEN;
+            return;
+        }
+    }
+
+    assert(false);
+}
+
+static void handle_gpadl_teardown(VMBus *vmbus,
+                                  vmbus_message_gpadl_teardown *msg,
+                                  uint32_t msglen)
+{
+    VMBusGpadl *gpadl;
+
+    if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) {
+        return;
+    }
+
+    gpadl = find_gpadl(vmbus, msg->gpadl_id);
+    if (!gpadl || gpadl->in_use) {
+        return;
+    }
+
+    gpadl->alive = false;
+    vmbus->state = VMBUS_TEARDOWN_GPADL;
+}
+
+static void send_teardown_gpadl(VMBus *vmbus)
+{
+    VMBusGpadl *gpadl;
+
+    QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) {
+        if (gpadl_full(gpadl) && !gpadl->alive) {
+            struct vmbus_message_gpadl_torndown msg = {
+                .header.message_type = VMBUS_MSG_GPADL_TORNDOWN,
+                .gpadl_id = gpadl->id,
+            };
+
+            post_msg(vmbus, &msg, sizeof(msg));
+            return;
+        }
+    }
+
+    assert(false);
+}
+
+static void complete_teardown_gpadl(VMBus *vmbus)
+{
+    VMBusGpadl *gpadl;
+
+    QTAILQ_FOREACH(gpadl, &vmbus->gpadl_list, link) {
+        if (gpadl_full(gpadl) && !gpadl->alive) {
+            free_gpadl(vmbus, gpadl);
+            vmbus->state = VMBUS_LISTEN;
+            return;
+        }
+    }
+
+    assert(false);
+}
+
+static void handle_open_channel(VMBus *vmbus, vmbus_message_open_channel *msg,
+                                uint32_t msglen)
+{
+    VMBusChannel *chan;
+
+    if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) {
+        return;
+    }
+
+    chan = find_channel(vmbus, msg->child_relid);
+    if (!chan || chan->state != VMCHAN_INIT) {
+        /* FIXME: think of replying with an error */
+        return;
+    }
+
+    chan->state = VMCHAN_OPENING;
+    chan->rb_gpadl = msg->ring_buffer_gpadl_id;
+    chan->rb_rcv_offset = msg->ring_buffer_offset;
+    chan->target_vp = msg->target_vp;
+    chan->open_id = msg->open_id;
+
+    open_channel(chan);
+    vmbus->state = VMBUS_OPEN_CHANNEL;
+}
+
+static void send_open_channel(VMBus *vmbus)
+{
+    VMBusChannel *chan;
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->state == VMCHAN_OPENING) {
+            struct vmbus_message_open_result msg = {
+                .header.message_type = VMBUS_MSG_OPENCHANNEL_RESULT,
+                .child_relid = chan->relid,
+                .open_id = chan->open_id,
+                .status = channel_broken(chan),
+            };
+
+            post_msg(vmbus, &msg, sizeof(msg));
+            return;
+        }
+    }
+
+    assert(false);
+}
+
+static void complete_open_channel(VMBus *vmbus)
+{
+    VMBusChannel *chan;
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (chan->state == VMCHAN_OPENING) {
+            chan->state = channel_broken(chan) ? VMCHAN_INIT : VMCHAN_OPEN;
+            vmbus->state = VMBUS_LISTEN;
+            return;
+        }
+    }
+
+    assert(false);
+}
+
+static void handle_close_channel(VMBus *vmbus, vmbus_message_close_channel *msg,
+                                 uint32_t msglen)
+{
+    VMBusChannel *chan;
+
+    if (msglen < sizeof(*msg) || !vmbus_initialized(vmbus)) {
+        return;
+    }
+
+    chan = find_channel(vmbus, msg->child_relid);
+    if (!chan) {
+        return;
+    }
+
+    close_channel(chan);
+}
+
+static void handle_unload(VMBus *vmbus, void *msg, uint32_t msglen)
+{
+    vmbus->state = VMBUS_UNLOAD;
+}
+
+static void send_unload(VMBus *vmbus)
+{
+    vmbus_message_header msg = {
+        .message_type = VMBUS_MSG_UNLOAD_RESPONSE,
+    };
+
+    qemu_mutex_lock(&vmbus->rx_queue_lock);
+    vmbus->rx_queue_size = 0;
+    qemu_mutex_unlock(&vmbus->rx_queue_lock);
+
+    post_msg(vmbus, &msg, sizeof(msg));
+    return;
+}
+
+static void complete_unload(VMBus *vmbus)
+{
+    vmbus_reset_all(vmbus);
+}
+
+static void process_incoming_message(VMBus *vmbus)
+{
+    struct hyperv_post_message_input *hv_msg;
+    struct vmbus_message_header *msg;
+    void *msgdata;
+    uint32_t msglen;
+
+    qemu_mutex_lock(&vmbus->rx_queue_lock);
+
+    if (!vmbus->rx_queue_size) {
+        goto unlock;
+    }
+
+    hv_msg = &vmbus->rx_queue[vmbus->rx_queue_head];
+    msglen =  hv_msg->payload_size;
+    if (msglen < sizeof(*msg)) {
+        goto out;
+    }
+    msgdata = hv_msg->payload;
+    msg = (struct vmbus_message_header*)msgdata;
+
+    trace_vmbus_process_incoming_message(msg->message_type);
+
+    switch (msg->message_type) {
+    case VMBUS_MSG_INITIATE_CONTACT:
+        handle_initiate_contact(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_REQUESTOFFERS:
+        handle_request_offers(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_GPADL_HEADER:
+        handle_gpadl_header(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_GPADL_BODY:
+        handle_gpadl_body(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_GPADL_TEARDOWN:
+        handle_gpadl_teardown(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_OPENCHANNEL:
+        handle_open_channel(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_CLOSECHANNEL:
+        handle_close_channel(vmbus, msgdata, msglen);
+        break;
+    case VMBUS_MSG_UNLOAD:
+        handle_unload(vmbus, msgdata, msglen);
+        break;
+    default:
+        error_report("unknown message type %#x", msg->message_type);
+        break;
+    }
+
+out:
+    vmbus->rx_queue_size--;
+    vmbus->rx_queue_head++;
+    vmbus->rx_queue_head %= VMBUS_RX_QUEUE_CAPACITY;
+
+    vmbus_resched(vmbus);
+unlock:
+    qemu_mutex_unlock(&vmbus->rx_queue_lock);
+}
+
+static void vmbus_run(void *opaque)
+{
+    VMBus *vmbus = opaque;
+
+    if (vmbus->msg_in_progress) {
+        return;
+    }
+
+    switch(vmbus->state) {
+    case VMBUS_LISTEN:
+        process_incoming_message(vmbus);
+        break;
+    case VMBUS_HANDSHAKE:
+        send_handshake(vmbus);
+        break;
+    case VMBUS_OFFER:
+        send_offer(vmbus);
+        break;
+    case VMBUS_CREATE_GPADL:
+        send_create_gpadl(vmbus);
+        break;
+    case VMBUS_TEARDOWN_GPADL:
+        send_teardown_gpadl(vmbus);
+        break;
+    case VMBUS_OPEN_CHANNEL:
+        send_open_channel(vmbus);
+        break;
+    case VMBUS_UNLOAD:
+        send_unload(vmbus);
+        break;
+    default:
+        assert(false);
+    };
+}
+
+static void vmbus_msg_cb(void *data, int status)
+{
+    VMBus *vmbus = data;
+
+    assert(vmbus->msg_in_progress);
+
+    trace_vmbus_post_reply_callback(status);
+
+    if (status == -EAGAIN) {
+        goto out;
+    }
+    if (status) {
+        error_report("message delivery fatal failure: %d; aborting vmbus",
+                     status);
+        vmbus_reset_all(vmbus);
+        return;
+    }
+
+    switch (vmbus->state) {
+    case VMBUS_HANDSHAKE:
+        complete_handshake(vmbus);
+        break;
+    case VMBUS_OFFER:
+        complete_offer(vmbus);
+        break;
+    case VMBUS_CREATE_GPADL:
+        complete_create_gpadl(vmbus);
+        break;
+    case VMBUS_TEARDOWN_GPADL:
+        complete_teardown_gpadl(vmbus);
+        break;
+    case VMBUS_OPEN_CHANNEL:
+        complete_open_channel(vmbus);
+        break;
+    case VMBUS_UNLOAD:
+        complete_unload(vmbus);
+        break;
+    default:
+        assert(false);
+    }
+
+out:
+    vmbus->msg_in_progress = false;
+    vmbus_resched(vmbus);
+}
+
+static void vmbus_resched(VMBus *vmbus)
+{
+    aio_bh_schedule_oneshot(qemu_get_aio_context(), vmbus_run, vmbus);
+}
+
+static void vmbus_signal_event(EventNotifier *e)
+{
+    VMBusChannel *chan;
+    VMBus *vmbus = container_of(e, VMBus, notifier);
+    unsigned long *int_map;
+    hwaddr addr, len;
+    bool is_dirty = false;
+
+    if (!event_notifier_test_and_clear(e)) {
+        return;
+    }
+
+    trace_vmbus_signal_event();
+
+    if (!vmbus->int_page_gpa) {
+        return;
+    }
+
+    addr = vmbus->int_page_gpa + TARGET_PAGE_SIZE / 2;
+    len = TARGET_PAGE_SIZE / 2;
+    int_map = cpu_physical_memory_map(addr, &len, 1);
+    if (len != TARGET_PAGE_SIZE / 2) {
+        goto unmap;
+    }
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        if (bitmap_test_and_clear_atomic(int_map, chan->relid, 1)) {
+            event_notifier_set(&chan->notifier);
+            is_dirty = true;
+        }
+    }
+
+unmap:
+    cpu_physical_memory_unmap(int_map, len, 1, is_dirty);
+}
+
+static void vmbus_dev_realize(DeviceState *dev, Error **errp)
+{
+    VMBusDevice *vdev = VMBUS_DEVICE(dev);
+    VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev);
+    VMBus *vmbus = VMBUS(qdev_get_parent_bus(dev));
+    BusChild *child;
+    Error *err = NULL;
+    char idstr[UUID_FMT_LEN + 1];
+
+    if (!qemu_uuid_is_null(&vdc->instanceid)) {
+        /* Class wants to only have a single instance with a fixed UUID */
+        vdev->instanceid = vdc->instanceid;
+    }
+    assert(!qemu_uuid_is_null(&vdev->instanceid));
+
+    /* Check for instance id collision for this class id */
+    QTAILQ_FOREACH(child, &BUS(vmbus)->children, sibling) {
+        VMBusDevice *child_dev = VMBUS_DEVICE(child->child);
+
+        if (child_dev == vdev) {
+            continue;
+        }
+
+        if (qemu_uuid_is_equal(&child_dev->instanceid, &vdev->instanceid)) {
+            qemu_uuid_unparse(&vdev->instanceid, idstr);
+            error_setg(&err, "duplicate vmbus device instance id %s", idstr);
+            goto error_out;
+        }
+    }
+
+    vdev->dma_as = &address_space_memory;
+
+    create_channels(vmbus, vdev, &err);
+    if (err) {
+        goto error_out;
+    }
+
+    if (vdc->vmdev_realize) {
+        vdc->vmdev_realize(vdev, &err);
+        if (err) {
+            goto err_vdc_realize;
+        }
+    }
+    return;
+
+err_vdc_realize:
+    free_channels(vmbus, vdev);
+error_out:
+    error_propagate(errp, err);
+}
+
+static void vmbus_dev_reset(DeviceState *dev)
+{
+    uint16_t i;
+    VMBusDevice *vdev = VMBUS_DEVICE(dev);
+    VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev);
+
+    if (vdc->vmdev_reset) {
+        vdc->vmdev_reset(vdev);
+    }
+
+    if (vdev->channels) {
+        for (i = 0; i < vdev->num_channels; i++) {
+            VMBusChannel *chan = &vdev->channels[i];
+            if (chan->state == VMCHAN_OPEN) {
+                close_channel(chan);
+            }
+            chan->offer_state = VMOFFER_INIT;
+        }
+    }
+}
+
+static void vmbus_dev_unrealize(DeviceState *dev, Error **errp)
+{
+    VMBusDevice *vdev = VMBUS_DEVICE(dev);
+    VMBusDeviceClass *vdc = VMBUS_DEVICE_GET_CLASS(vdev);
+    VMBus *vmbus = VMBUS(qdev_get_parent_bus(dev));
+
+    if (vdc->vmdev_unrealize) {
+        vdc->vmdev_unrealize(vdev, errp);
+    }
+    free_channels(vmbus, vdev);
+}
+
+static void vmbus_dev_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *kdev = DEVICE_CLASS(klass);
+    kdev->bus_type = TYPE_VMBUS;
+    kdev->realize = vmbus_dev_realize;
+    kdev->unrealize = vmbus_dev_unrealize;
+    kdev->reset = vmbus_dev_reset;
+}
+
+static int vmbus_dev_post_load(void *opaque, int version_id)
+{
+    int ret;
+    uint16_t i;
+    VMBusDevice *dev = opaque;
+
+    for (i = 0; i < dev->num_channels; i++) {
+        ret = register_chan_ids(&dev->channels[i]);
+        if (ret) {
+            goto err_reg;
+        }
+    }
+
+    return 0;
+
+err_reg:
+    while (i--) {
+        unregister_chan_ids(&dev->channels[i]);
+    }
+    return ret;
+}
+
+const VMStateDescription vmstate_vmbus_dev = {
+    .name = TYPE_VMBUS_DEVICE,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .post_load = vmbus_dev_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY(instanceid.data, VMBusDevice, 16),
+        VMSTATE_UINT16(num_channels, VMBusDevice),
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(channels, VMBusDevice, num_channels,
+                                             vmstate_channel, VMBusChannel),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+/* vmbus generic device base */
+static const TypeInfo vmbus_dev_type_info = {
+    .name = TYPE_VMBUS_DEVICE,
+    .parent = TYPE_DEVICE,
+    .abstract = true,
+    .instance_size = sizeof(VMBusDevice),
+    .class_size = sizeof(VMBusDeviceClass),
+    .class_init = vmbus_dev_class_init,
+};
+
+static void vmbus_realize(BusState *bus, Error **errp)
+{
+    int ret = 0;
+    Error *local_err = NULL;
+    VMBus *vmbus = VMBUS(bus);
+
+    qemu_mutex_init(&vmbus->rx_queue_lock);
+
+    QTAILQ_INIT(&vmbus->gpadl_list);
+    QTAILQ_INIT(&vmbus->channel_list);
+
+    ret = hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID,
+                                 vmbus_recv_message, vmbus);
+    if (ret != 0) {
+        error_setg(&local_err, "hyperv set message handler failed: %d", ret);
+        goto error_out;
+    }
+
+    ret = event_notifier_init(&vmbus->notifier, 0);
+    if (ret != 0) {
+        error_setg(&local_err, "event notifier failed to init with %d", ret);
+        goto remove_msg_handler;
+    }
+
+    event_notifier_set_handler(&vmbus->notifier, vmbus_signal_event);
+    ret = hyperv_set_event_flag_handler(VMBUS_EVENT_CONNECTION_ID,
+                                        &vmbus->notifier);
+    if (ret != 0) {
+        error_setg(&local_err, "hyperv set event handler failed with %d", ret);
+        goto clear_event_notifier;
+    }
+
+    return;
+
+clear_event_notifier:
+    event_notifier_cleanup(&vmbus->notifier);
+remove_msg_handler:
+    hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, NULL, NULL);
+error_out:
+    qemu_mutex_destroy(&vmbus->rx_queue_lock);
+    error_propagate(errp, local_err);
+}
+
+static void vmbus_unrealize(BusState *bus, Error **errp)
+{
+    VMBus *vmbus = VMBUS(bus);
+
+    hyperv_set_msg_handler(VMBUS_MESSAGE_CONNECTION_ID, NULL, NULL);
+    hyperv_set_event_flag_handler(VMBUS_MESSAGE_CONNECTION_ID, NULL);
+    event_notifier_cleanup(&vmbus->notifier);
+
+    qemu_mutex_destroy(&vmbus->rx_queue_lock);
+}
+
+static void vmbus_reset(BusState *bus)
+{
+    vmbus_deinit(VMBUS(bus));
+}
+
+static char *vmbus_get_dev_path(DeviceState *dev)
+{
+    BusState *bus = qdev_get_parent_bus(dev);
+    return qdev_get_dev_path(bus->parent);
+}
+
+static char *vmbus_get_fw_dev_path(DeviceState *dev)
+{
+    VMBusDevice *vdev = VMBUS_DEVICE(dev);
+    char path[32 + 1 + UUID_FMT_LEN + 1];
+    int off;
+
+    off = snprintf(path, sizeof(path), "%s@", qdev_fw_name(dev));
+    if (sizeof(path) - off > UUID_FMT_LEN) {
+        qemu_uuid_unparse(&vdev->instanceid, path + off);
+    }
+    return g_strdup(path);
+}
+
+static void vmbus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    k->get_dev_path = vmbus_get_dev_path;
+    k->get_fw_dev_path = vmbus_get_fw_dev_path;
+    k->realize = vmbus_realize;
+    k->unrealize = vmbus_unrealize;
+    k->reset = vmbus_reset;
+}
+
+static const TypeInfo vmbus_type_info = {
+    .name = TYPE_VMBUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(VMBus),
+    .class_init = vmbus_class_init,
+};
+
+typedef struct VMBusBridge {
+    SysBusDevice parent_obj;
+
+    VMBus bus;
+} VMBusBridge;
+
+#define VMBUS_BRIDGE(obj) OBJECT_CHECK(VMBusBridge, (obj), TYPE_VMBUS_BRIDGE)
+
+static void vmbus_bridge_realize(DeviceState *dev, Error **errp)
+{
+    VMBus *vmbus = &VMBUS_BRIDGE(dev)->bus;
+
+    if (!vmbus_exists()) {
+        error_setg(errp, "at most one %s device is permitted",
+                   TYPE_VMBUS_BRIDGE);
+        return;
+    }
+
+    if (!hyperv_is_synic_enabled()) {
+        error_report("VMBus requires usable Hyper-V SynIC and VP_INDEX");
+        return;
+    }
+
+    qbus_create_inplace(vmbus, sizeof(VMBus), TYPE_VMBUS, dev, "vmbus");
+}
+
+static int vmbus_post_load(void *opaque, int version_id)
+{
+    int ret;
+    VMBusChannel *chan;
+    VMBus *vmbus = &VMBUS_BRIDGE(opaque)->bus;
+
+    QTAILQ_FOREACH(chan, &vmbus->channel_list, link) {
+        unregister_chan_ids(chan);
+    }
+
+    ret = vmbus_init(vmbus);
+    if (ret) {
+        return ret;
+    }
+
+    vmbus_resched(vmbus);
+    return 0;
+}
+
+static const VMStateDescription vmstate_post_message_input = {
+    .name = "vmbus/hyperv_post_message_input",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(connection_id, struct hyperv_post_message_input),
+        VMSTATE_UINT32(message_type, struct hyperv_post_message_input),
+        VMSTATE_UINT32(payload_size, struct hyperv_post_message_input),
+        VMSTATE_UINT8_ARRAY(payload, struct hyperv_post_message_input,
+                            HV_MESSAGE_PAYLOAD_SIZE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static bool vmbus_rx_queue_needed(void *opaque)
+{
+    VMBus *vmbus = &VMBUS_BRIDGE(opaque)->bus;
+    return vmbus->rx_queue_size;
+}
+
+static const VMStateDescription vmstate_rx_queue = {
+    .name = "vmbus/rx_queue",
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .needed = vmbus_rx_queue_needed,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(bus.rx_queue_head, VMBusBridge),
+        VMSTATE_UINT8(bus.rx_queue_size, VMBusBridge),
+        VMSTATE_STRUCT_ARRAY(bus.rx_queue, VMBusBridge,
+                             VMBUS_RX_QUEUE_CAPACITY, 0,
+                             vmstate_post_message_input,
+                             struct hyperv_post_message_input),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_vmbus_bridge = {
+    .name = TYPE_VMBUS_BRIDGE,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .post_load = vmbus_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(bus.state, VMBusBridge),
+        VMSTATE_UINT32(bus.version, VMBusBridge),
+        VMSTATE_UINT32(bus.target_vp, VMBusBridge),
+        VMSTATE_UINT64(bus.int_page_gpa, VMBusBridge),
+        VMSTATE_QTAILQ_V(bus.gpadl_list, VMBusBridge, 0,
+                         vmstate_gpadl, VMBusGpadl, link),
+        VMSTATE_END_OF_LIST()
+    },
+    .subsections = (const VMStateDescription*[]) {
+        &vmstate_rx_queue,
+        NULL
+    }
+};
+
+static void vmbus_bridge_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+    k->realize = vmbus_bridge_realize;
+    k->fw_name = "vmbus@0";
+    set_bit(DEVICE_CATEGORY_BRIDGE, k->categories);
+    k->vmsd = &vmstate_vmbus_bridge;
+    k->user_creatable = true;
+}
+
+static const TypeInfo vmbus_bridge_type_info = {
+    .name = TYPE_VMBUS_BRIDGE,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(VMBusBridge),
+    .class_init = vmbus_bridge_class_init,
+};
+
+static void vmbus_register_types(void)
+{
+    type_register_static(&vmbus_bridge_type_info);
+    type_register_static(&vmbus_dev_type_info);
+    type_register_static(&vmbus_type_info);
+}
+
+type_init(vmbus_register_types)
diff --git a/include/hw/vmbus/vmbus.h b/include/hw/vmbus/vmbus.h
new file mode 100644
index 0000000000..813614d6d0
--- /dev/null
+++ b/include/hw/vmbus/vmbus.h
@@ -0,0 +1,109 @@
+/*
+ * QEMU Hyper-V VMBus
+ *
+ * Copyright (c) 2017-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 QEMU_VMBUS_H
+#define QEMU_VMBUS_H
+
+#include "hw/qdev-properties.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/dma.h"
+#include "target/i386/hyperv.h"
+#include "target/i386/hyperv-proto.h"
+#include "hw/vmbus/vmbus-proto.h"
+#include "qemu/uuid.h"
+
+#define TYPE_VMBUS_DEVICE "vmbus-dev"
+#define TYPE_VMBUS_BRIDGE "vmbus-bridge"
+
+#define VMBUS_DEVICE(obj) \
+    OBJECT_CHECK(VMBusDevice, (obj), TYPE_VMBUS_DEVICE)
+#define VMBUS_DEVICE_CLASS(klass) \
+    OBJECT_CLASS_CHECK(VMBusDeviceClass, (klass), TYPE_VMBUS_DEVICE)
+#define VMBUS_DEVICE_GET_CLASS(obj) \
+    OBJECT_GET_CLASS(VMBusDeviceClass, (obj), TYPE_VMBUS_DEVICE)
+
+typedef struct VMBus VMBus;
+typedef struct VMBusChannel VMBusChannel;
+typedef struct VMBusDevice VMBusDevice;
+typedef struct VMBusGpadl VMBusGpadl;
+
+static inline Object *vmbus_exists(void)
+{
+    return object_resolve_path_type("", TYPE_VMBUS_BRIDGE, NULL);
+}
+
+typedef void(*VMBusChannelNotifyCb)(struct VMBusChannel *chan);
+
+typedef struct VMBusDeviceClass {
+    DeviceClass parent;
+
+    QemuUUID classid;
+    QemuUUID instanceid;     /* Fixed UUID for singleton devices */
+    uint16_t channel_flags;
+    uint16_t mmio_size_mb;
+
+    void (*vmdev_realize)(VMBusDevice *vdev, Error **errp);
+    void (*vmdev_unrealize)(VMBusDevice *vdev, Error **errp);
+    void (*vmdev_reset)(VMBusDevice *vdev);
+    uint16_t (*num_channels)(VMBusDevice *vdev);
+    int (*open_channel) (VMBusDevice *vdev);
+    void (*close_channel) (VMBusDevice *vdev);
+    VMBusChannelNotifyCb chan_notify_cb;
+} VMBusDeviceClass;
+
+typedef struct VMBusDevice {
+    DeviceState parent;
+    QemuUUID instanceid;
+    uint16_t num_channels;
+    VMBusChannel *channels;
+    AddressSpace *dma_as;
+} VMBusDevice;
+
+extern const VMStateDescription vmstate_vmbus_dev;
+
+typedef struct VMBusChanReq {
+    VMBusChannel *chan;
+    uint16_t pkt_type;
+    uint32_t msglen;
+    void *msg;
+    uint64_t transaction_id;
+    void *comp;
+    QEMUSGList sgl;
+} VMBusChanReq;
+
+VMBusDevice *vmbus_channel_device(VMBusChannel *chan);
+VMBusChannel *vmbus_device_channel(VMBusDevice *dev, uint32_t chan_idx);
+uint32_t vmbus_channel_idx(VMBusChannel *chan);
+void vmbus_notify_channel(VMBusChannel *chan);
+
+int vmbus_channel_send(VMBusChannel *chan, uint16_t pkt_type,
+                       void *desc, uint32_t desclen,
+                       void *msg, uint32_t msglen,
+                       bool need_comp, uint64_t transaction_id);
+int vmbus_chan_send_completion(VMBusChanReq *req);
+int vmbus_channel_reserve(VMBusChannel *chan,
+                          uint32_t desclen, uint32_t msglen);
+void *vmbus_channel_recv(VMBusChannel *chan, uint32_t size);
+void vmbus_release_req(void *req);
+
+void vmbus_save_req(QEMUFile *f, VMBusChanReq *req);
+void *vmbus_load_req(QEMUFile *f, VMBusDevice *dev, uint32_t size);
+
+
+VMBusGpadl *vmbus_get_gpadl(VMBusChannel *chan, uint32_t gpadl_id);
+void vmbus_put_gpadl(VMBusGpadl *gpadl);
+uint32_t vmbus_gpadl_len(VMBusGpadl *gpadl);
+ssize_t vmbus_iov_to_gpadl(VMBusChannel *chan, VMBusGpadl *gpadl, uint32_t off,
+                           const struct iovec *iov, size_t iov_cnt);
+int vmbus_map_sgl(QEMUSGList *sgl, DMADirection dir, struct iovec *iov,
+                  unsigned iov_cnt, size_t len, size_t off);
+void vmbus_unmap_sgl(QEMUSGList *sgl, DMADirection dir, struct iovec *iov,
+                     unsigned iov_cnt, size_t accessed);
+
+#endif
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
                   ` (3 preceding siblings ...)
  2020-04-03 14:23 ` [PATCH v1 4/5] vmbus: vmbus implementation Jon Doron
@ 2020-04-03 14:23 ` Jon Doron
  2020-04-03 14:56   ` Maciej S. Szmigiero
  2020-04-06 10:14   ` Igor Mammedov
  2020-04-03 22:48 ` [PATCH v1 0/5] hyperv: VMBus implementation no-reply
  5 siblings, 2 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 14:23 UTC (permalink / raw)
  To: qemu-devel
  Cc: Evgeny Yakovlev, ehabkost, Roman Kagan, pbonzini, vkuznets, Jon Doron

Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
entry to DSDT in case vmbus has been enabled.

Experimentally Windows guests were found to require this entry to
include two IRQ resources, so this patch adds two semi-arbitrarily
chosen ones (7 and 13).  This results, in particular, in parallel port
conflicting with vmbus.

TODO: discover and use spare IRQs to avoid conflicts.

Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
Signed-off-by: Jon Doron <arilou@gmail.com>
---
 hw/i386/acpi-build.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 2a7e55bae7..6d7fdbbe9b 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -43,6 +43,7 @@
 #include "hw/acpi/tpm.h"
 #include "hw/acpi/vmgenid.h"
 #include "hw/boards.h"
+#include "hw/vmbus/vmbus.h"
 #include "sysemu/tpm_backend.h"
 #include "hw/rtc/mc146818rtc_regs.h"
 #include "migration/vmstate.h"
@@ -1270,6 +1271,43 @@ static Aml *build_com_device_aml(uint8_t uid)
     return dev;
 }
 
+static Aml *build_vmbus_device_aml(void)
+{
+    Aml *dev;
+    Aml *method;
+    Aml *crs;
+
+    dev = aml_device("VMBS");
+    aml_append(dev, aml_name_decl("STA", aml_int(0xF)));
+    aml_append(dev, aml_name_decl("_HID", aml_string("VMBus")));
+    aml_append(dev, aml_name_decl("_UID", aml_int(0x0)));
+    aml_append(dev, aml_name_decl("_DDN", aml_string("VMBUS")));
+
+    method = aml_method("_DIS", 0, AML_NOTSERIALIZED);
+    aml_append(method, aml_store(aml_and(aml_name("STA"), aml_int(0xD), NULL),
+                                     aml_name("STA")));
+    aml_append(dev, method);
+
+    method = aml_method("_PS0", 0, AML_NOTSERIALIZED);
+    aml_append(method, aml_store(aml_or(aml_name("STA"), aml_int(0xF), NULL),
+                                     aml_name("STA")));
+    aml_append(dev, method);
+
+    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
+    aml_append(method, aml_store(aml_name("STA"), aml_local(0)));
+    aml_append(method, aml_return(aml_local(0)));
+    aml_append(dev, method);
+
+    aml_append(dev, aml_name_decl("_PS3", aml_int(0x0)));
+
+    crs = aml_resource_template();
+    aml_append(crs, aml_irq_no_flags(7));
+    aml_append(crs, aml_irq_no_flags(13));
+    aml_append(dev, aml_name_decl("_CRS", crs));
+
+    return dev;
+}
+
 static void build_isa_devices_aml(Aml *table)
 {
     ISADevice *fdc = pc_find_fdc0();
@@ -1296,6 +1334,10 @@ static void build_isa_devices_aml(Aml *table)
         build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
     }
 
+    if (vmbus_exists()) {
+        aml_append(scope, build_vmbus_device_aml());
+    }
+
     aml_append(table, scope);
 }
 
-- 
2.24.1



^ permalink raw reply related	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 14:23 ` [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry Jon Doron
@ 2020-04-03 14:56   ` Maciej S. Szmigiero
  2020-04-03 15:06     ` Jon Doron
  2020-04-06 10:14   ` Igor Mammedov
  1 sibling, 1 reply; 26+ messages in thread
From: Maciej S. Szmigiero @ 2020-04-03 14:56 UTC (permalink / raw)
  To: Jon Doron
  Cc: Evgeny Yakovlev, ehabkost, qemu-devel, Roman Kagan, pbonzini, vkuznets

Hi Jon,

On 03.04.2020 16:23, Jon Doron wrote:
> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> entry to DSDT in case vmbus has been enabled.
> 
> Experimentally Windows guests were found to require this entry to
> include two IRQ resources, so this patch adds two semi-arbitrarily
> chosen ones (7 and 13).  This results, in particular, in parallel port
> conflicting with vmbus.
> 
> TODO: discover and use spare IRQs to avoid conflicts.
> 
> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> Signed-off-by: Jon Doron <arilou@gmail.com>

Nice work, thanks!

However, it seems to be based on the code version that was posted in 
February 2018, and not the latest version in OpenVZ qemu repository
dated October 2019:
https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus

This newer version has slightly different API here and there.
Any particular reason for selecting that older version for porting?

I have actually rebased this latest version on the top of the current
QEMU master, and it basically seems to work fine.
However, I haven't done extensive tests whether there isn't a memory leak
somewhere or so on.

Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 14:56   ` Maciej S. Szmigiero
@ 2020-04-03 15:06     ` Jon Doron
  2020-04-03 15:30       ` Jon Doron
  0 siblings, 1 reply; 26+ messages in thread
From: Jon Doron @ 2020-04-03 15:06 UTC (permalink / raw)
  To: Maciej S. Szmigiero
  Cc: Evgeny Yakovlev, ehabkost, QEMU, Roman Kagan, Paolo Bonzini,
	Vitaly Kuznetsov

Thank you Maciej, I based it on top of what Denis (den@openvz.org) gave me
which was this:
https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm

Do you think you have a more recent version I dont mind diffing and
resubmitting a new version of the patchset?

Thanks,
-- Jon.

On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
<mail@maciej.szmigiero.name> wrote:
>
> Hi Jon,
>
> On 03.04.2020 16:23, Jon Doron wrote:
> > Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> > entry to DSDT in case vmbus has been enabled.
> >
> > Experimentally Windows guests were found to require this entry to
> > include two IRQ resources, so this patch adds two semi-arbitrarily
> > chosen ones (7 and 13).  This results, in particular, in parallel port
> > conflicting with vmbus.
> >
> > TODO: discover and use spare IRQs to avoid conflicts.
> >
> > Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> > Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> > Signed-off-by: Jon Doron <arilou@gmail.com>
>
> Nice work, thanks!
>
> However, it seems to be based on the code version that was posted in
> February 2018, and not the latest version in OpenVZ qemu repository
> dated October 2019:
> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>
> This newer version has slightly different API here and there.
> Any particular reason for selecting that older version for porting?
>
> I have actually rebased this latest version on the top of the current
> QEMU master, and it basically seems to work fine.
> However, I haven't done extensive tests whether there isn't a memory leak
> somewhere or so on.
>
> Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 15:06     ` Jon Doron
@ 2020-04-03 15:30       ` Jon Doron
  2020-04-03 15:50         ` Maciej S. Szmigiero
  2020-04-03 17:18         ` Maciej S. Szmigiero
  0 siblings, 2 replies; 26+ messages in thread
From: Jon Doron @ 2020-04-03 15:30 UTC (permalink / raw)
  To: Maciej S. Szmigiero
  Cc: Evgeny Yakovlev, ehabkost, QEMU, Roman Kagan, Paolo Bonzini,
	Vitaly Kuznetsov

 Thank you Maciej it seems like your version is really ahead I'll do
the required work and merge it so i can submit a v2 with the latest
patchset from Roman

On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
>
> Thank you Maciej, I based it on top of what Denis (den@openvz.org) gave me
> which was this:
> https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
>
> Do you think you have a more recent version I dont mind diffing and
> resubmitting a new version of the patchset?
>
> Thanks,
> -- Jon.
>
> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
> <mail@maciej.szmigiero.name> wrote:
> >
> > Hi Jon,
> >
> > On 03.04.2020 16:23, Jon Doron wrote:
> > > Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> > > entry to DSDT in case vmbus has been enabled.
> > >
> > > Experimentally Windows guests were found to require this entry to
> > > include two IRQ resources, so this patch adds two semi-arbitrarily
> > > chosen ones (7 and 13).  This results, in particular, in parallel port
> > > conflicting with vmbus.
> > >
> > > TODO: discover and use spare IRQs to avoid conflicts.
> > >
> > > Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> > > Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> > > Signed-off-by: Jon Doron <arilou@gmail.com>
> >
> > Nice work, thanks!
> >
> > However, it seems to be based on the code version that was posted in
> > February 2018, and not the latest version in OpenVZ qemu repository
> > dated October 2019:
> > https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
> >
> > This newer version has slightly different API here and there.
> > Any particular reason for selecting that older version for porting?
> >
> > I have actually rebased this latest version on the top of the current
> > QEMU master, and it basically seems to work fine.
> > However, I haven't done extensive tests whether there isn't a memory leak
> > somewhere or so on.
> >
> > Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 15:30       ` Jon Doron
@ 2020-04-03 15:50         ` Maciej S. Szmigiero
  2020-04-03 17:18         ` Maciej S. Szmigiero
  1 sibling, 0 replies; 26+ messages in thread
From: Maciej S. Szmigiero @ 2020-04-03 15:50 UTC (permalink / raw)
  To: Jon Doron
  Cc: Evgeny Yakovlev, ehabkost, QEMU, Roman Kagan, Paolo Bonzini,
	Vitaly Kuznetsov

Thanks Jon,

I will push out to what I have in a moment.

Maciej

On 03.04.2020 17:30, Jon Doron wrote:
>  Thank you Maciej it seems like your version is really ahead I'll do
> the required work and merge it so i can submit a v2 with the latest
> patchset from Roman
> 
> On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
>>
>> Thank you Maciej, I based it on top of what Denis (den@openvz.org) gave me
>> which was this:
>> https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
>>
>> Do you think you have a more recent version I dont mind diffing and
>> resubmitting a new version of the patchset?
>>
>> Thanks,
>> -- Jon.
>>
>> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
>> <mail@maciej.szmigiero.name> wrote:
>>>
>>> Hi Jon,
>>>
>>> On 03.04.2020 16:23, Jon Doron wrote:
>>>> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
>>>> entry to DSDT in case vmbus has been enabled.
>>>>
>>>> Experimentally Windows guests were found to require this entry to
>>>> include two IRQ resources, so this patch adds two semi-arbitrarily
>>>> chosen ones (7 and 13).  This results, in particular, in parallel port
>>>> conflicting with vmbus.
>>>>
>>>> TODO: discover and use spare IRQs to avoid conflicts.
>>>>
>>>> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
>>>> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
>>>> Signed-off-by: Jon Doron <arilou@gmail.com>
>>>
>>> Nice work, thanks!
>>>
>>> However, it seems to be based on the code version that was posted in
>>> February 2018, and not the latest version in OpenVZ qemu repository
>>> dated October 2019:
>>> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>>>
>>> This newer version has slightly different API here and there.
>>> Any particular reason for selecting that older version for porting?
>>>
>>> I have actually rebased this latest version on the top of the current
>>> QEMU master, and it basically seems to work fine.
>>> However, I haven't done extensive tests whether there isn't a memory leak
>>> somewhere or so on.
>>>
>>> Maciej



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 15:30       ` Jon Doron
  2020-04-03 15:50         ` Maciej S. Szmigiero
@ 2020-04-03 17:18         ` Maciej S. Szmigiero
  2020-04-03 21:00           ` Maciej S. Szmigiero
  1 sibling, 1 reply; 26+ messages in thread
From: Maciej S. Szmigiero @ 2020-04-03 17:18 UTC (permalink / raw)
  To: Jon Doron
  Cc: Evgeny Yakovlev, ehabkost, QEMU, Liran Alon, Roman Kagan,
	Paolo Bonzini, Vitaly Kuznetsov

Hi Jon,

The patches are available here:
https://github.com/maciejsszmigiero/qemu.git in "vmbus-patches" branch.

Please note that these patches don't have Roman's "Signed-off-by:" tags,
so I haven't applied mine, either.

If you are able to establish a proper SoB chain then please also add:
"Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>".

Thanks for the effort,
Maciej

On 03.04.2020 17:30, Jon Doron wrote:
>  Thank you Maciej it seems like your version is really ahead I'll do
> the required work and merge it so i can submit a v2 with the latest
> patchset from Roman
> 
> On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
>>
>> Thank you Maciej, I based it on top of what Denis (den@openvz.org) gave me
>> which was this:
>> https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
>>
>> Do you think you have a more recent version I dont mind diffing and
>> resubmitting a new version of the patchset?
>>
>> Thanks,
>> -- Jon.
>>
>> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
>> <mail@maciej.szmigiero.name> wrote:
>>>
>>> Hi Jon,
>>>
>>> On 03.04.2020 16:23, Jon Doron wrote:
>>>> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
>>>> entry to DSDT in case vmbus has been enabled.
>>>>
>>>> Experimentally Windows guests were found to require this entry to
>>>> include two IRQ resources, so this patch adds two semi-arbitrarily
>>>> chosen ones (7 and 13).  This results, in particular, in parallel port
>>>> conflicting with vmbus.
>>>>
>>>> TODO: discover and use spare IRQs to avoid conflicts.
>>>>
>>>> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
>>>> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
>>>> Signed-off-by: Jon Doron <arilou@gmail.com>
>>>
>>> Nice work, thanks!
>>>
>>> However, it seems to be based on the code version that was posted in
>>> February 2018, and not the latest version in OpenVZ qemu repository
>>> dated October 2019:
>>> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>>>
>>> This newer version has slightly different API here and there.
>>> Any particular reason for selecting that older version for porting?
>>>
>>> I have actually rebased this latest version on the top of the current
>>> QEMU master, and it basically seems to work fine.
>>> However, I haven't done extensive tests whether there isn't a memory leak
>>> somewhere or so on.
>>>
>>> Maciej



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 17:18         ` Maciej S. Szmigiero
@ 2020-04-03 21:00           ` Maciej S. Szmigiero
  2020-04-06  7:32             ` Roman Kagan
  0 siblings, 1 reply; 26+ messages in thread
From: Maciej S. Szmigiero @ 2020-04-03 21:00 UTC (permalink / raw)
  To: Roman Kagan
  Cc: Evgeny Yakovlev, Jon Doron, QEMU, Liran Alon, Roman Kagan,
	Paolo Bonzini, Vitaly Kuznetsov, ehabkost

It seems to me that Roman might not be getting our e-mails since his
new e-mail address seems to be "rvkagan@yandex-team.ru".

@Roman, are you with us?

Thanks,
Maciej

On 03.04.2020 19:18, Maciej S. Szmigiero wrote:
> Hi Jon,
> 
> The patches are available here:
> https://github.com/maciejsszmigiero/qemu.git in "vmbus-patches" branch.
> 
> Please note that these patches don't have Roman's "Signed-off-by:" tags,
> so I haven't applied mine, either.
> 
> If you are able to establish a proper SoB chain then please also add:
> "Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>".
> 
> Thanks for the effort,
> Maciej
> 
> On 03.04.2020 17:30, Jon Doron wrote:
>>  Thank you Maciej it seems like your version is really ahead I'll do
>> the required work and merge it so i can submit a v2 with the latest
>> patchset from Roman
>>
>> On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
>>>
>>> Thank you Maciej, I based it on top of what Denis (den@openvz.org) gave me
>>> which was this:
>>> https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
>>>
>>> Do you think you have a more recent version I dont mind diffing and
>>> resubmitting a new version of the patchset?
>>>
>>> Thanks,
>>> -- Jon.
>>>
>>> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
>>> <mail@maciej.szmigiero.name> wrote:
>>>>
>>>> Hi Jon,
>>>>
>>>> On 03.04.2020 16:23, Jon Doron wrote:
>>>>> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
>>>>> entry to DSDT in case vmbus has been enabled.
>>>>>
>>>>> Experimentally Windows guests were found to require this entry to
>>>>> include two IRQ resources, so this patch adds two semi-arbitrarily
>>>>> chosen ones (7 and 13).  This results, in particular, in parallel port
>>>>> conflicting with vmbus.
>>>>>
>>>>> TODO: discover and use spare IRQs to avoid conflicts.
>>>>>
>>>>> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
>>>>> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
>>>>> Signed-off-by: Jon Doron <arilou@gmail.com>
>>>>
>>>> Nice work, thanks!
>>>>
>>>> However, it seems to be based on the code version that was posted in
>>>> February 2018, and not the latest version in OpenVZ qemu repository
>>>> dated October 2019:
>>>> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>>>>
>>>> This newer version has slightly different API here and there.
>>>> Any particular reason for selecting that older version for porting?
>>>>
>>>> I have actually rebased this latest version on the top of the current
>>>> QEMU master, and it basically seems to work fine.
>>>> However, I haven't done extensive tests whether there isn't a memory leak
>>>> somewhere or so on.
>>>>
>>>> Maciej
> 



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 0/5] hyperv: VMBus implementation
  2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
                   ` (4 preceding siblings ...)
  2020-04-03 14:23 ` [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry Jon Doron
@ 2020-04-03 22:48 ` no-reply
  5 siblings, 0 replies; 26+ messages in thread
From: no-reply @ 2020-04-03 22:48 UTC (permalink / raw)
  To: arilou; +Cc: pbonzini, vkuznets, arilou, qemu-devel, ehabkost

Patchew URL: https://patchew.org/QEMU/20200403142308.82990-1-arilou@gmail.com/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Subject: [PATCH v1 0/5] hyperv: VMBus implementation
Message-id: 20200403142308.82990-1-arilou@gmail.com
Type: series

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
f79ca2e i386: Hyper-V VMBus ACPI DSDT entry
d2715b7 vmbus: vmbus implementation
00f328e vmbus: add vmbus protocol definitions
8a097ec hyperv: SControl is optional to enable SynIc
2dfe4b0 hyperv: expose API to determine if synic is enabled

=== OUTPUT BEGIN ===
1/5 Checking commit 2dfe4b0090be (hyperv: expose API to determine if synic is enabled)
2/5 Checking commit 8a097ec3667f (hyperv: SControl is optional to enable SynIc)
3/5 Checking commit 00f328eb4254 (vmbus: add vmbus protocol definitions)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#17: 
new file mode 100644

ERROR: do not use C99 // comments
#135: FILE: include/hw/vmbus/vmbus-proto.h:114:
+    uint8_t  monitor_flags;      // VMBUS_OFFER_MONITOR_*

ERROR: do not use C99 // comments
#136: FILE: include/hw/vmbus/vmbus-proto.h:115:
+    uint16_t interrupt_flags;    // VMBUS_OFFER_INTERRUPT_*

ERROR: do not use C99 // comments
#213: FILE: include/hw/vmbus/vmbus-proto.h:192:
+    uint32_t feature_bits;     // VMBUS_RING_BUFFER_FEAT_*

total: 3 errors, 1 warnings, 222 lines checked

Patch 3/5 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

4/5 Checking commit d2715b789821 (vmbus: vmbus implementation)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#106: 
new file mode 100644

ERROR: memory barrier without comment
#645: FILE: hw/vmbus/vmbus.c:505:
+    smp_mb();

ERROR: memory barrier without comment
#706: FILE: hw/vmbus/vmbus.c:566:
+    smp_mb();

ERROR: "(foo*)" should be "(foo *)"
#1547: FILE: hw/vmbus/vmbus.c:1407:
+    vmbus_msg = (struct vmbus_message_header*)msg->payload;

ERROR: "(foo*)" should be "(foo *)"
#2036: FILE: hw/vmbus/vmbus.c:1896:
+    msg = (struct vmbus_message_header*)msgdata;

ERROR: space required before the open parenthesis '('
#2088: FILE: hw/vmbus/vmbus.c:1948:
+    switch(vmbus->state) {

WARNING: line over 80 characters
#2325: FILE: hw/vmbus/vmbus.c:2185:
+        VMSTATE_STRUCT_VARRAY_POINTER_UINT16(channels, VMBusDevice, num_channels,

ERROR: spaces required around that '*' (ctx:VxV)
#2532: FILE: hw/vmbus/vmbus.c:2392:
+    .subsections = (const VMStateDescription*[]) {
                                             ^

total: 6 errors, 2 warnings, 2585 lines checked

Patch 4/5 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

5/5 Checking commit f79ca2e47cca (i386: Hyper-V VMBus ACPI DSDT entry)
=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20200403142308.82990-1-arilou@gmail.com/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 21:00           ` Maciej S. Szmigiero
@ 2020-04-06  7:32             ` Roman Kagan
  2020-04-06  8:20               ` Jon Doron
  0 siblings, 1 reply; 26+ messages in thread
From: Roman Kagan @ 2020-04-06  7:32 UTC (permalink / raw)
  To: Maciej S. Szmigiero
  Cc: Evgeny Yakovlev, Jon Doron, QEMU, Liran Alon, Roman Kagan,
	Paolo Bonzini, Vitaly Kuznetsov, ehabkost

On Fri, Apr 03, 2020 at 11:00:27PM +0200, Maciej S. Szmigiero wrote:
> It seems to me that Roman might not be getting our e-mails since his
> new e-mail address seems to be "rvkagan@yandex-team.ru".

Indeed.  I'm subscribed with my new address to qemu-devel ML but must
have missed this series.

> @Roman, are you with us?

Yes ;)

So what are your plans regarding this patchset?

Thanks,
Roman.

> On 03.04.2020 19:18, Maciej S. Szmigiero wrote:
> > Hi Jon,
> > 
> > The patches are available here:
> > https://github.com/maciejsszmigiero/qemu.git in "vmbus-patches" branch.
> > 
> > Please note that these patches don't have Roman's "Signed-off-by:" tags,
> > so I haven't applied mine, either.
> > 
> > If you are able to establish a proper SoB chain then please also add:
> > "Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>".
> > 
> > Thanks for the effort,
> > Maciej
> > 
> > On 03.04.2020 17:30, Jon Doron wrote:
> >>  Thank you Maciej it seems like your version is really ahead I'll do
> >> the required work and merge it so i can submit a v2 with the latest
> >> patchset from Roman
> >>
> >> On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
> >>>
> >>> Thank you Maciej, I based it on top of what Denis (den@openvz.org) gave me
> >>> which was this:
> >>> https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
> >>>
> >>> Do you think you have a more recent version I dont mind diffing and
> >>> resubmitting a new version of the patchset?
> >>>
> >>> Thanks,
> >>> -- Jon.
> >>>
> >>> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
> >>> <mail@maciej.szmigiero.name> wrote:
> >>>>
> >>>> Hi Jon,
> >>>>
> >>>> On 03.04.2020 16:23, Jon Doron wrote:
> >>>>> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> >>>>> entry to DSDT in case vmbus has been enabled.
> >>>>>
> >>>>> Experimentally Windows guests were found to require this entry to
> >>>>> include two IRQ resources, so this patch adds two semi-arbitrarily
> >>>>> chosen ones (7 and 13).  This results, in particular, in parallel port
> >>>>> conflicting with vmbus.
> >>>>>
> >>>>> TODO: discover and use spare IRQs to avoid conflicts.
> >>>>>
> >>>>> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> >>>>> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> >>>>> Signed-off-by: Jon Doron <arilou@gmail.com>
> >>>>
> >>>> Nice work, thanks!
> >>>>
> >>>> However, it seems to be based on the code version that was posted in
> >>>> February 2018, and not the latest version in OpenVZ qemu repository
> >>>> dated October 2019:
> >>>> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
> >>>>
> >>>> This newer version has slightly different API here and there.
> >>>> Any particular reason for selecting that older version for porting?
> >>>>
> >>>> I have actually rebased this latest version on the top of the current
> >>>> QEMU master, and it basically seems to work fine.
> >>>> However, I haven't done extensive tests whether there isn't a memory leak
> >>>> somewhere or so on.
> >>>>
> >>>> Maciej
> > 
> 


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-06  7:32             ` Roman Kagan
@ 2020-04-06  8:20               ` Jon Doron
  2020-04-07 18:56                 ` Roman Kagan
  0 siblings, 1 reply; 26+ messages in thread
From: Jon Doron @ 2020-04-06  8:20 UTC (permalink / raw)
  To: Roman Kagan, Maciej S. Szmigiero, Jon Doron, QEMU,
	Evgeny Yakovlev, ehabkost, Paolo Bonzini, Vitaly Kuznetsov,
	Liran Alon, Roman Kagan

[-- Attachment #1: Type: text/plain, Size: 3430 bytes --]

Well I want it to be merged in :-)

On Mon, Apr 6, 2020, 10:32 Roman Kagan <rvkagan@yandex-team.ru> wrote:

> On Fri, Apr 03, 2020 at 11:00:27PM +0200, Maciej S. Szmigiero wrote:
> > It seems to me that Roman might not be getting our e-mails since his
> > new e-mail address seems to be "rvkagan@yandex-team.ru".
>
> Indeed.  I'm subscribed with my new address to qemu-devel ML but must
> have missed this series.
>
> > @Roman, are you with us?
>
> Yes ;)
>
> So what are your plans regarding this patchset?
>
> Thanks,
> Roman.
>
> > On 03.04.2020 19:18, Maciej S. Szmigiero wrote:
> > > Hi Jon,
> > >
> > > The patches are available here:
> > > https://github.com/maciejsszmigiero/qemu.git in "vmbus-patches"
> branch.
> > >
> > > Please note that these patches don't have Roman's "Signed-off-by:"
> tags,
> > > so I haven't applied mine, either.
> > >
> > > If you are able to establish a proper SoB chain then please also add:
> > > "Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>".
> > >
> > > Thanks for the effort,
> > > Maciej
> > >
> > > On 03.04.2020 17:30, Jon Doron wrote:
> > >>  Thank you Maciej it seems like your version is really ahead I'll do
> > >> the required work and merge it so i can submit a v2 with the latest
> > >> patchset from Roman
> > >>
> > >> On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
> > >>>
> > >>> Thank you Maciej, I based it on top of what Denis (den@openvz.org)
> gave me
> > >>> which was this:
> > >>>
> https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
> > >>>
> > >>> Do you think you have a more recent version I dont mind diffing and
> > >>> resubmitting a new version of the patchset?
> > >>>
> > >>> Thanks,
> > >>> -- Jon.
> > >>>
> > >>> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
> > >>> <mail@maciej.szmigiero.name> wrote:
> > >>>>
> > >>>> Hi Jon,
> > >>>>
> > >>>> On 03.04.2020 16:23, Jon Doron wrote:
> > >>>>> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> > >>>>> entry to DSDT in case vmbus has been enabled.
> > >>>>>
> > >>>>> Experimentally Windows guests were found to require this entry to
> > >>>>> include two IRQ resources, so this patch adds two semi-arbitrarily
> > >>>>> chosen ones (7 and 13).  This results, in particular, in parallel
> port
> > >>>>> conflicting with vmbus.
> > >>>>>
> > >>>>> TODO: discover and use spare IRQs to avoid conflicts.
> > >>>>>
> > >>>>> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> > >>>>> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> > >>>>> Signed-off-by: Jon Doron <arilou@gmail.com>
> > >>>>
> > >>>> Nice work, thanks!
> > >>>>
> > >>>> However, it seems to be based on the code version that was posted in
> > >>>> February 2018, and not the latest version in OpenVZ qemu repository
> > >>>> dated October 2019:
> > >>>>
> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
> > >>>>
> > >>>> This newer version has slightly different API here and there.
> > >>>> Any particular reason for selecting that older version for porting?
> > >>>>
> > >>>> I have actually rebased this latest version on the top of the
> current
> > >>>> QEMU master, and it basically seems to work fine.
> > >>>> However, I haven't done extensive tests whether there isn't a
> memory leak
> > >>>> somewhere or so on.
> > >>>>
> > >>>> Maciej
> > >
> >
>

[-- Attachment #2: Type: text/html, Size: 5934 bytes --]

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-03 14:23 ` [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry Jon Doron
  2020-04-03 14:56   ` Maciej S. Szmigiero
@ 2020-04-06 10:14   ` Igor Mammedov
  1 sibling, 0 replies; 26+ messages in thread
From: Igor Mammedov @ 2020-04-06 10:14 UTC (permalink / raw)
  To: Jon Doron
  Cc: Evgeny Yakovlev, ehabkost, qemu-devel, Roman Kagan, pbonzini, vkuznets

On Fri,  3 Apr 2020 17:23:08 +0300
Jon Doron <arilou@gmail.com> wrote:

> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> entry to DSDT in case vmbus has been enabled.
> 
> Experimentally Windows guests were found to require this entry to
> include two IRQ resources, so this patch adds two semi-arbitrarily
> chosen ones (7 and 13).  This results, in particular, in parallel port
> conflicting with vmbus.
> 
> TODO: discover and use spare IRQs to avoid conflicts.

CCing Vitaly
as he might know whom to ping wrt 'spec' that describes vmbus
and confirm  with ACPI tables that native hyperv generates.

 
> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> Signed-off-by: Jon Doron <arilou@gmail.com>
> ---
>  hw/i386/acpi-build.c | 42 ++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 2a7e55bae7..6d7fdbbe9b 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -43,6 +43,7 @@
>  #include "hw/acpi/tpm.h"
>  #include "hw/acpi/vmgenid.h"
>  #include "hw/boards.h"
> +#include "hw/vmbus/vmbus.h"
>  #include "sysemu/tpm_backend.h"
>  #include "hw/rtc/mc146818rtc_regs.h"
>  #include "migration/vmstate.h"
> @@ -1270,6 +1271,43 @@ static Aml *build_com_device_aml(uint8_t uid)
>      return dev;
>  }
>  
> +static Aml *build_vmbus_device_aml(void)
> +{
> +    Aml *dev;
> +    Aml *method;
> +    Aml *crs;
> +
> +    dev = aml_device("VMBS");
> +    aml_append(dev, aml_name_decl("STA", aml_int(0xF)));
> +    aml_append(dev, aml_name_decl("_HID", aml_string("VMBus")));
> +    aml_append(dev, aml_name_decl("_UID", aml_int(0x0)));
> +    aml_append(dev, aml_name_decl("_DDN", aml_string("VMBUS")));
> +
> +    method = aml_method("_DIS", 0, AML_NOTSERIALIZED);
> +    aml_append(method, aml_store(aml_and(aml_name("STA"), aml_int(0xD), NULL),
> +                                     aml_name("STA")));
> +    aml_append(dev, method);
> +
> +    method = aml_method("_PS0", 0, AML_NOTSERIALIZED);
> +    aml_append(method, aml_store(aml_or(aml_name("STA"), aml_int(0xF), NULL),
> +                                     aml_name("STA")));
> +    aml_append(dev, method);
> +
> +    method = aml_method("_STA", 0, AML_NOTSERIALIZED);
> +    aml_append(method, aml_store(aml_name("STA"), aml_local(0)));
> +    aml_append(method, aml_return(aml_local(0)));
> +    aml_append(dev, method);
does it need all that complicated _STA handling?
Would simple
   aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
work for you?

> +    aml_append(dev, aml_name_decl("_PS3", aml_int(0x0)));
> +
> +    crs = aml_resource_template();
> +    aml_append(crs, aml_irq_no_flags(7));
> +    aml_append(crs, aml_irq_no_flags(13));
> +    aml_append(dev, aml_name_decl("_CRS", crs));
> +
> +    return dev;
> +}
> +
>  static void build_isa_devices_aml(Aml *table)
>  {
>      ISADevice *fdc = pc_find_fdc0();
> @@ -1296,6 +1334,10 @@ static void build_isa_devices_aml(Aml *table)
>          build_acpi_ipmi_devices(scope, BUS(obj), "\\_SB.PCI0.ISA");
>      }
>  
> +    if (vmbus_exists()) {
> +        aml_append(scope, build_vmbus_device_aml());
> +    }
> +
>      aml_append(table, scope);
>  }
>  



^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-06  8:20               ` Jon Doron
@ 2020-04-07 18:56                 ` Roman Kagan
  2020-04-07 19:03                   ` Maciej S. Szmigiero
  0 siblings, 1 reply; 26+ messages in thread
From: Roman Kagan @ 2020-04-07 18:56 UTC (permalink / raw)
  To: Jon Doron
  Cc: Maciej S. Szmigiero, Evgeny Yakovlev, ehabkost, QEMU, Liran Alon,
	Roman Kagan, Paolo Bonzini, Vitaly Kuznetsov

On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
> Well I want it to be merged in :-)

Hmm I'm curious why, it has little to offer over virtio.

Anyway the series you've posted seems to be based on a fairly old
version.

The one in openvz repo is more recent.  It's still in need for
improvement, too, but should be testable at least.

Thanks,
Roman.

> On Mon, Apr 6, 2020, 10:32 Roman Kagan <rvkagan@yandex-team.ru> wrote:
> 
> > On Fri, Apr 03, 2020 at 11:00:27PM +0200, Maciej S. Szmigiero wrote:
> > > It seems to me that Roman might not be getting our e-mails since his
> > > new e-mail address seems to be "rvkagan@yandex-team.ru".
> >
> > Indeed.  I'm subscribed with my new address to qemu-devel ML but must
> > have missed this series.
> >
> > > @Roman, are you with us?
> >
> > Yes ;)
> >
> > So what are your plans regarding this patchset?
> >
> > Thanks,
> > Roman.
> >
> > > On 03.04.2020 19:18, Maciej S. Szmigiero wrote:
> > > > Hi Jon,
> > > >
> > > > The patches are available here:
> > > > https://github.com/maciejsszmigiero/qemu.git in "vmbus-patches"
> > branch.
> > > >
> > > > Please note that these patches don't have Roman's "Signed-off-by:"
> > tags,
> > > > so I haven't applied mine, either.
> > > >
> > > > If you are able to establish a proper SoB chain then please also add:
> > > > "Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com>".
> > > >
> > > > Thanks for the effort,
> > > > Maciej
> > > >
> > > > On 03.04.2020 17:30, Jon Doron wrote:
> > > >>  Thank you Maciej it seems like your version is really ahead I'll do
> > > >> the required work and merge it so i can submit a v2 with the latest
> > > >> patchset from Roman
> > > >>
> > > >> On Fri, Apr 3, 2020 at 6:06 PM Jon Doron <arilou@gmail.com> wrote:
> > > >>>
> > > >>> Thank you Maciej, I based it on top of what Denis (den@openvz.org)
> > gave me
> > > >>> which was this:
> > > >>>
> > https://ftp.openvz.org/virtuozzo/releases/openvz-7.0.12-288/source/SRPMS/q/qemu-kvm-vz-2.12.0-33.vz7.14.4.src.rpm
> > > >>>
> > > >>> Do you think you have a more recent version I dont mind diffing and
> > > >>> resubmitting a new version of the patchset?
> > > >>>
> > > >>> Thanks,
> > > >>> -- Jon.
> > > >>>
> > > >>> On Fri, Apr 3, 2020 at 5:56 PM Maciej S. Szmigiero
> > > >>> <mail@maciej.szmigiero.name> wrote:
> > > >>>>
> > > >>>> Hi Jon,
> > > >>>>
> > > >>>> On 03.04.2020 16:23, Jon Doron wrote:
> > > >>>>> Guest OS uses ACPI to discover vmbus presence.  Add a corresponding
> > > >>>>> entry to DSDT in case vmbus has been enabled.
> > > >>>>>
> > > >>>>> Experimentally Windows guests were found to require this entry to
> > > >>>>> include two IRQ resources, so this patch adds two semi-arbitrarily
> > > >>>>> chosen ones (7 and 13).  This results, in particular, in parallel
> > port
> > > >>>>> conflicting with vmbus.
> > > >>>>>
> > > >>>>> TODO: discover and use spare IRQs to avoid conflicts.
> > > >>>>>
> > > >>>>> Signed-off-by: Evgeny Yakovlev <eyakovlev@virtuozzo.com>
> > > >>>>> Signed-off-by: Roman Kagan <rkagan@virtuozzo.com>
> > > >>>>> Signed-off-by: Jon Doron <arilou@gmail.com>
> > > >>>>
> > > >>>> Nice work, thanks!
> > > >>>>
> > > >>>> However, it seems to be based on the code version that was posted in
> > > >>>> February 2018, and not the latest version in OpenVZ qemu repository
> > > >>>> dated October 2019:
> > > >>>>
> > https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
> > > >>>>
> > > >>>> This newer version has slightly different API here and there.
> > > >>>> Any particular reason for selecting that older version for porting?
> > > >>>>
> > > >>>> I have actually rebased this latest version on the top of the
> > current
> > > >>>> QEMU master, and it basically seems to work fine.
> > > >>>> However, I haven't done extensive tests whether there isn't a
> > memory leak
> > > >>>> somewhere or so on.
> > > >>>>
> > > >>>> Maciej
> > > >
> > >
> >


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-07 18:56                 ` Roman Kagan
@ 2020-04-07 19:03                   ` Maciej S. Szmigiero
  2020-04-08  4:16                     ` Jon Doron
  2020-04-08 20:26                     ` Roman Kagan
  0 siblings, 2 replies; 26+ messages in thread
From: Maciej S. Szmigiero @ 2020-04-07 19:03 UTC (permalink / raw)
  To: Roman Kagan
  Cc: Evgeny Yakovlev, Jon Doron, QEMU, Liran Alon, Paolo Bonzini,
	Vitaly Kuznetsov, ehabkost

On 07.04.2020 20:56, Roman Kagan wrote:
> On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
>> Well I want it to be merged in :-)
> 
> Hmm I'm curious why, it has little to offer over virtio.
> 
> Anyway the series you've posted seems to be based on a fairly old
> version.
> 
> The one in openvz repo is more recent.  It's still in need for
> improvement, too, but should be testable at least.

Isn't the one at 
https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
the latest one?

It seems to be last changed in October 2019 - is there a
later one?

> Thanks,
> Roman.

Thanks,
Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-07 19:03                   ` Maciej S. Szmigiero
@ 2020-04-08  4:16                     ` Jon Doron
  2020-04-08 20:47                       ` Roman Kagan
  2020-04-08 20:26                     ` Roman Kagan
  1 sibling, 1 reply; 26+ messages in thread
From: Jon Doron @ 2020-04-08  4:16 UTC (permalink / raw)
  To: Maciej S. Szmigiero
  Cc: Evgeny Yakovlev, ehabkost, QEMU, Roman Kagan, Liran Alon,
	Paolo Bonzini, Vitaly Kuznetsov

On 07/04/2020, Maciej S. Szmigiero wrote:
>On 07.04.2020 20:56, Roman Kagan wrote:
>> On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
>>> Well I want it to be merged in :-)
>>
>> Hmm I'm curious why, it has little to offer over virtio.
>>
>> Anyway the series you've posted seems to be based on a fairly old
>> version.
>>
>> The one in openvz repo is more recent.  It's still in need for
>> improvement, too, but should be testable at least.

Well I have implemented the hyperv synthetic kernel debugger interface, 
but on Windows 10 it requires to have a working VMBus (it's not really 
using it, but without a function vmbus that will answer to the initiate 
contact then the kdnet will simply be stuck in a loop.

With the synthetic kernel debugger interface you can debug older OS 
(Win7 up to latest Win10). The benefit is that its much faster than all 
other interfaces.

In addition to that Michael Kelley from Microsoft has informed us that 
Microsoft might be dropped the synthetic kernel debugger interface 
sometime in the future, and it seems like the new mode is simply to use 
hvnet device for the communication (which is again much faster).

Cheers,
-- Jon.
>
>Isn't the one at
>https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>the latest one?
>
>It seems to be last changed in October 2019 - is there a
>later one?
>
>> Thanks,
>> Roman.
>
>Thanks,
>Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-07 19:03                   ` Maciej S. Szmigiero
  2020-04-08  4:16                     ` Jon Doron
@ 2020-04-08 20:26                     ` Roman Kagan
  2020-04-08 21:42                       ` Maciej S. Szmigiero
  1 sibling, 1 reply; 26+ messages in thread
From: Roman Kagan @ 2020-04-08 20:26 UTC (permalink / raw)
  To: Maciej S. Szmigiero
  Cc: Evgeny Yakovlev, Jon Doron, QEMU, Liran Alon, Paolo Bonzini,
	Vitaly Kuznetsov, ehabkost

On Tue, Apr 07, 2020 at 09:03:05PM +0200, Maciej S. Szmigiero wrote:
> On 07.04.2020 20:56, Roman Kagan wrote:
> > On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
> >> Well I want it to be merged in :-)
> > 
> > Hmm I'm curious why, it has little to offer over virtio.
> > 
> > Anyway the series you've posted seems to be based on a fairly old
> > version.
> > 
> > The one in openvz repo is more recent.  It's still in need for
> > improvement, too, but should be testable at least.
> 
> Isn't the one at 
> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
> the latest one?
> 
> It seems to be last changed in October 2019 - is there a
> later one?

There isn't, to the best of my knowledge.  It's still sorta unfinished,
though, and the demand seems to have disappeared so I couldn't find the
motivation to complete it.

Thanks,
Roman.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-08  4:16                     ` Jon Doron
@ 2020-04-08 20:47                       ` Roman Kagan
  2020-04-09  3:35                         ` Jon Doron
  0 siblings, 1 reply; 26+ messages in thread
From: Roman Kagan @ 2020-04-08 20:47 UTC (permalink / raw)
  To: Jon Doron
  Cc: Maciej S. Szmigiero, Evgeny Yakovlev, ehabkost, QEMU, Liran Alon,
	Paolo Bonzini, Vitaly Kuznetsov

On Wed, Apr 08, 2020 at 07:16:39AM +0300, Jon Doron wrote:
> On 07/04/2020, Maciej S. Szmigiero wrote:
> > On 07.04.2020 20:56, Roman Kagan wrote:
> > > On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
> > > > Well I want it to be merged in :-)
> > > 
> > > Hmm I'm curious why, it has little to offer over virtio.
> > > 
> > > Anyway the series you've posted seems to be based on a fairly old
> > > version.
> > > 
> > > The one in openvz repo is more recent.  It's still in need for
> > > improvement, too, but should be testable at least.
> 
> Well I have implemented the hyperv synthetic kernel debugger interface, but
> on Windows 10 it requires to have a working VMBus (it's not really using it,
> but without a function vmbus that will answer to the initiate contact then
> the kdnet will simply be stuck in a loop.

I see, thanks, I've never heard of this before.

> With the synthetic kernel debugger interface you can debug older OS (Win7 up
> to latest Win10). The benefit is that its much faster than all other
> interfaces.

I guess you compare it to debugging via serial port.  I wonder where the
difference comes from?  I thought the transport didn't require any
significant throughput, and latency-wise the (emulated) serial port was
just as good as any other.  Am I missing something?

Thanks,
Roman.

> In addition to that Michael Kelley from Microsoft has informed us that
> Microsoft might be dropped the synthetic kernel debugger interface sometime
> in the future, and it seems like the new mode is simply to use hvnet device
> for the communication (which is again much faster).
> 
> Cheers,
> -- Jon.
> > 
> > Isn't the one at
> > https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
> > the latest one?
> > 
> > It seems to be last changed in October 2019 - is there a
> > later one?
> > 
> > > Thanks,
> > > Roman.
> > 
> > Thanks,
> > Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-08 20:26                     ` Roman Kagan
@ 2020-04-08 21:42                       ` Maciej S. Szmigiero
  0 siblings, 0 replies; 26+ messages in thread
From: Maciej S. Szmigiero @ 2020-04-08 21:42 UTC (permalink / raw)
  To: Roman Kagan
  Cc: Evgeny Yakovlev, Jon Doron, QEMU, Liran Alon, Paolo Bonzini,
	Vitaly Kuznetsov, ehabkost

On 08.04.2020 22:26, Roman Kagan wrote:
> On Tue, Apr 07, 2020 at 09:03:05PM +0200, Maciej S. Szmigiero wrote:
>> On 07.04.2020 20:56, Roman Kagan wrote:
>>> On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
>>>> Well I want it to be merged in :-)
>>>
>>> Hmm I'm curious why, it has little to offer over virtio.
>>>
>>> Anyway the series you've posted seems to be based on a fairly old
>>> version.
>>>
>>> The one in openvz repo is more recent.  It's still in need for
>>> improvement, too, but should be testable at least.
>>
>> Isn't the one at 
>> https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>> the latest one?
>>
>> It seems to be last changed in October 2019 - is there a
>> later one?
> 
> There isn't, to the best of my knowledge.  It's still sorta unfinished,
> though, and the demand seems to have disappeared so I couldn't find the
> motivation to complete it.

These patches that were posted should be based on this version, that I
have ported to the current QEMU master and then provided to Jon.

BTW. I have written an e-mail to you about this porting work about
a month ago, but it was sent your old Virtuozzo mailbox, because that's
the email address that these commits had in their metadata.

> Thanks,
> Roman.
> 

Thanks,
Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-08 20:47                       ` Roman Kagan
@ 2020-04-09  3:35                         ` Jon Doron
  2020-05-12 14:05                           ` Roman Kagan
  0 siblings, 1 reply; 26+ messages in thread
From: Jon Doron @ 2020-04-09  3:35 UTC (permalink / raw)
  To: Roman Kagan, Maciej S. Szmigiero, QEMU, Evgeny Yakovlev,
	ehabkost, Paolo Bonzini, Vitaly Kuznetsov, Liran Alon

On 08/04/2020, Roman Kagan wrote:
>On Wed, Apr 08, 2020 at 07:16:39AM +0300, Jon Doron wrote:
>> On 07/04/2020, Maciej S. Szmigiero wrote:
>> > On 07.04.2020 20:56, Roman Kagan wrote:
>> > > On Mon, Apr 06, 2020 at 11:20:39AM +0300, Jon Doron wrote:
>> > > > Well I want it to be merged in :-)
>> > >
>> > > Hmm I'm curious why, it has little to offer over virtio.
>> > >
>> > > Anyway the series you've posted seems to be based on a fairly old
>> > > version.
>> > >
>> > > The one in openvz repo is more recent.  It's still in need for
>> > > improvement, too, but should be testable at least.
>>
>> Well I have implemented the hyperv synthetic kernel debugger interface, but
>> on Windows 10 it requires to have a working VMBus (it's not really using it,
>> but without a function vmbus that will answer to the initiate contact then
>> the kdnet will simply be stuck in a loop.
>
>I see, thanks, I've never heard of this before.
>
>> With the synthetic kernel debugger interface you can debug older OS (Win7 up
>> to latest Win10). The benefit is that its much faster than all other
>> interfaces.
>
>I guess you compare it to debugging via serial port.  I wonder where the
>difference comes from?  I thought the transport didn't require any
>significant throughput, and latency-wise the (emulated) serial port was
>just as good as any other.  Am I missing something?
>
>Thanks,
>Roman.
>

Well kdcom is sending out UART through the virtual serial port, this
results in very slow speeds (try it out if you get a chance), because
of that most Windows kernel developers use  VMWare with a combination
of a tool called VirtualKD which implements it's own debug transport on
the Windows part and patches the hypervisor (aka VMWare) to get the 
VMExits.
This way it can transfer more and bigger blocks faster, to the debugger.

With the synthetic debugger interface in-place (which you can use since 
Windows 7) all these tricks are not really required, you just need to 
implement it :P .

Thanks,
-- Jon.

>> In addition to that Michael Kelley from Microsoft has informed us that
>> Microsoft might be dropped the synthetic kernel debugger interface sometime
>> in the future, and it seems like the new mode is simply to use hvnet device
>> for the communication (which is again much faster).
>>
>> Cheers,
>> -- Jon.
>> >
>> > Isn't the one at
>> > https://src.openvz.org/projects/UP/repos/qemu/commits?until=refs%2Fheads%2Fvmbus
>> > the latest one?
>> >
>> > It seems to be last changed in October 2019 - is there a
>> > later one?
>> >
>> > > Thanks,
>> > > Roman.
>> >
>> > Thanks,
>> > Maciej


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-04-09  3:35                         ` Jon Doron
@ 2020-05-12 14:05                           ` Roman Kagan
  2020-05-12 15:01                             ` Jon Doron
  0 siblings, 1 reply; 26+ messages in thread
From: Roman Kagan @ 2020-05-12 14:05 UTC (permalink / raw)
  To: Jon Doron
  Cc: Maciej S. Szmigiero, Evgeny Yakovlev, ehabkost, QEMU, Liran Alon,
	Paolo Bonzini, Vitaly Kuznetsov

On Thu, Apr 09, 2020 at 06:35:18AM +0300, Jon Doron wrote:
> On 08/04/2020, Roman Kagan wrote:
> > On Wed, Apr 08, 2020 at 07:16:39AM +0300, Jon Doron wrote:
> > > Well I have implemented the hyperv synthetic kernel debugger interface, but
> > > on Windows 10 it requires to have a working VMBus (it's not really using it,
> > > but without a function vmbus that will answer to the initiate contact then
> > > the kdnet will simply be stuck in a loop.

I tried to google for this interface but the only thing I managed to
find was this

https://withinrafael.com/2015/02/01/how-to-set-up-synthetic-kernel-debugging-for-hyper-v-virtual-machines/

Is this what you're trying to implement?  Are there any more
authoritative descriptions of the feature?

The document doesn't quite explain the inner workings of the feature,
but it looks like the regular network debugging interface, except that
IP is forwarded by the hypervisor app, so that the debugger has to
connect to the host and avoid setting up full-fledged network
connectivity to the guest.  That would be essentially hv-net + slirp.
OTOH you say it doesn't use VMBus so I'm confused...

Thanks,
Roman.

> > > In addition to that Michael Kelley from Microsoft has informed us that
> > > Microsoft might be dropped the synthetic kernel debugger interface sometime
> > > in the future, and it seems like the new mode is simply to use hvnet device
> > > for the communication (which is again much faster).


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-05-12 14:05                           ` Roman Kagan
@ 2020-05-12 15:01                             ` Jon Doron
  2020-05-12 15:05                               ` Jon Doron
  0 siblings, 1 reply; 26+ messages in thread
From: Jon Doron @ 2020-05-12 15:01 UTC (permalink / raw)
  To: Roman Kagan, Maciej S. Szmigiero, QEMU, Evgeny Yakovlev,
	ehabkost, Paolo Bonzini, Vitaly Kuznetsov, Liran Alon

On 12/05/2020, Roman Kagan wrote:
>On Thu, Apr 09, 2020 at 06:35:18AM +0300, Jon Doron wrote:
>> On 08/04/2020, Roman Kagan wrote:
>> > On Wed, Apr 08, 2020 at 07:16:39AM +0300, Jon Doron wrote:
>> > > Well I have implemented the hyperv synthetic kernel debugger interface, but
>> > > on Windows 10 it requires to have a working VMBus (it's not really using it,
>> > > but without a function vmbus that will answer to the initiate contact then
>> > > the kdnet will simply be stuck in a loop.
>
>I tried to google for this interface but the only thing I managed to
>find was this
>
>https://withinrafael.com/2015/02/01/how-to-set-up-synthetic-kernel-debugging-for-hyper-v-virtual-machines/
>
>Is this what you're trying to implement?  Are there any more
>authoritative descriptions of the feature?
>
>The document doesn't quite explain the inner workings of the feature,
>but it looks like the regular network debugging interface, except that
>IP is forwarded by the hypervisor app, so that the debugger has to
>connect to the host and avoid setting up full-fledged network
>connectivity to the guest.  That would be essentially hv-net + slirp.
>OTOH you say it doesn't use VMBus so I'm confused...
>
>Thanks,
>Roman.
>
>> > > In addition to that Michael Kelley from Microsoft has informed us that
>> > > Microsoft might be dropped the synthetic kernel debugger interface sometime
>> > > in the future, and it seems like the new mode is simply to use hvnet device
>> > > for the communication (which is again much faster).

Yes that's indeed the interface I have implemented this part of the 
patch it not full ready for commit, but I think we can keep going with 
the VMBUS.

Based on your previous reply it sounds like there is not a real issue 
with the current patch of ACPI DSDT entry, right?

Thanks,
-- Jon.


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry
  2020-05-12 15:01                             ` Jon Doron
@ 2020-05-12 15:05                               ` Jon Doron
  0 siblings, 0 replies; 26+ messages in thread
From: Jon Doron @ 2020-05-12 15:05 UTC (permalink / raw)
  To: Roman Kagan, Maciej S. Szmigiero, QEMU, Evgeny Yakovlev,
	ehabkost, Paolo Bonzini, Vitaly Kuznetsov, Liran Alon

On 12/05/2020, Jon Doron wrote:
>On 12/05/2020, Roman Kagan wrote:
>>On Thu, Apr 09, 2020 at 06:35:18AM +0300, Jon Doron wrote:
>>>On 08/04/2020, Roman Kagan wrote:
>>>> On Wed, Apr 08, 2020 at 07:16:39AM +0300, Jon Doron wrote:
>>>> > Well I have implemented the hyperv synthetic kernel debugger interface, but
>>>> > on Windows 10 it requires to have a working VMBus (it's not really using it,
>>>> > but without a function vmbus that will answer to the initiate contact then
>>>> > the kdnet will simply be stuck in a loop.
>>
>>I tried to google for this interface but the only thing I managed to
>>find was this
>>
>>https://withinrafael.com/2015/02/01/how-to-set-up-synthetic-kernel-debugging-for-hyper-v-virtual-machines/
>>
>>Is this what you're trying to implement?  Are there any more
>>authoritative descriptions of the feature?
>>
>>The document doesn't quite explain the inner workings of the feature,
>>but it looks like the regular network debugging interface, except that
>>IP is forwarded by the hypervisor app, so that the debugger has to
>>connect to the host and avoid setting up full-fledged network
>>connectivity to the guest.  That would be essentially hv-net + slirp.
>>OTOH you say it doesn't use VMBus so I'm confused...
>>
>>Thanks,
>>Roman.
>>
>>>> > In addition to that Michael Kelley from Microsoft has informed us that
>>>> > Microsoft might be dropped the synthetic kernel debugger interface sometime
>>>> > in the future, and it seems like the new mode is simply to use hvnet device
>>>> > for the communication (which is again much faster).
>
>Yes that's indeed the interface I have implemented this part of the 
>patch it not full ready for commit, but I think we can keep going with 
>the VMBUS.
>
>Based on your previous reply it sounds like there is not a real issue 
>with the current patch of ACPI DSDT entry, right?
>
>Thanks,
>-- Jon.

I suggest referring to the KVM patches I have already submitted that 
Paolo said will probably get in soon.
https://patchwork.kernel.org/patch/11507663/


^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2020-05-12 15:17 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-03 14:23 [PATCH v1 0/5] hyperv: VMBus implementation Jon Doron
2020-04-03 14:23 ` [PATCH v1 1/5] hyperv: expose API to determine if synic is enabled Jon Doron
2020-04-03 14:23 ` [PATCH v1 2/5] hyperv: SControl is optional to enable SynIc Jon Doron
2020-04-03 14:23 ` [PATCH v1 3/5] vmbus: add vmbus protocol definitions Jon Doron
2020-04-03 14:23 ` [PATCH v1 4/5] vmbus: vmbus implementation Jon Doron
2020-04-03 14:23 ` [PATCH v1 5/5] i386: Hyper-V VMBus ACPI DSDT entry Jon Doron
2020-04-03 14:56   ` Maciej S. Szmigiero
2020-04-03 15:06     ` Jon Doron
2020-04-03 15:30       ` Jon Doron
2020-04-03 15:50         ` Maciej S. Szmigiero
2020-04-03 17:18         ` Maciej S. Szmigiero
2020-04-03 21:00           ` Maciej S. Szmigiero
2020-04-06  7:32             ` Roman Kagan
2020-04-06  8:20               ` Jon Doron
2020-04-07 18:56                 ` Roman Kagan
2020-04-07 19:03                   ` Maciej S. Szmigiero
2020-04-08  4:16                     ` Jon Doron
2020-04-08 20:47                       ` Roman Kagan
2020-04-09  3:35                         ` Jon Doron
2020-05-12 14:05                           ` Roman Kagan
2020-05-12 15:01                             ` Jon Doron
2020-05-12 15:05                               ` Jon Doron
2020-04-08 20:26                     ` Roman Kagan
2020-04-08 21:42                       ` Maciej S. Szmigiero
2020-04-06 10:14   ` Igor Mammedov
2020-04-03 22:48 ` [PATCH v1 0/5] hyperv: VMBus implementation no-reply

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.