Blame 0038-spice-add-virtio-serial-based-spice-vmchannel-backen.patch

Justin M. Forbes a81953
From 5bdc01e675a51a123a813d62a8ae837db9360b7f Mon Sep 17 00:00:00 2001
Justin M. Forbes a81953
From: Gerd Hoffmann <kraxel@redhat.com>
Justin M. Forbes a81953
Date: Tue, 20 Apr 2010 13:33:54 +0200
Justin M. Forbes a81953
Subject: [PATCH 38/39] spice: add virtio-serial based spice vmchannel backend.
Justin M. Forbes a81953
Justin M. Forbes a81953
Adds the spicevmc device.  This is a communication channel between the
Justin M. Forbes a81953
spice client and the guest.  It is used to send display information and
Justin M. Forbes a81953
mouse events from the spice clients to the guest.
Justin M. Forbes a81953
---
Justin M. Forbes a81953
 Makefile.target |    1 +
Justin M. Forbes a81953
 hw/spice-vmc.c  |  262 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
Justin M. Forbes a81953
 2 files changed, 263 insertions(+), 0 deletions(-)
Justin M. Forbes a81953
 create mode 100644 hw/spice-vmc.c
Justin M. Forbes a81953
Justin M. Forbes a81953
diff --git a/Makefile.target b/Makefile.target
Justin M. Forbes a81953
index 4da33b5..90544c5 100644
Justin M. Forbes a81953
--- a/Makefile.target
Justin M. Forbes a81953
+++ b/Makefile.target
Justin M. Forbes a81953
@@ -217,6 +217,7 @@ obj-i386-y += pc_piix.o
Justin M. Forbes a81953
 obj-i386-y += testdev.o
Justin M. Forbes a81953
 obj-i386-y += acpi.o acpi_piix4.o
Justin M. Forbes a81953
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
Justin M. Forbes a81953
+obj-i386-$(CONFIG_SPICE) += spice-vmc.o
Justin M. Forbes a81953
Justin M. Forbes a81953
 obj-i386-y += pcspk.o i8254.o
Justin M. Forbes a81953
 obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o
Justin M. Forbes a81953
diff --git a/hw/spice-vmc.c b/hw/spice-vmc.c
Justin M. Forbes a81953
new file mode 100644
Justin M. Forbes a81953
index 0000000..b77fc60
Justin M. Forbes a81953
--- /dev/null
Justin M. Forbes a81953
+++ b/hw/spice-vmc.c
Justin M. Forbes a81953
@@ -0,0 +1,262 @@
Justin M. Forbes a81953
+/*
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+ Spice Virtual Machine Channel (VMC).
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+ A virtio-serial port used for spice to guest communication, over
Justin M. Forbes a81953
+ which spice client and a daemon in the guest operating system
Justin M. Forbes a81953
+ communicate.
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+ Replaces the old vdi_port PCI device.
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+*/
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include <stdio.h>
Justin M. Forbes a81953
+#include <stdbool.h>
Justin M. Forbes a81953
+#include <spice.h>
Justin M. Forbes a81953
+#include <spice-experimental.h>
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#include "virtio-serial.h"
Justin M. Forbes a81953
+#include "qemu-spice.h"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0"
Justin M. Forbes a81953
+#define VMC_DEVICE_NAME       "spicevmc"
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/* windows guest driver bug workaround */
Justin M. Forbes a81953
+#define VMC_MAX_HOST_WRITE    2048
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+#define dprintf(_svc, _level, _fmt, ...)                                \
Justin M. Forbes a81953
+    do {                                                                \
Justin M. Forbes a81953
+        static unsigned __dprintf_counter = 0;                          \
Justin M. Forbes a81953
+        if (_svc->debug >= _level) {                                    \
Justin M. Forbes a81953
+            fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\
Justin M. Forbes a81953
+        }                                                               \
Justin M. Forbes a81953
+    } while (0)
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+typedef struct SpiceVirtualChannel {
Justin M. Forbes a81953
+    VirtIOSerialPort         port;
Justin M. Forbes a81953
+    VMChangeStateEntry       *vmstate;
Justin M. Forbes a81953
+    SpiceCharDeviceInstance  sin;
Justin M. Forbes a81953
+    char                     *subtype;
Justin M. Forbes a81953
+    bool                     active;
Justin M. Forbes a81953
+    uint8_t                  *buffer;
Justin M. Forbes a81953
+    uint8_t                  *datapos;
Justin M. Forbes a81953
+    ssize_t                  bufsize, datalen;
Justin M. Forbes a81953
+    uint32_t                 debug;
Justin M. Forbes a81953
+} SpiceVirtualChannel;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
Justin M. Forbes a81953
+    ssize_t out = 0;
Justin M. Forbes a81953
+    ssize_t last_out;
Justin M. Forbes a81953
+    uint8_t* p = (uint8_t*)buf;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    while (len > 0) {
Justin M. Forbes a81953
+        last_out = virtio_serial_write(&svc->port, p,
Justin M. Forbes a81953
+                            MIN(len, VMC_MAX_HOST_WRITE));
Justin M. Forbes a81953
+        if (last_out > 0) {
Justin M. Forbes a81953
+            out += last_out;
Justin M. Forbes a81953
+            len -= last_out;
Justin M. Forbes a81953
+            p += last_out;
Justin M. Forbes a81953
+        } else {
Justin M. Forbes a81953
+            break;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out);
Justin M. Forbes a81953
+    return out;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin);
Justin M. Forbes a81953
+    int bytes = MIN(len, svc->datalen);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen);
Justin M. Forbes a81953
+    if (bytes > 0) {
Justin M. Forbes a81953
+        memcpy(buf, svc->datapos, bytes);
Justin M. Forbes a81953
+        svc->datapos += bytes;
Justin M. Forbes a81953
+        svc->datalen -= bytes;
Justin M. Forbes a81953
+        assert(svc->datalen >= 0);
Justin M. Forbes a81953
+        if (svc->datalen == 0) {
Justin M. Forbes a81953
+            svc->datapos = 0;
Justin M. Forbes a81953
+            virtio_serial_throttle_port(&svc->port, false);
Justin M. Forbes a81953
+            // ^^^ !!! may call vmc_have_data, so don't touch svc after it!
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    return bytes;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static SpiceCharDeviceInterface vmc_interface = {
Justin M. Forbes a81953
+    .base.type          = SPICE_INTERFACE_CHAR_DEVICE,
Justin M. Forbes a81953
+    .base.description   = "spice virtual channel char device",
Justin M. Forbes a81953
+    .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR,
Justin M. Forbes a81953
+    .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR,
Justin M. Forbes a81953
+    .write              = vmc_write,
Justin M. Forbes a81953
+    .read               = vmc_read,
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_register_interface(SpiceVirtualChannel *svc)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (svc->active) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+    svc->sin.base.sif = &vmc_interface.base;
Justin M. Forbes a81953
+    spice_server_add_interface(spice_server, &svc->sin.base);
Justin M. Forbes a81953
+    svc->active = true;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_unregister_interface(SpiceVirtualChannel *svc)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    if (!svc->active) {
Justin M. Forbes a81953
+        return;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+    spice_server_remove_interface(&svc->sin.base);
Justin M. Forbes a81953
+    svc->active = false;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_change_state_handler(void *opaque, int running, int reason)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = opaque;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (running && svc->active) {
Justin M. Forbes a81953
+        spice_server_char_device_wakeup(&svc->sin);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+/*
Justin M. Forbes a81953
+ * virtio-serial callbacks
Justin M. Forbes a81953
+ */
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_guest_open(VirtIOSerialPort *port)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+    vmc_register_interface(svc);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_guest_close(VirtIOSerialPort *port)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+    vmc_unregister_interface(svc);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_guest_ready(VirtIOSerialPort *port)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+    if (svc->active) {
Justin M. Forbes a81953
+        spice_server_char_device_wakeup(&svc->sin);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 2, "%s: %zd\n", __func__, len);
Justin M. Forbes a81953
+    assert(svc->datalen == 0);
Justin M. Forbes a81953
+    if (svc->bufsize < len) {
Justin M. Forbes a81953
+        svc->bufsize = len;
Justin M. Forbes a81953
+        svc->buffer = qemu_realloc(svc->buffer, svc->bufsize);
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    memcpy(svc->buffer, buf, len);
Justin M. Forbes a81953
+    svc->datapos = svc->buffer;
Justin M. Forbes a81953
+    svc->datalen = len;
Justin M. Forbes a81953
+    virtio_serial_throttle_port(&svc->port, true);
Justin M. Forbes a81953
+    spice_server_char_device_wakeup(&svc->sin);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_print_optional_subtypes(void)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    const char** psubtype = spice_server_char_device_recognized_subtypes();
Justin M. Forbes a81953
+    int i;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    fprintf(stderr, "supported subtypes: ");
Justin M. Forbes a81953
+    for(i=0; *psubtype != NULL; ++psubtype, ++i) {
Justin M. Forbes a81953
+        if (i == 0) {
Justin M. Forbes a81953
+            fprintf(stderr, *psubtype);
Justin M. Forbes a81953
+        } else {
Justin M. Forbes a81953
+            fprintf(stderr, ", %s", *psubtype);
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    fprintf(stderr, "\n");
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int vmc_initfn(VirtIOSerialDevice *dev)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
Justin M. Forbes a81953
+    const char** psubtype = spice_server_char_device_recognized_subtypes();
Justin M. Forbes a81953
+    const char *subtype = NULL;
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (!using_spice) {
Justin M. Forbes a81953
+        return -1;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    if (svc->subtype == NULL) {
Justin M. Forbes a81953
+        svc->subtype = strdup("vdagent");
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    for(;*psubtype != NULL; ++psubtype) {
Justin M. Forbes a81953
+        if (strcmp(svc->subtype, *psubtype) == 0) {
Justin M. Forbes a81953
+            subtype = *psubtype;
Justin M. Forbes a81953
+            break;
Justin M. Forbes a81953
+        }
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    if (subtype == NULL) {
Justin M. Forbes a81953
+        fprintf(stderr, "spice-vmc: unsupported subtype\n");
Justin M. Forbes a81953
+        vmc_print_optional_subtypes();
Justin M. Forbes a81953
+        return -1;
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+    port->name = qemu_strdup(VMC_GUEST_DEVICE_NAME);
Justin M. Forbes a81953
+    svc->vmstate = qemu_add_vm_change_state_handler
Justin M. Forbes a81953
+        (vmc_change_state_handler, svc);
Justin M. Forbes a81953
+    svc->sin.subtype = svc->subtype;
Justin M. Forbes a81953
+    virtio_serial_open(port);
Justin M. Forbes a81953
+    return 0;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static int vmc_exitfn(VirtIOSerialDevice *dev)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
Justin M. Forbes a81953
+    SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port);
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+    dprintf(svc, 1, "%s\n", __func__);
Justin M. Forbes a81953
+    vmc_unregister_interface(svc);
Justin M. Forbes a81953
+    qemu_del_vm_change_state_handler(svc->vmstate);
Justin M. Forbes a81953
+    virtio_serial_close(port);
Justin M. Forbes a81953
+    return 0;
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static VirtIOSerialPortInfo vmc_info = {
Justin M. Forbes a81953
+    .qdev.name     = VMC_DEVICE_NAME,
Justin M. Forbes a81953
+    .qdev.size     = sizeof(SpiceVirtualChannel),
Justin M. Forbes a81953
+    .init          = vmc_initfn,
Justin M. Forbes a81953
+    .exit          = vmc_exitfn,
Justin M. Forbes a81953
+    .guest_open    = vmc_guest_open,
Justin M. Forbes a81953
+    .guest_close   = vmc_guest_close,
Justin M. Forbes a81953
+    .guest_ready   = vmc_guest_ready,
Justin M. Forbes a81953
+    .have_data     = vmc_have_data,
Justin M. Forbes a81953
+    .qdev.props = (Property[]) {
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("nr", SpiceVirtualChannel, port.id, VIRTIO_CONSOLE_BAD_ID),
Justin M. Forbes a81953
+        DEFINE_PROP_UINT32("debug", SpiceVirtualChannel, debug, 1),
Justin M. Forbes a81953
+        DEFINE_PROP_STRING("subtype", SpiceVirtualChannel, subtype),
Justin M. Forbes a81953
+        DEFINE_PROP_END_OF_LIST(),
Justin M. Forbes a81953
+    }
Justin M. Forbes a81953
+};
Justin M. Forbes a81953
+
Justin M. Forbes a81953
+static void vmc_register(void)
Justin M. Forbes a81953
+{
Justin M. Forbes a81953
+    virtio_serial_port_qdev_register(&vmc_info);
Justin M. Forbes a81953
+}
Justin M. Forbes a81953
+device_init(vmc_register)
Justin M. Forbes a81953
-- 
Justin M. Forbes a81953
1.7.2.3
Justin M. Forbes a81953